SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

引言

在上一篇博客中我们已经介绍了事件与状态的绑定,通过对Button、TextField以及Slider控件的使用也了解了应用对用户操作的相应方式和能力。SwiftUI作为Apple提供的声明式UI框架,使得我们能够更加自然地管理用户的交互方式。

在本篇博客中,我们将重点探讨SwiftUI中的手势以及选择控件:gesture、Picker、DataPicker。这些控件不仅可以扩展应用的功能,还能为用户提供更加多样化的选择方式。通过它们,我们可以轻松实现响应式UI,让我们的应用在交互上更灵活。

添加手势

和UIKit一样,在SwiftUI中的任何视图都可以添加手势识别,而这些手势识别器会有一个闭包,当手势事件被激活时将会调用闭包中的代码。

手势同样也有很多类型,本篇博客中我们就选几个来介绍,因为它们非常相似。

TapGesture(点击手势)

首先是TapGesture,该手势是我们最常用的一个手势。当我们创建点击手势时,可以指定触发手势所需要的点击次数,然后添加一个onEnded闭包,该闭包将会在点击手势结束之后运行。例如下面的代码,每点击一次数量就会加1:


struct ContentView: View {
    @State private var count = 0
    var body: some View {
        VStack {
            Image(systemName: "plus")
                .resizable()
                .frame(width: 30, height: 30)
                .foregroundColor(.red)
                .background(
                    Circle()
                        .fill(.yellow)
                        .frame(width: 50, height:50)
                )
                .padding()
                .gesture(
                    TapGesture()
                        .onEnded { _ in
                            count += 1
                        }
                )
            Text("Count: \(count)")
                .padding()
                .background(.green)
        }
        .padding()
    }
}

SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

我们也可以直接使用OnTapGesture()效果是一样的:

            Image(systemName: "plus")
                .resizable()
                .frame(width: 30, height: 30)
                .foregroundColor(.red)
                .background(
                    Circle()
                        .fill(.yellow)
                        .frame(width: 50, height:50)
                )
                .padding()
                .onTapGesture {
                    count += 1
                }

LongPressGesture(长按手势)

其次就是LongPressGesture长按手势,用来识别用户在视图上按住的时间,当时间长达到我们指定的最小时长时则会触发该手势的闭包,我们来写一个案例,当长按达到2秒后显示出一个背景图片:

    @State private var show = false
    var body: some View {
        ZStack {
            if show {
                Image("swift")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
            }

            Image(systemName: "plus")
                .resizable()
                .frame(width: 30, height: 30)
                .foregroundColor(.red)
                .background(
                    Circle()
                        .fill(.yellow)
                        .frame(width: 50, height:50)
                )
                .padding()
                .onLongPressGesture {
                    show.toggle()
                }
        }
        .padding()
    }

SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

DragGesture(拖拽手势)

最后一个是拖拽手势,在实际开发中也是十分常用的,用户按下视图并至少拖拽一定距离后触发。下面的代码创建了一个图像,当用户拖拽至少20个点时就会触发拖拽手势:

    @State private var offset = CGSize.zero
    var body: some View {
        Image(systemName: "plus")
            .resizable()
            .frame(width: 30, height: 30)
            .foregroundColor(.red)
            .background(
                Circle()
                    .fill(.yellow)
                    .frame(width: 50, height:50)
            )
            .padding()
            .offset(offset)
            .gesture(
                DragGesture(minimumDistance: 20)
                    .onChanged { value in
                        offset = value.translation
                    }
                    .onEnded { value in
                        offset = .zero
                    }
            )
    }

运行代码会发现,当我们拖拽时图片会跟随我们的手指来回移动。

选择器

选择器是应用中不必可少的控件,通常选择日期,年龄,地区等等很多场景都会使用到,每个平台也都会提供一些系统的选择器,SwiftUI也为我们提供了丰富的选择器类型,下面我们来一一看一下吧。

Picker(普通选择器)

SwiftUI中的Picker视图成功将UIKit中的UIPicker和UITableView结合在一起。同时还适应了其他操作系统上的不同样式。并且我们不需要关心它到底是如何实现的SwiftUI能够很好地自动适应其环境。

与大多数控件一样,我们必须将选择器的值绑定到一个变量,以跟踪选择器的选择结果。例如下面的代码,创建了一个颜色数组和一个存储下标的整数变量,然后我们来创建一个选择器,并将结果显示到文本视图中:

    private let colors = ["红","黄","蓝","绿"]
    @State private var seletedIndex = 0
    var body: some View {
        VStack {
            Text("\(colors[seletedIndex])")
                .padding()
            Picker("颜色", selection: $seletedIndex) {
                ForEach(0..<colors.count) {
                    Text(colors[$0])
                }
            }
           
        }
    }

SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

Picker(分段控制器)

在SwiftUI中,并没有提供像UISegmentedControl一样的分段控制器,而是使用Picker来实现,当我们指定Picker的样式为SegmentedPickerStyle时,则显示为分段控制器,代码如下:

    @State private var favoriteColor = 0
       var colors = ["Red", "Green", "Blue"]
    var body: some View {
        VStack {
            Text("SegmentedControl")
                .padding()
            Picker("Favorite Color", selection: $favoriteColor) {
                ForEach(0..<colors.count) {
                    Text(self.colors[$0])
                }
            }
            .pickerStyle(SegmentedPickerStyle())
        }
    }

SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

DataPicker(日期选择器)

SwiftUI中的DatePiker视图类似于UIKit中的UIDatePicker,提供了多种选项来控制其外观和功能。与所有存储值的控件一样,它需要绑定到某个状态变量中。

例如,下面的代码创建了一个绑定到birthDate属性的日期选择器,并在设置日期时显示其值:

    @State private var birthDate = Date()
    private var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }
    private let maxmiumDate = Date()
    var body: some View {
        VStack {
            Text("日期选择器")
                .padding()
            DatePicker("出生日期",
                       selection: $birthDate,
                          in: ...maxmiumDate,
                       displayedComponents: .date)
                .datePickerStyle(WheelDatePickerStyle())
            Text("出生日期: \(birthDate, formatter: dateFormatter)")
                .padding()
        }
    }

SwiftUI(七)- 手势和选择器(gesture、Picker、DatePicker)-LMLPHP

结语

在SwiftUI中,通过手势和选择器等控件的组合,用户体验得到了进一步增强。我们可以在简单的声明式代码下完成复杂的交互逻辑,无论是通过 gesture 实现个性化的手势响应,还是通过 Picker 和 DatePicker 提供灵活的数据选择方式。SwiftUI的这种设计,帮助开发者高效构建出动态交互的应用。

希望本篇文章能帮助您理解和运用这些控件,不断提升应用的互动性和用户满意度。SwiftUI的持续更新还将带来更多便利与可能性,让我们一起期待更多创新的功能!

10-31 08:59