MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

SwiftUI Button与Picker组件

2022-11-136.0k 阅读

SwiftUI Button 组件

Button 基础使用

在 SwiftUI 中,Button 是一个用于触发操作的重要组件。其基本初始化方式非常直观。我们可以创建一个简单的 Button,它带有一个标签和一个点击时执行的动作。例如:

Button("点击我") {
    print("按钮被点击了")
}

在上述代码中,我们创建了一个 Button,标签为“点击我”。当用户点击这个按钮时,会在控制台打印“按钮被点击了”。

Button 还支持通过 image 参数添加图标。比如,我们想要创建一个带有删除图标的按钮,可以这样写:

Button(action: {
    print("删除操作")
}) {
    HStack {
        Image(systemName: "trash")
        Text("删除")
    }
}

这里使用了 HStack 来水平排列图标和文本,使得按钮看起来更加丰富。

Button 的样式定制

SwiftUI 允许我们对 Button 的样式进行高度定制。我们可以通过 buttonStyle 修饰符来改变按钮的外观。例如,将按钮样式设置为 PlainButtonStyle,它会移除按钮的默认背景和边框:

Button("无样式按钮") {
    print("无样式按钮被点击")
}
.buttonStyle(PlainButtonStyle())

如果想要自定义按钮样式,可以创建一个遵循 ButtonStyle 协议的结构体。假设我们要创建一个带有渐变背景的按钮样式:

struct GradientButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
           .padding()
           .background(LinearGradient(gradient: Gradient(colors: [.blue,.purple]), startPoint:.topLeading, endPoint:.bottomTrailing))
           .foregroundColor(.white)
           .cornerRadius(10)
           .scaleEffect(configuration.isPressed? 0.95 : 1.0)
    }
}

Button("渐变按钮") {
    print("渐变按钮被点击")
}
.buttonStyle(GradientButtonStyle())

在上述代码中,GradientButtonStyle 结构体实现了 makeBody 方法,根据按钮的配置状态(是否被按下)来定制按钮的外观。通过 padding 添加内边距,background 设置渐变背景,foregroundColor 设置文本颜色,cornerRadius 设置圆角,scaleEffect 根据按钮是否被按下改变按钮的缩放比例。

处理 Button 的状态

有时候,我们需要根据按钮的状态(如是否被按下、是否可用)来执行不同的逻辑或改变按钮的外观。Button 提供了一些方式来处理这些状态。

例如,我们可以通过 isDisabled 修饰符来禁用按钮:

@State private var isButtonDisabled = true

Button("禁用的按钮") {
    print("按钮被点击,但由于禁用不会执行此操作")
}
.isDisabled(isButtonDisabled)

在这个例子中,通过 @State 声明了一个布尔变量 isButtonDisabled,并将其传递给 isDisabled 修饰符来禁用按钮。如果我们想要根据按钮的按下状态来改变某些 UI,比如改变文本颜色,我们可以利用 Buttonconfiguration

Button(action: {
    print("按钮被点击")
}) {
    let configuration = EnvironmentValues().buttonConfiguration
    Text("动态颜色按钮")
       .foregroundColor(configuration?.isPressed == true?.red :.blue)
}

这里通过 EnvironmentValues 获取按钮的配置,根据 isPressed 状态改变文本颜色。

Button 与导航

在应用程序中,Button 经常用于触发导航操作。在 SwiftUI 中,结合 NavigationLink 可以轻松实现这一点。例如,假设我们有一个主视图和一个详情视图,点击按钮从主视图导航到详情视图:

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: DetailView()) {
                    Button("前往详情") {
                        print("导航按钮被点击")
                    }
                }
            }
           .navigationTitle("主视图")
        }
    }
}

struct DetailView: View {
    var body: some View {
        Text("这是详情视图")
           .navigationTitle("详情")
    }
}

在上述代码中,NavigationLink 包裹着 Button,当按钮被点击时,会导航到 DetailViewNavigationView 提供了导航的上下文,navigationTitle 用于设置导航栏的标题。

SwiftUI Picker 组件

Picker 基础使用

Picker 是 SwiftUI 中用于选择值的组件,类似于传统 UI 框架中的下拉菜单或选择器。Picker 需要一个标签和一组选项供用户选择。

例如,我们创建一个简单的 Picker 用于选择颜色:

struct ColorPickerView: View {
    @State private var selectedColorIndex = 0
    let colors = ["红色", "绿色", "蓝色"]

    var body: some View {
        Picker("选择颜色", selection: $selectedColorIndex) {
            ForEach(0..<colors.count) { index in
                Text(self.colors[index]).tag(index)
            }
        }
    }
}

在这个例子中,我们使用 @State 来存储当前选中的颜色索引 selectedColorIndexPicker 的第一个参数是标签,用于在某些样式下显示,第二个参数 selection 绑定到我们的状态变量。ForEach 循环用于创建每个选项,tag 用于将每个选项与一个值关联,这里关联的是颜色的索引。

Picker 的样式

SwiftUI 为 Picker 提供了多种样式。默认情况下,在 iOS 上,Picker 会以紧凑的样式显示,在 macOS 上会以弹出框的样式显示。

我们可以通过 pickerStyle 修饰符来改变样式。例如,将 Picker 的样式设置为 WheelPickerStyle,它会以滚轮的形式显示选项,在 iOS 上常用于日期选择等场景:

struct WheelColorPickerView: View {
    @State private var selectedColorIndex = 0
    let colors = ["红色", "绿色", "蓝色"]

    var body: some View {
        Picker("选择颜色", selection: $selectedColorIndex) {
            ForEach(0..<colors.count) { index in
                Text(self.colors[index]).tag(index)
            }
        }
       .pickerStyle(WheelPickerStyle())
    }
}

另一种常见的样式是 SegmentedPickerStyle,它会将选项以分段控件的形式显示:

struct SegmentedColorPickerView: View {
    @State private var selectedColorIndex = 0
    let colors = ["红色", "绿色", "蓝色"]

    var body: some View {
        Picker("选择颜色", selection: $selectedColorIndex) {
            ForEach(0..<colors.count) { index in
                Text(self.colors[index]).tag(index)
            }
        }
       .pickerStyle(SegmentedPickerStyle())
    }
}

这种样式在需要紧凑显示选项且用户需要快速切换选项时非常有用。

Picker 与数据模型

在实际应用中,Picker 通常会与更复杂的数据模型一起使用。假设我们有一个表示水果的结构体,并且想要创建一个 Picker 来选择水果:

struct Fruit {
    let name: String
    let calories: Int
}

struct FruitPickerView: View {
    @State private var selectedFruitIndex = 0
    let fruits: [Fruit] = [
        Fruit(name: "苹果", calories: 52),
        Fruit(name: "香蕉", calories: 89),
        Fruit(name: "橙子", calories: 48)
    ]

    var body: some View {
        Picker("选择水果", selection: $selectedFruitIndex) {
            ForEach(0..<fruits.count) { index in
                Text(self.fruits[index].name).tag(index)
            }
        }
    }
}

这里我们定义了 Fruit 结构体,包含水果名称和卡路里信息。Picker 仍然基于索引来选择水果,但是我们可以根据选中的索引进一步获取水果的详细信息。例如,如果我们想要在选择水果后显示其卡路里信息:

struct FruitDetailView: View {
    @State private var selectedFruitIndex = 0
    let fruits: [Fruit] = [
        Fruit(name: "苹果", calories: 52),
        Fruit(name: "香蕉", calories: 89),
        Fruit(name: "橙子", calories: 48)
    ]

    var body: some View {
        VStack {
            Picker("选择水果", selection: $selectedFruitIndex) {
                ForEach(0..<fruits.count) { index in
                    Text(self.fruits[index].name).tag(index)
                }
            }
           .pickerStyle(SegmentedPickerStyle())
            Text("所选水果的卡路里:\(fruits[selectedFruitIndex].calories)")
        }
    }
}

通过这种方式,我们将 Picker 与实际的数据模型相结合,实现了更丰富的功能。

多列 Picker

在某些情况下,我们可能需要创建多列的 Picker,比如日期选择器,需要同时选择年、月、日。SwiftUI 允许我们通过嵌套 Picker 来实现这一点。

struct DatePickerView: View {
    @State private var selectedYearIndex = 0
    @State private var selectedMonthIndex = 0
    @State private var selectedDayIndex = 0

    let years = Array(2000...2030)
    let months = Array(1...12)
    let days = Array(1...31)

    var body: some View {
        HStack {
            Picker("选择年份", selection: $selectedYearIndex) {
                ForEach(0..<years.count) { index in
                    Text("\(self.years[index])").tag(index)
                }
            }
           .pickerStyle(WheelPickerStyle())
            Picker("选择月份", selection: $selectedMonthIndex) {
                ForEach(0..<months.count) { index in
                    Text("\(self.months[index])").tag(index)
                }
            }
           .pickerStyle(WheelPickerStyle())
            Picker("选择日期", selection: $selectedDayIndex) {
                ForEach(0..<days.count) { index in
                    Text("\(self.days[index])").tag(index)
                }
            }
           .pickerStyle(WheelPickerStyle())
        }
    }
}

在上述代码中,我们通过 HStack 水平排列了三个 Picker,分别用于选择年、月、日。每个 Picker 都有自己的状态变量来存储选中的值,并且都使用了 WheelPickerStyle 来呈现滚轮样式。这样就创建了一个简单的多列 Picker,类似于常见的日期选择器。

通过深入了解 SwiftUI ButtonPicker 组件的这些特性,开发者可以创建出更加交互性强、用户体验良好的应用界面。无论是简单的操作触发还是复杂的选项选择,这两个组件都提供了丰富的功能和定制性,以满足不同的应用需求。