按钮的基本写法有以下几种:
Button( title: , action: )
,由于最后一个参数是闭包,可以简写为 Button(""){ ... }
//当它只包含一些文本时,传递按钮的标题,以及点击按钮时应该运行的闭包即可
Button("Delete selection") { print("Now deleting…") }
//除了闭包,还可以给按钮传递具体的函数
Button("Delete selection", action: executeDelete)
func executeDelete() { print("Now deleting…") }
Button( action: { 动作闭包 } , label:{ 视图闭包 } )
,简写为 Button { 动作闭包 } label: { 视图闭包 }
//例子1:
Button(
action: { ... },
label:{
Text("忘记密码?").foregroundColor(.red)
}
)
//例子2:
Button( action: { ... } )
{
Image("yosemite")
.renderingMode(.original)
}
//纯图片按钮可能无法看见图片,这是由于图像渲染模式默认设置为“template”决定的
//template 意味着所有非透明区域都将使用强调色,遇到这种问题可以尝试更改渲染模式为 renderingMode(.original) 来解决
//例子3: 简写
Button {
print("Button was tapped")
} label: {
Text("Tap me!")
}
//例子4: 如果想要完全自定义的东西,可以使用第二个尾随闭包传递一个自定义标签
Button(
action: { print("Delete tapped!") }
)
{
HStack {
Image(systemName: "trash")
Text("Delete")
}
}
为按钮附加一个 role ,iOS 可以使用它来调整其外观,也更利于屏幕阅读器。例如,可以说 delete
按钮具有 destructive
作用;
Button("Delete", role: .destructive) { print("Delete") }
Button("Cancel", role: .cancel, action: executeCancel)
可以为按钮使用内置样式: .bordered
和 .borderedProminent
。它们可以单独使用,也可以与角色结合使用:
Button("Button 1") { ... }.buttonStyle(.bordered)
Button("Button 2", role: .destructive) { ... }.buttonStyle(.bordered)
// borderedProminent 的颜色更加强烈
Button("Button 3") { ... }.buttonStyle(.borderedProminent)
Button("Button 4", role: .destructive) { ... }.buttonStyle(.borderedProminent)
// 如果要自定义用于带边框按钮的颜色,请使用如下 tint() 修饰符:
Button("Button 3") { }
.buttonStyle(.borderedProminent)
.tint(.mint)
代码示例 | ||
---|---|---|
添加边框 | .overlay( RoundedRectangle(cornerRadius: 40).stroke(.purple, lineWidth: 5) ) | |
增加可点击区域 | .padding(20) | |
设置整体点击区域 | .contentShape(Rectangle()) | |
禁用按钮叠加颜色 | Image("Button") .renderingMode(.original) | 在 NavigationLink 也适用 |
禁用按钮叠加颜色 | .buttonStyle(.plain) | |
禁用按钮叠加颜色 | .buttonStyle(PlainButtonStyle()) | Xcode 12 之前版本 |
<aside>
💡 区别很微妙,但很重要:在 List
内使用 Button
时,如果使用 buttonStyle(.plain)
将意味着只有按钮内容直接周围的空间可以点击;而如果使用 .renderingMode(.original)
则整个单元格仍然可点击。
</aside>
有一个专用的 buttonRepeatBehavior()
修饰符,当用户按住按钮时,它会重复触发按钮的操作。该动作的触发速度越来越快,因此用户按住它的时间越长,触发的速度就越快。
// 例如,按下按钮时计数器会加 1,但如果按住按钮,它会继续以越来越快的速度加 1:
struct ContentView: View {
@State private var tapCount = 0
var body: some View {
Button("Tap Count: \\(tapCount)") {
tapCount += 1
}
.buttonRepeatBehavior(.enabled)
}
}
// 这种重复行为也适用于键盘快捷键,尽管它受到用户的键盘重复率的限制。
struct ContentView: View {
@State private var tapCount = 0
var body: some View {
Button("Tap Count: \\(tapCount)") {
tapCount += 1
}
.buttonRepeatBehavior(.enabled)
// 这允许用户按住 Shift+Return 来重复触发我们的按钮
.keyboardShortcut(.return, modifiers: .shift)
}
}
SwiftUI 可以轻松地为支持它的设备(例如 iPadOS 和 macOS)添加键盘快捷键,所有这些都使用 keyboardShortcut()
修饰符。您可以通过三种方式使用此修饰符,从最基本的开始:
方法一是将修饰符附加到现有操作。例如,如果我们有一个登录按钮并希望在用户按下 Cmd+L 时触发其行为,我们可以这样做:
Button("Log in") {
print("Authenticating…")
}
.keyboardShortcut("l")
请注意,这里不需要指定是 Cmd+L
,因为 SwiftUI 默认假设使用 Command 键,除非我们另外指定。如果您在 iPad 上运行该代码示例,您会看到按住 Cmd 键会弹出键盘快捷键叠加层,显示“Cmd+L Log in
”,SwiftUI 自动找出我们的按钮的功能并使其可用。
方法二是指定您实际需要的修饰键。例如,这会创建另外两个按钮
VStack {
Button("Run") {
print("Running…")
}
// 使用 Shift+R 触发“运行”按钮
.keyboardShortcut("r", modifiers: .shift)
Button("Home") {
print("Going home")
}
// 使用 Ctrl+Opt+Cmd+H 触发“主页”按钮
.keyboardShortcut("h", modifiers: [.control, .option, .command])
}
最后一种方法是使用其内置键之一,这对于难以键入的键(例如 Escape 和箭头)以及语义键(例如取消操作和默认操作。语义键非常有用 - 每次您按 Return 接受警报的默认操作,或按 Escape 取消操作时,您都使用了语义键。
Button("Confirm Launch") {
print("Launching drone…")
}
// 这将创建一个具有默认操作快捷方式的按钮,这意味着按 Return 键将触发它:
.keyboardShortcut(.defaultAction)
Swift提供了一个 ButtonStyle
的协议,让我们可以重复使用按钮样式。
ButtonStyle
协议,要求提供可接收 configuration
参数的 makeBody
函数configuration
参数包含一个 label
属性,该属性可以让你用修饰器更改按钮的样式// 创建新的按钮样式符合 ButtonStyle 协议
struct GradientBackgroundStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
//把自己的样式修饰符都写到这
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(LinearGradient(gradient: Gradient(colors: [Color("DarkGreen"), Color("LightGreen")]), startPoint: .leading, endPoint: .trailing))
.cornerRadius(40)
.padding(.horizontal, 20)
}
}
// 调用时:
Button(
action: { print("Delete tapped!") }
){
...
}
}
// 对所有按钮应用相同的样式
.buttonStyle(GradientBackgroundStyle())
// 自定义按钮样式,带有背景颜色和圆角参数
struct CustomButtonStyle: ButtonStyle {
let backgroundColor: Color
let cornerRadius: CGFloat
// 初始化方法,用于设置参数
init(backgroundColor: Color, cornerRadius: CGFloat) {
self.backgroundColor = backgroundColor
self.cornerRadius = cornerRadius
}
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(10)
.background(backgroundColor)
.foregroundColor(.white)
.cornerRadius(cornerRadius)
.scaleEffect(configuration.isPressed ? 0.95 : 1.0) // 添加按下效果
}
}
// 使用时
struct ContentView: View {
var body: some View {
Button(action: { ... }) {
Text("Custom Button")
}
.buttonStyle(CustomButtonStyle(backgroundColor: Color.blue, cornerRadius: 10))
}
}
configuration
有 isPressed
屬性。可以通过判断 isPressed
是否为true ,来判断按钮是否被按,以便直接设定按钮被按下时的样式。
struct GradientBackgroundStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(minWidth: 0, maxWidth: .infinity)
// 为真执行前面,为假执行后面
.scaleEffect(configuration.isPressed ? 0.9 : 1.0)
}
}
ControlGroup
视图让我们告诉系统两个或多个视图应该组合在一起,因为它们是相关的。它对这些信息的作用取决于使用它们的上下文以及代码运行的平台。例如,在 iOS 和 macOS 上,这将显示水平连接的三个按钮,其样式有时称为“瞬时分段”:
ControlGroup {
Button("First") { }
Button("Second") { }
Button("Third") { }
}
.padding()
ControlGroup
在创建可自定义的工具栏时特别有用,其中控件组中的按钮必须一起添加或删除,而不是分开。