问题
I'm working with SwiftUI and is trying to make a list of buttons with custom .buttonStyle inside a List view on WatchOS, but can't get it to work. Is this even currently possible, and if so, how?
Example project:
struct Superhero: Identifiable {
var id = UUID()
var name: String
}
var superheroes = [
Superhero(name: "Batman"),
Superhero(name: "Superman"),
Superhero(name: "Wonder Woman"),
Superhero(name: "Aquaman"),
Superhero(name: "Green Lantern"),
Superhero(name: "The Flash")
]
struct SuperheroButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(minWidth: 0, maxWidth: .infinity)
.foregroundColor(.white)
.background(configuration.isPressed ? Color.white.opacity(0.95) : .green)
.cornerRadius(13.0)
}
}
struct SuperHeroesView: View{
var body: some View {
List {
ForEach(superheroes) { superhero in
Button(action: {
print(superhero.name)
}){
Text(superhero.name)
}.buttonStyle(SuperheroButtonStyle())
}
}
}
}
This code produces this:
Instead, I want the buttons to look more like this:
In this last example, I'm using ScrollView instead of List which means I'm not getting the nice animation of rows shrinking and fading away when scrolling through the list.
I've tried playing with negative padding, but that can't give me a bigger corner radius (more round corners than the default) and doesn't really look like good.
So is there a way to apply a ButtonStyle on items in a List view correctly, including having a custom cornerRadius?
Or is there some other way of getting more control of the way the rows look while still keeping the animation that comes with List?
回答1:
To have a the background of the whole cell in a certain colour you have to use .listRowBackground
modifier. You can either use a Capsule
or a RoundedRectangle
as the background depending on your preference:
struct SuperHeroesView: View{
var body: some View {
List {
ForEach(superheroes) { superhero in
Button(action: { print(superhero.name) }){
Text(superhero.name)
} .buttonStyle(SuperheroButtonStyle())
} .listRowBackground(Capsule()
.fill(Color.green))
// or as an alternative:
//.listRowBackground(RoundedRectangle(cornerRadius: 13.0)
// .fill(Color.green))
}
}
}
You would also probably want to change the button style, as the background highlight effect will only affect the button, not the whole cell:
struct SuperheroButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(minWidth: 0, maxWidth: .infinity)
.foregroundColor(configuration.isPressed ? .gray : .white)
}
}
回答2:
I don't know if you've figured this out yet or not, but I ended up using
List {
ForEach(superheroes) { superhero in
Button(action: {
print(superhero.name)
}){
Text(superhero.name)
}
.buttonStyle(SuperheroButtonStyle())
.listRowInsets(EdgeInsets.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
to extend the edges of my buttons to the edge of the list like this:
You can also add the modifier
.environment(\.defaultMinListRowHeight, 20)
to the List itself to allow the rows height to scale down to the size you want. I chose 20 for this example:
And finally there's a
.listRowPlatterColor(.clear)
modifier you can use to change the background color of the row itself. I chose clear for this example to hide the edges that aren't fully covered by the button.
回答3:
I know this isn't how it is supposed to be implemented, but it looks like there is a bug in SwiftUI preventing listRowPlatterColor
, listRowBackground
, or even listRowInsets
from doing anything in the latest version of watchOS.
Here is how I got around it for now:
ZStack {
Color.black
MyRowView()
}
.padding(.horizontal, -8)
回答4:
struct SuperHeroesView: View{
var body: some View {
List {
ForEach(superheroes) { superhero in
Button(action: {
print(superhero.name)
}){
Text(superhero.name)
}.buttonStyle(SuperheroButtonStyle())
.listRowInsets(EdgeInsets())
.listRowBackground(Color.clear)
}.environment(\.defaultMinListRowHeight, 20)
}
}
}
来源:https://stackoverflow.com/questions/58434622/how-to-style-rows-in-swiftui-list-on-watchos