作为一名刚接触SwiftUI的开发者,在运用 Button 时还是遇到了不少的困惑。网上绝大部分教程都仅仅浅浅地说了下用法,授人以鱼不如授人以渔,let’s go~
1.Xcode运用(如现已熟练,请越过)
在Xcode中,咱们能够按住 command + shift + L 组合键,来调用出一个窗口,在这个窗口下,咱们能够很方便的查找咱们所需的一些 Controls,比方Button,Text等,如图所示:

在Xcode中,你能够经过拖拽的方式来快速生成一个Button组件,亦或许直接在代码中输入Button字样,也能够得到相关的编译提示,如图所示:
接着咱们按住 command + 鼠标左键,按回车去到Button的界说文件中
2. Button的参数
在界说文件中,将Button相关的先折叠起来,如图所示
其间 Label 为 Button中的泛型,它遵从了 View 协议,并决议了每个Button实例将运用什么类型的视图进行渲染。
依据不同的Label,咱们能够运用不同的初始化参数。
初始化参数(-):action与label

action参数为一个逃逸闭包,当用户单击或点击按钮时它会履行相关操作。而label参数为一个跟随闭包,咱们能够在其间写一些自界说的视图(custom view)。所以关于这种初始化,咱们能够写出以下代码:
// 正常写法
Button(action: {}, label: {
Text("按钮")
})
// 因为参数label是个跟随闭包,则能够省掉关键字,用大括号直接翻开
Button(action:{}){
Text("按钮")
}
// 因为label参数的回来类型是泛型Label,而泛型Label又遵从了View协议,所以咱们能在其间写相关自界说的视图
Button(action:{}){
VStack{
Text("按钮")
Text("描述文字")
}
.foregroundColor(.red)
}
初始化参数(二): titleKey/title,action
依据类型的界说能够知道,在第一个参数中,咱们能够传 LocalizedStringKey 或许是一般的 String 字符串,action 参数则同上。
什么是 LocalizedStringKey ?
关于LocalizedStringKey官方文档是这么解说的:The key used to look up an entry in a strings file or strings dictionary file.
意思便是,当你的字符串用 LocalizedStringKey 创立或许运用其类型声明时,SwiftUI会依据你当时的言语环境,自动翻译成对应的字符串。比方:
let hello:LocalizedStringKey = "Hello"
let today = LocalizedStringKey("Today")
var body: some View {
VStack{
Text(hello) //在中文环境下,将会变成字符串 "你好"
Text(today) //在中文环境下,将会变成字符串 "今日"
}
.font(.largeTitle)
}
接下来咱们看 preview 的作用
额…这不是没啥改变吗?在这儿,咱们需求做一些装备。咱们先点击根项目,然后添加对应的中文简体言语,如图所示:
接着新建一个Strings File文件,运用其默许命名即可。

同样在检查器 Localzation 中,挑选中文简体,如图所示:
接着咱们在 Localizable 文件夹中的两个文件内,写入对应的翻译。
Tips:笔者查了一圈下来,大部分的做法是在Preview中加上 .environment(\.locale, .init(identifier: "zh-Hans")),这样能够预览到言语的改变。但在笔者的Xcode中,这不管用,可能是我Xcode的版别(14.2)过高了。这儿咱们挑选 command + R 运行模拟器来看作用。注意,你需求在模拟器的体系中,切换手机的体系言语,如图所示:
然后翻开咱们构建后的App应用,就能够看到作用了。
咱们在本来代码的基础上,再添加一些:
let str = "Hello"
var body: some View {
VStack{
Text(hello) //在中文环境下,将会变成字符串 "你好"
Text(today) //在中文环境下,将会变成字符串 "今日"
Text("Hello") // 新增
Text(str) // 新增
}
.font(.largeTitle)
}
猜猜看,它的成果是什么?
在 SwiftUI 中,Button、Text等视图,在传入文本参数时会优先进行言语本地化。假如你不想将文本翻译成本地化言语,能够像上方相同,将Text中的文本值抽出来,提前用let声明即可。
———————————分割线————————————
了解完 LocalizedStringKey 后,是不是第二种 Button 的传值方式便心领神会啦~咱们写出以下的代码:
let str = "Hello"
var body: some View {
VStack{
Button("按钮", action: {})
Button("按钮"){}
}
.font(.largeTitle)
}
在后续的界说文件中,也便是ios15.0,咱们看到了 SwiftUI 关于这两种初始化,加多了一个可选参数 role,如图所示
在 role 传参中,有两种 ButtonRole 供你挑选。
- destructive:用于删去用户数据或履行不可逆操作的按钮。
- cancel: 用于撤销操作按钮。
说时迟那时快,相信有朋友现已快速写出以下代码试试水了
VStack{
Button("按钮",role: .cancel){}
Button("按钮",role: .destructive){}
}
.font(.largeTitle)

role参数? 其实这两种 role 首要结合着 .swipeActions 和 .alert 进行运用,如下所示:
struct ButtonView: View {
@State private var isPresented = false
var body: some View {
VStack{
List{
Text("测试滑动")
.swipeActions {
Button("一般按钮", action: {})
Button("撤销按钮", role: .cancel, action: {})
Button("删去按钮", role: .destructive, action: {})
}
}
Button("Show Alert", action: {
isPresented = true
})
.alert("Alert", isPresented: $isPresented) {
Button("撤销按钮", role: .cancel, action: {})
Button("一般按钮", action: {})
Button("删去按钮", role: .destructive, action: {})
}
}
}
}
感兴趣的朋友能够看看详细的款式表现~因为今日咱们首要讲Button,就不对其他的进行拓宽了(等会讲不完了)。
初始化参数(三):configuration

PrimitiveButtonStyleConfiguration 类型的参数。依据上方的注释,咱们相关例子界说一个struct,这个struct需求遵从 PrimitiveButtonStyle 协议,并且咱们需求在 .buttonStyle 修饰符中进行运用,如图所示:
ok话不多说,咱们先照猫画虎,把这个struct按照例子先实现一下
struct ButtonView: View {
struct RedBorderedButtonStyle: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
// 这儿便是Button接收configuration的情况啦
Button(configuration)
.border(Color.red)
}
}
var body: some View {
VStack{
Button("按钮"){}
.buttonStyle(RedBorderedButtonStyle())
}
.font(.largeTitle)
}
}
经过预览后的UI咱们能够看到,它为当时的按钮加了个赤色边框。oh~不会绕了一圈,仅仅加了个赤色边框罢了吧? 别着急,咱们还没运用 configuration 这个 struct 里边的内容呢。这儿的Configuration实践上便是 PrimitiveButtonStyleConfiguration,咱们来看看它这儿面有啥。
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public struct PrimitiveButtonStyleConfiguration {
public struct Label : View {.
public typealias Body = Never
}
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
public let role: ButtonRole?
/// A view that describes the effect of calling the button's action.
public let label: PrimitiveButtonStyleConfiguration.Label
/// Performs the button's action.
public func trigger()
}
role咱们在上面现已讲过了,这儿不再多讲。label 表明的是咱们当时触发这个按钮后,需求展现出来的视图方式。 trigger 办法表明你能够经过调用 configuration.trigger() 的方式来自动触发按钮。咱们先写出以下的代码:
struct ButtonView: View {
struct RedBorderedButtonStyle: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
// 自动触发按钮
configuration.trigger()
return configuration.label.border(.red)
// configuration.label.onTapGesture {
// configuration.trigger()
// }
}
}
var body: some View {
VStack{
Button("按钮"){
print("按钮被触发了~")
}
.buttonStyle(RedBorderedButtonStyle())
}
.font(.largeTitle)
}
}
预览UI如图所示:

Tips: Xcode到高版别后,输出只能在 Simulator 中检查,所以command + R 以检查相关输出。
3. Button的款式与交互
3-1: ButtonStyle
在阅览Button文档的过程中,想必你注意到了这样一段话:
You can also create custom styles. To add a custom appearance with standard interaction behavior, create a style that conforms to theButtonStyleprotocol. To customize both appearance and interaction behavior, create a style that conforms to thePrimitiveButtonStyleprotocol. Custom styles can also read the button’s role and use it to adjust the button’s appearance.
官方言语讲得便是很官方,咱们还是来看看 ButtonStyle 的相关界说吧。

ButtonStyle 协议如同和PrimitiveButtonStyle 协议差不多。
接着看一下ButtonStyleConfiguration ,能够发现它里边提供的是 isPressed常量,用来判别当时用户是否按下按钮。而之前的PrimitiveButtonStyleConfiguration 提供的是 trigger 办法,能够允许咱们自动去触发按钮。
接下来咱们经过一个需求来更好的领会 ButtonStyle的作用。比方我想在用户按下按钮时,让按钮添加一些改变。如下所示:
struct ButtonView: View {
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.background(.blue)
.cornerRadius(10)
.foregroundColor(.white)
.scaleEffect(configuration.isPressed ? 2 : 1)
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
}
}
var body: some View {
VStack{
Button("按钮"){
print("按钮被触发了~")
}
.buttonStyle(CustomButtonStyle())
}
.font(.largeTitle)
}
}
Tips: 能够发现,咱们是在按下按钮履行对应的作用后,再触发 Button 的 action。
3-2:ButtonStyle 和 PrimitiveButtonStyle的差异
在做完以上的工作后,相信你对这两种 Style 的了解现已很透彻了。那么咱们能够总结一下这两种Style的运用场景。
- 想对按钮的款式做一些修改并且自动触发按钮,咱们能够运用
PrimitiveButtonStyle。 - 想在按钮被按下时做一些作用交互,咱们能够运用
ButtonStyle。
3-3:运用Modifier添加自界说款式
除了以上的办法,咱们还能够创立一个自界说的 Modifier 来修改相关按钮的款式。咱们按下 command + N 创立一个 Styles 文件,并写上以下代码:
import SwiftUI
struct YellowButtonStyle:ViewModifier{
func body(content: Content) -> some View {
content
.padding()
.background(.yellow)
.cornerRadius(10)
.foregroundColor(.white)
}
}
接着咱们能够在代码中这样去运用:
Button("黄色按钮"){}.modifier(YellowButtonStyle())
这样看起来方便了一些,但这个 modifier 看着很不顺眼,能够去掉吗?当然了。咱们能够在Styles文件中,对 YellowButtonStyle进行拓宽,如下:
import SwiftUI
struct YellowButtonStyle:ViewModifier{
func body(content: Content) -> some View {
content
.padding()
.background(.yellow)
.cornerRadius(10)
.foregroundColor(.white)
}
}
extension View{
func yellowButtonStyle() -> some View{
modifier(YellowButtonStyle())
}
}
然后咱们这样去运用即可:
Button("黄色按钮"){}.yellowButtonStyle()
4.Button的拓宽
上面咱们提到过,在 Buttton 中提供了一个 Label 泛型。咱们能够利用该泛型进行对应的拓宽。比方咱们想创立一个图画按钮,能够这样做:
struct ButtonView: View {
var body: some View {
VStack{
Button(iconName: "camera.shutter.button"){}
}
.font(.largeTitle)
.foregroundColor(.gray)
}
}
extension Button where Label == Image{
init(iconName: String, action: @escaping () -> Void) {
self.init(action: action) {
Image(systemName: iconName)
}
}
}
作用如图所示:
你可能会很猎奇,这个 “camera.shutter.button” 是怎样来的?Apple其实给我提供了一些内置的符号,咱们能够在官网的设计资源中下载对应的软件。
以上便是全部内容了,感谢你坚持读完,欢迎在谈论区进行交流~





















