SwiftUI-手势

SwiftUI为视图提供了许多手势,比如:
单击onTapGesture()
多击onTapGesture(count:)
长按onLongPressGesture()
放大MagnificationGesture()
旋转RotationGesture()

单击
Text("单击")
      .onTapGesture {
          print("单击🚀")
}
双击
Text("双击")
      .onTapGesture(count: 2) {
          print("双击🚀")
}
长按

长按相比单击手势复杂一点,是可以定制的。例如,指定需要满足的最少时长和最大时长。

Text("长按")
    .onLongPressGesture(minimumDuration: 1, maximumDistance: 3, pressing: { (isProgress) in
        print("长按进行中 -> \(isProgress)")
     }) {
         print("长按🚀")
}

长按进行中 -> true
长按进行中 -> false
长按🚀

对于更高级的手势,你需要使用gesture()Modifier,并提供DragGestureLongPressGestureMagnificationGestureRotationGestureTapGesture。这些手势都有特定Modifier,最常用包括手势进行中onEnded (),已完成onEnded (),你可以在这里执行动作。

放大
struct ContentView: View {
    @State private var currentAmount: CGFloat = 0
    @State private var finalAmount: CGFloat = 1

    var body: some View {
        Text("放大")
            .scaleEffect(finalAmount + currentAmount)
            .gesture(
                MagnificationGesture()
                    .onChanged { amount in
                        self.currentAmount = amount - 1
                    }
                    .onEnded { amount in
                        self.finalAmount += self.currentAmount 
                        self.currentAmount = 0
                    }
            )
    }
}
旋转
struct ContentView: View {
    @State private var currentAngle: Angle = .degrees(0)
    @State private var finalAngle: Angle = .degrees(0)

    var body: some View {
        Text("旋转")
            .rotationEffect(currentAmount + finalAmount)
            .gesture(
                RotationGesture()
                    .onChanged { angle in
                        self.currentAmount = angle
                    }
                    .onEnded { angle in
                        self.finalAmount += self.currentAmount
                        self.currentAmount = .degrees(0)
                    }
            )
    }
}
手势冲突

加入子视图和父视图同时有单击手势,点击子视图默认只会触发子视图的单击手势,我们可以使用highPriorityGesture ()来强制父视图的手势优先。或者使用simultaneousGesture ()来使父视图和子视图的手势同时触发。

struct ContentView: View {
    var body: some View {
        VStack {
            Text("单击")
                .onTapGesture {
                    print("单击🚀")
                }
        }
    // simultaneousGesture(父视图和子视图同时触发) highPriorityGesture(高优先级,优先触发)
        .simultaneousGesture(
            TapGesture()
                .onEnded { _ in
                    print("VStack🚀")
                }
        )
    }
}
手势序列

SwiftUI还可以创建手势序列,序列中的手势之间存在引用,只有前一个手势成功识别之后才会被激活识别。

struct DragView: View {
    
    // 圆被拖拽的偏移量
    @State private var offset = CGSize.zero
    // 圆是否正在被拖拽
    @State private var isDragging = false

    var body: some View {
        
        // 拖拽手势更新偏移量,结束后更新偏移量和isDragging
        let dragGesture = DragGesture()
            .onChanged { (value) in
                self.offset = value.translation
        }
        .onEnded { (_) in
            withAnimation {
                self.offset = .zero
                self.isDragging = false
            }
        }
        // 长按手势激活isDragging
        let pressGesture = LongPressGesture()
            .onEnded { (value) in
                withAnimation {
                    self.isDragging = true
                }
        }
        // 组合手势
        let combined = pressGesture.sequenced(before: dragGesture)
        
        return Circle()
            .fill(Color.blue)
            .frame(width: 80, height: 80)
            .scaleEffect(isDragging ? 2 : 1)
            .offset(offset)
            .gesture(combined)
    }
}

全部示例代码

ContentView
struct ContentView: View {
    
    // 记录放大的值
    @State private var currentAmount: CGFloat = 0
    @State private var finalAmount: CGFloat = 1
    // 记录旋转的值
    @State private var currentAngle: Angle = .degrees(0)
    @State private var finalAngle: Angle = .degrees(0)
    
    var body: some View {
        
        VStack {
        
            VStack {
                Text("单击")
                    .onTapGesture {
                        print("单击🚀")
                }.padding(.top).padding(.horizontal)
                Text("双击")
                    .onTapGesture(count: 2) {
                        print("双击🚀")
                }.padding(.top)
                Text("长按")
                    .onLongPressGesture(minimumDuration: 1, maximumDistance: 3, pressing: { (isProgress) in
                        print("长按进行中 -> \(isProgress)")
                    }) {
                        print("长按🚀")
                }.padding(.top)
                Text("放大")
                .scaleEffect(finalAmount + currentAmount)
                .gesture(
                    MagnificationGesture()
                        .onChanged({ (amount) in
                            self.currentAmount = amount - 1
                        })
                        .onEnded({ (amount) in
                            self.finalAmount += self.currentAmount
                            self.currentAmount = 0
                        })
                ).padding(.top)
                Text("旋转")
                .rotationEffect(finalAngle + currentAngle)
                .gesture(
                    RotationGesture()
                        .onChanged({ (angle) in
                            self.currentAngle = angle
                        })
                        .onEnded({ (angle) in
                            self.finalAngle += self.currentAngle
                            self.currentAngle = .degrees(0)
                        })
                ).padding(.vertical)
                
            }
            .font(.title)
            .background(Color.red)
    //          simultaneousGesture(父视图和子视图同时触发) highPriorityGesture(高优先级,优先触发)
            .simultaneousGesture(
                TapGesture()
                    .onEnded({ (_) in
                        print("VStack🚀")
                    })
            )
            
            // 拖拽view
            DragView()
        }
    }
}
DragView
struct DragView: View {
    
    // 手势序列
    // 圆被拖拽的偏移量
    @State private var offset = CGSize.zero
    // 圆是否正在被拖拽
    @State private var isDragging = false

    var body: some View {
        
        // 拖拽手势更新偏移量,结束后更新偏移量和isDragging
        let dragGesture = DragGesture()
            .onChanged { (value) in
                self.offset = value.translation
        }
        .onEnded { (_) in
            withAnimation {
                self.offset = .zero
                self.isDragging = false
            }
        }
        // 长按手势激活isDragging
        let pressGesture = LongPressGesture()
            .onEnded { (value) in
                withAnimation {
                    self.isDragging = true
                }
        }
        // 组合手势
        let combined = pressGesture.sequenced(before: dragGesture)
        
        return Circle()
            .fill(Color.blue)
            .frame(width: 80, height: 80)
            .scaleEffect(isDragging ? 2 : 1)
            .offset(offset)
            .gesture(combined)
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,387评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,845评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,091评论 0 246
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,308评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,662评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,795评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,008评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,466评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,687评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,181评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,531评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,177评论 3 239
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,126评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,862评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,734评论 2 274