如何设置 SwiftUI 按钮的自定义突出显示状态
How to set custom highlighted state of SwiftUI Button
我有一个按钮。我想为突出显示的状态设置自定义背景颜色。我怎样才能在 SwiftUI 中做到这一点?
Button(action: signIn) {
Text("Sign In")
}
.padding(.all)
.background(Color.red)
.cornerRadius(16)
.foregroundColor(.white)
.font(Font.body.bold())
据我所知,目前还没有官方支持的方法来做到这一点。这是您可以使用的一些解决方法。这会产生与在 UIKit 中相同的行为,在 UIKit 中点击按钮并将手指拖离它会使按钮保持突出显示。
struct HoverButton<Label>: View where Label: View {
private let action: () -> ()
private let label: () -> Label
init(action: @escaping () -> (), label: @escaping () -> Label) {
self.action = action
self.label = label
}
@State private var pressed: Bool = false
var body: some View {
Button(action: action) {
label()
.foregroundColor(pressed ? .red : .blue)
.gesture(DragGesture(minimumDistance: 0.0)
.onChanged { _ in self.pressed = true }
.onEnded { _ in self.pressed = false })
}
}
}
针对 SwiftUI beta 5 进行了更新
SwiftUI 实际上 expose an API 为此:ButtonStyle
.
struct MyButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding()
.foregroundColor(.white)
.background(configuration.isPressed ? Color.red : Color.blue)
.cornerRadius(8.0)
}
}
// To use it
Button(action: {}) {
Text("Hello World")
}
.buttonStyle(MyButtonStyle())
我一直在寻找类似的功能,我是通过以下方式实现的。
我创建了一个特殊的 View 结构,以我需要的样式返回一个 Button,在这个结构中我添加了一个 State 属性 selected。我有一个名为 'table' 的变量,它是一个 Int,因为我的按钮是一个带有数字的圆形按钮
struct TableButton: View {
@State private var selected = false
var table: Int
var body: some View {
Button("\(table)") {
self.selected.toggle()
}
.frame(width: 50, height: 50)
.background(selected ? Color.blue : Color.red)
.foregroundColor(.white)
.clipShape(Circle())
}
}
然后我在我的内容中使用查看代码
HStack(spacing: 10) {
ForEach((1...6), id: \.self) { table in
TableButton(table: table)
}
}
这将创建一个水平堆栈,其中包含 6 个按钮,选中时颜色为蓝色,取消选中时颜色为红色。
我不是经验丰富的开发人员,只是尝试了所有可能的方法,直到我发现这对我有用,希望它对其他人也有用。
这是针对那些对上述解决方案不满意的人,因为他们提出了其他问题,例如重叠手势(例如,现在在 scrollview 中很难使用此解决方案)。另一个拐杖是创建一个像这样的自定义按钮样式
struct CustomButtonStyle<Content>: ButtonStyle where Content: View {
var change: (Bool) -> Content
func makeBody(configuration: Self.Configuration) -> some View {
return change(configuration.isPressed)
}
}
所以,我们应该只传递将 return 按钮状态的闭包,并根据此参数创建按钮。它将像这样使用:
struct CustomButton<Content>: View where Content: View {
var content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
Button(action: { }, label: {
EmptyView()
})
.buttonStyle(CustomButtonStyle(change: { bool in
Text("\(bool ? "yo" : "yo2")")
}))
}
}
好的,让我再次清除所有内容。这是确切的解决方案
- 创建下面的按钮修改器。
struct StateableButton<Content>: ButtonStyle where Content: View {
var change: (Bool) -> Content
func makeBody(configuration: Configuration) -> some View {
return change(configuration.isPressed)
}
}
- 然后像下面一样使用它
Button(action: {
print("Do something")
}, label: {
// Don't create your button view in here
EmptyView()
})
.buttonStyle(StateableButton(change: { state in
// Create your button view in here
return HStack {
Image(systemName: "clock.arrow.circlepath")
Text(item)
Spacer()
Image(systemName: "arrow.up.backward")
}
.padding(.horizontal)
.frame(height: 50)
.background(state ? Color.black : Color.clear)
}))
您需要定义一个自定义样式,用于为正常状态和高亮状态提供两种背景:
Button(action: {
print("action")
}, label: {
Text("My Button").padding()
})
.buttonStyle(HighlightableButtonStyle(normal: { Color.red },
highlighted: { Color.green }))
// Custom button style
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
struct HighlightableButtonStyle<N, H>: ButtonStyle where N: View, H: View {
private let alignment: Alignment
private let normal: () -> N
private let highlighted: () -> H
init(alignment: Alignment = .center, @ViewBuilder normal: @escaping () -> N, @ViewBuilder highlighted: @escaping () -> H) {
self.alignment = alignment
self.normal = normal
self.highlighted = highlighted
}
func makeBody(configuration: Configuration) -> some View {
return ZStack {
if configuration.isPressed {
configuration.label.background(alignment: alignment, content: normal)
}
else {
configuration.label.background(alignment: alignment, content: highlighted)
}
}
}
}
我有一个按钮。我想为突出显示的状态设置自定义背景颜色。我怎样才能在 SwiftUI 中做到这一点?
Button(action: signIn) {
Text("Sign In")
}
.padding(.all)
.background(Color.red)
.cornerRadius(16)
.foregroundColor(.white)
.font(Font.body.bold())
据我所知,目前还没有官方支持的方法来做到这一点。这是您可以使用的一些解决方法。这会产生与在 UIKit 中相同的行为,在 UIKit 中点击按钮并将手指拖离它会使按钮保持突出显示。
struct HoverButton<Label>: View where Label: View {
private let action: () -> ()
private let label: () -> Label
init(action: @escaping () -> (), label: @escaping () -> Label) {
self.action = action
self.label = label
}
@State private var pressed: Bool = false
var body: some View {
Button(action: action) {
label()
.foregroundColor(pressed ? .red : .blue)
.gesture(DragGesture(minimumDistance: 0.0)
.onChanged { _ in self.pressed = true }
.onEnded { _ in self.pressed = false })
}
}
}
针对 SwiftUI beta 5 进行了更新
SwiftUI 实际上 expose an API 为此:ButtonStyle
.
struct MyButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding()
.foregroundColor(.white)
.background(configuration.isPressed ? Color.red : Color.blue)
.cornerRadius(8.0)
}
}
// To use it
Button(action: {}) {
Text("Hello World")
}
.buttonStyle(MyButtonStyle())
我一直在寻找类似的功能,我是通过以下方式实现的。
我创建了一个特殊的 View 结构,以我需要的样式返回一个 Button,在这个结构中我添加了一个 State 属性 selected。我有一个名为 'table' 的变量,它是一个 Int,因为我的按钮是一个带有数字的圆形按钮
struct TableButton: View {
@State private var selected = false
var table: Int
var body: some View {
Button("\(table)") {
self.selected.toggle()
}
.frame(width: 50, height: 50)
.background(selected ? Color.blue : Color.red)
.foregroundColor(.white)
.clipShape(Circle())
}
}
然后我在我的内容中使用查看代码
HStack(spacing: 10) {
ForEach((1...6), id: \.self) { table in
TableButton(table: table)
}
}
这将创建一个水平堆栈,其中包含 6 个按钮,选中时颜色为蓝色,取消选中时颜色为红色。
我不是经验丰富的开发人员,只是尝试了所有可能的方法,直到我发现这对我有用,希望它对其他人也有用。
这是针对那些对上述解决方案不满意的人,因为他们提出了其他问题,例如重叠手势(例如,现在在 scrollview 中很难使用此解决方案)。另一个拐杖是创建一个像这样的自定义按钮样式
struct CustomButtonStyle<Content>: ButtonStyle where Content: View {
var change: (Bool) -> Content
func makeBody(configuration: Self.Configuration) -> some View {
return change(configuration.isPressed)
}
}
所以,我们应该只传递将 return 按钮状态的闭包,并根据此参数创建按钮。它将像这样使用:
struct CustomButton<Content>: View where Content: View {
var content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
Button(action: { }, label: {
EmptyView()
})
.buttonStyle(CustomButtonStyle(change: { bool in
Text("\(bool ? "yo" : "yo2")")
}))
}
}
好的,让我再次清除所有内容。这是确切的解决方案
- 创建下面的按钮修改器。
struct StateableButton<Content>: ButtonStyle where Content: View {
var change: (Bool) -> Content
func makeBody(configuration: Configuration) -> some View {
return change(configuration.isPressed)
}
}
- 然后像下面一样使用它
Button(action: {
print("Do something")
}, label: {
// Don't create your button view in here
EmptyView()
})
.buttonStyle(StateableButton(change: { state in
// Create your button view in here
return HStack {
Image(systemName: "clock.arrow.circlepath")
Text(item)
Spacer()
Image(systemName: "arrow.up.backward")
}
.padding(.horizontal)
.frame(height: 50)
.background(state ? Color.black : Color.clear)
}))
您需要定义一个自定义样式,用于为正常状态和高亮状态提供两种背景:
Button(action: {
print("action")
}, label: {
Text("My Button").padding()
})
.buttonStyle(HighlightableButtonStyle(normal: { Color.red },
highlighted: { Color.green }))
// Custom button style
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
struct HighlightableButtonStyle<N, H>: ButtonStyle where N: View, H: View {
private let alignment: Alignment
private let normal: () -> N
private let highlighted: () -> H
init(alignment: Alignment = .center, @ViewBuilder normal: @escaping () -> N, @ViewBuilder highlighted: @escaping () -> H) {
self.alignment = alignment
self.normal = normal
self.highlighted = highlighted
}
func makeBody(configuration: Configuration) -> some View {
return ZStack {
if configuration.isPressed {
configuration.label.background(alignment: alignment, content: normal)
}
else {
configuration.label.background(alignment: alignment, content: highlighted)
}
}
}
}