SwiftUI 教程

SwiftUI 主页 SwiftUI 概览 SwiftUI 与 UIkit

SwiftUI 环境

SwiftUI 安装和环境配置 SwiftUI 基本组件 SwiftUI 构建第一个应用程序

SwiftUI 视图

SwiftUI 视图 SwiftUI 自定义文本视图 SwiftUI 自定义图像视图 SwiftUI 堆栈

SwiftUI 绘制形状

SwiftUI 形状 SwiftUI 绘制线条 SwiftUI 绘制矩形 SwiftUI 绘制圆角矩形 SwiftUI 绘制三角形 SwiftUI 绘制圆形 SwiftUI 绘制星形 SwiftUI 绘制多边形 SwiftUI 绘制饼图 SwiftUI 使用内置形状

SwiftUI 文本

SwiftUI 文本视图 SwiftUI 文本输入和输出

SwiftUI 颜色

SwiftUI 颜色 SwiftUI 颜色选择器 SwiftUI 渐变 SwiftUI 调整颜色

SwiftUI 效果

SwiftUI 效果 SwiftUI 混合效果 SwiftUI BLur 效果 SwiftUI 阴影效果 SwiftUI 悬停效果

SwiftUI 动画

SwiftUI 动画 SwiftUI 创建动画 SwiftUI 创建显式动画 SwiftUI 多个动画 SwiftUI 过渡 SwiftUI 不对称过渡 SwiftUI 自定义过渡

SwiftUI 图像

SwiftUI 图像 SwiftUI 图像作为背景 SwiftUI 旋转图像 SwiftUI 媒体

SwiftUI 视图布局

SwiftUI 视图布局 SwiftUI 视图大小 SwiftUI 视图间距 SwiftUI 视图填充

SwiftUI UI 控件

SwiftUI UI 控件 SwiftUI 按钮 SwiftUI 复选框 SwiftUI 菜单栏 SwiftUI 工具栏 SwiftUI 搜索栏 SwiftUI 文本字段 SwiftUI 滑块 SwiftUI 切换 SwiftUI 选择器 SwiftUI 菜单

SwiftUI 列表 &表格

SwiftUI 列表 SwiftUI 静态列表 SwiftUI 动态列表 SwiftUI 自定义列表 SwiftUI 表格

SwiftUI 表单

SwiftUI 表单 SwiftUI 在部分中拆分表单

SwiftUI 事件处理

SwiftUI 事件处理 SwiftUI 手势 SwiftUI 剪贴板 SwiftUI 拖放 SwiftUI 焦点 SwiftUI 警报

SwiftUI 杂项

SwiftUI 容器 SwiftUI 导航 SwiftUI 通知 SwiftUI 跨平台 UI SwiftUI 数据 SwiftUI 可访问性

SwiftUI 框架集成

SwiftUI 框架集成 SwiftUI 与 UIKit 交互 SwiftUI 创建 macOS 应用

SwiftUI 有用资源

SwiftUI 有用资源 SwiftUI 讨论


SwiftUI - 手势

手势用于处理用户与应用中的 UI 组件之间的交互。或者我们可以说手势处理触摸事件。它通过响应用户的触摸和动作,为所有 Apple 平台创建交互式和响应式应用。

SwiftUI 支持各种内置手势,例如点击、拖动、滑动等,我们还可以创建自定义手势来满足应用的要求。

在这里,手势通常支持单指交互,SwiftUI 不提供任何特殊功能来设置移动的总手指数。手势取代了传统按钮,与按钮相比提供了更多功能。

SwiftUI 中的手势类型

SwiftUI 为不同类型的交互提供了各种手势。它既支持预定义手势,也支持自定义手势。一些常用的手势如下−

点击手势

点击手势用于识别视图上的单个或多个点击。它是最常用和最简单的手势。我们可以借助 .onTapGesture() 修饰符来实现点击手势。此修饰符只要找到点击手势,就会执行指定的操作。

语法

以下是语法 −

func onTapGesture(count:Int, perfrom: action)

参数

以下是修饰符 −

接受的参数
  • count:表示点击总数。默认情况下,该值为 1。

  • action:表示要执行的操作。

示例

以下 SwiftUI 程序执行点击手势。在这里,当我们点击形状时,形状从胶囊变为矩形。

import SwiftUI
struct ContentView: View {
   @State private var isShape = true
   var body: some View {
      Group {
         if isShape {
            Capsule()
               .fill(.green)
               .frame(width: 100, height: 50)
               .overlay(Text("Tap Me").font(.title2))
         } else {
            Rectangle().fill(.blue).frame(width: 100, height: 100)
         }
      }.onTapGesture {
         
         // 在胶囊和矩形之间切换形状
         isShape.toggle()
      }
   }
}
#Preview {
   ContentView()
}

输出

Gesture

长按手势

长按手势用于识别视图上的长按。此手势通过使用 .onLongPressGesture() 修饰符激活。此修饰符插入一个操作,该操作将在用户长按给定 UI 组件或视图时执行。

语法

以下是语法−

func onLongPressGesture(minimumDuration:Double, perfrom:action, onPressingChanged: Bool)

参数

以下是修饰符−接受的参数

  • minimumDuration:表示长按的最小持续时间。

  • action:表示要执行的操作。

  • onPressingChanged:表示当手势的按下状态改变时将运行的闭包。

示例

以下 SwiftUI 程序执行长按手势。

import SwiftUI
struct ContentView: View {
   @State private var isPress = false
   var body: some View {
      Rectangle()
         .fill(isPress ? .red : .yellow)
         .frame(width: 100, height: 100)
         .gesture(            
            // 按住 0.5 秒
            LongPressGesture(minimumDuration: 0.5).onEnded { _ in                  
                  // 长按结束时切换颜色
                  isPress.toggle()
               }
         )
   }
}
#Preview {
   ContentView()
}

输出

Gesture

DragGesture

拖动手势用于跟踪用户手指在屏幕上的移动。它允许用户通过在屏幕上拖动视图来更新视图的位置。我们可以借助 DragGesture() 方法实现拖动手势。此方法在手势成功之前创建一个具有最小拖动距离的拖动手势,并且还包含手势位置的坐标。此方法始终在 .gesture() 修饰符内使用。

语法

以下是语法 −

func DragGesture(minimumDistance:CGFloat, coordinateSpace:coordinates)

参数

以下是修饰符 − 接受的参数

  • minimumDistance:表示最小拖动距离。

  • coordinateSpace:表示执行拖动手势的坐标空间。

示例

以下 SwiftUI 程序执行拖动手势。

import SwiftUI
struct ContentView: View {   
   // 追踪位置
   @State private var position = CGSize.zero
   
   // 跟踪拖动偏移
   @State private var dragOffsetValue = CGSize.zero
   var body: some View {
      VStack {
         Text("Drag the Text").font(.title)
         
         // 可拖拽文本
         Text("TutorialsPoint")
            .font(.largeTitle)
            .frame(width: 200)
            .foregroundStyle(.red)
            .offset(x: position.width + dragOffsetValue.width, y: position.height + dragOffsetValue.height)
            .gesture(
               DragGesture().onChanged { g in                     
                     // 拖动过程中更新偏移值
                     dragOffsetValue = g.translation
                  }.onEnded { _ in
                     
                     // 拖动完成后更新位置。
                     position.width += dragOffsetValue.width
                     position.height += dragOffsetValue.height
                     dragOffsetValue = .zero
                  }
            ).animation(.easeIn, value: position)
      }
   }
}
#Preview {
   ContentView()
}

输出

Gesture

MagnifyGesture

放大手势用于跟踪放大动作或捏合缩放手势。此手势通过使用 MagnifyGesture() 方法实现。此方法创建一个放大手势,我们可以通过该手势缩放视图。它也用于 .gesture() 修饰符内。

语法

以下是语法−

func MagnifyGesture(minimumDelta:CGFloat)

参数

它仅需要一个参数,即启动手势的最小缩放值。

示例

以下 SwiftUI 程序执行放大手势。

import SwiftUI
struct ContentView: View {
   // 跟踪当前比例
   @State private var initialScale: CGFloat = 1.0
   
   // 手势开始前轨道缩放
   @State private var finalScale: CGFloat = 1.0

   var body: some View {
      Rectangle()
         .fill(.red)
         .frame(width: 200, height: 200)
      
         // 应用缩放因子
         .scaleEffect(initialScale)
         .gesture(
            MagnificationGesture().onChanged { x in
                  
                  // 根据放大倍数更新比例
                  initialScale = finalScale * x
               }.onEnded { _ in
                  // 手势结束时保存比例
                  finalScale = initialScale
               }
         ).animation(.easeInOut, value: initialScale)
   }
}
#Preview {
   ContentView()
}

输出

Gesture

RotateGesture

旋转手势用于跟踪旋转运动,并允许我们将视图围绕其锚点旋转到指定角度。我们可以使用 RotateGesture() 方法创建旋转手势。此方法创建一个旋转手势,跟踪旋转运动,并且视图中的角度被旋转。它也用于 .gesture() 修饰符内部。

语法

以下是语法−

func RotateGesture(minimumAngleDelta: Angle)

参数

它只接受一个参数,即启动手势的最小角度。此参数的默认值为 0 度。

示例

以下 SwiftUI 程序执行旋转手势。

import SwiftUI
struct ContentView: View {   
   // 当前旋转角度
   @State private var initialAngle: Angle = .zero
   
   // 最后确认的角度
   @State private var endAngle: Angle = .zero
   var body: some View {      
      Text("Rotate Me!").font(.largeTitle).padding()      
         // 将旋转效果应用于文本
         .rotationEffect(initialAngle)
         .gesture(
            RotationGesture()
               .onChanged { x in
                  
                  // 根据旋转手势更新角度
                  initialAngle = endAngle + x
               }.onEnded { _ in
                  
                  // 手势结束后的最终角度
                  endAngle = initialAngle
               }
         ).animation(.easeInOut, value: initialAngle)
   }
}

#Preview {
   ContentView()
}

输出

Gesture

在 SwiftUI 中组合手势

在 SwiftUI 中,我们可以组合多个手势,以便同时使用多个手势。或者通过组合多个手势,我们可以创建一个新手势。因此,要组合手势,我们可以遵循以下任何一种方法 −

同时

同时手势是一个容器,我们可以在其中使用两个同时运行的手势,而没有任何优先权。例如,我们同时结合旋转和点击手势,因此每当我们点击图像时,图像就会开始旋转。

语法

以下是语法−

func SimultaneousGesture(first: FirstGesture, second: SecondGesture)

参数

它需要两个参数来保存相同类型或不同类型的两个手势。

示例

以下 SwiftUI 程序在 SimultaneousGesture() 的帮助下同时运行两个点击和拖动手势。

import SwiftUI

struct ContentView: View {   
   // 跟踪点击状态
   @State private var isTap = false   
   // 追踪当前位置
   @State private var currentPosition = CGSize.zero   
   // 追踪拖动位置
   @GestureState private var dragPosition = CGSize.zero
   var body: some View {
      Text("Tap Me and Drag Me")
         .font(.largeTitle)
         .background(isTap ? .brown : .green)
         .foregroundStyle(.white)
         .offset(x: currentPosition.width + dragPosition.width, y: currentPosition.height + dragPosition.height)
         .gesture(
            
            // 使用 SimultaneousGesture 运行两个手势
            SimultaneousGesture(
               TapGesture().onEnded {
                     
                     // 点击时切换颜色
                     isTap.toggle()
                  },               
               DragGesture()
                  .updating($dragPosition) { x, dragPosition, _ in
                     // 更新拖拽偏移
                     dragPosition = x.translation
                  }.onEnded { x in
                     // 拖动完成后更新位置
                     currentPosition.width += x.translation.width
                     currentPosition.height += x.translation.height
                  }
            )
         ).animation(.easeInOut, value: isTap)
   }
}
#Preview {
   ContentView()
}

输出

Gesture

序列

序列用于按顺序应用两个手势,这里第二个手势是在完成第一个手势后识别的。或者我们可以说手势是按顺序识别的。当我们想在指定的手势序列之后触发动作时,它很有用。这里手势的优先级很重要。

语法

以下是语法−

func SequenceGesture(first: FirstGesture, second: SecondGesture)

参数

它需要两个参数来保存相同类型或不同类型的两个手势。

示例

以下 SwiftUI 程序在 SequenceGesture() 函数的帮助下按顺序运行两个手势(点击和拖动手势)。

import SwiftUI

struct ContentView: View {
   
   //跟踪点击状态
   @State private var isTap = false
   
   // 追踪当前位置
   @State private var currentPosition = CGSize.zero
   
   // 追踪拖动位置
   @GestureState private var dragPosition = CGSize.zero

   var body: some View {      
      Text("Tap Me and Drag Me")
         .font(.largeTitle)
         .background(isTap ? .brown : .green)
         .foregroundStyle(.white)
         .offset(x: currentPosition.width + dragPosition.width, y: currentPosition.height + dragPosition.height)
         .gesture(            
            // 使用 SequenceGesture 按顺序运行两个手势
            SequenceGesture(
               TapGesture().onEnded {                     
                     // 点击时切换颜色
                     isTap.toggle()
                  },               
               DragGesture()
                  .updating($dragPosition) { x, dragPosition, _ in
                     // 更新拖拽偏移
                     dragPosition = x.translation
                  }.onEnded { x in
                     // 拖动完成后更新位置
                     currentPosition.width += x.translation.width
                     currentPosition.height += x.translation.height
                  }
            )
         ).animation(.easeInOut, value: isTap)
   }
}
#Preview {
   ContentView()
}

输出

Gesture

独占

独占手势是一种由两个手势组成的手势,其中只有一个手势会被执行。默认情况下,系统将优先执行第一个手势。

语法

以下是语法−

func ExclusiveGesture(first: FirstGesture, second: SecondGesture)

参数

它需要两个参数来保存这两个手势。

示例

以下 SwiftUI 程序执行点击手势。

import SwiftUI

struct ContentView: View {   
   // 跟踪点击状态
   @State private var isTap = false
   
   // 追踪当前位置
   @State private var currentPosition = CGSize.zero 
  
   // 追踪拖动位置
   @GestureState private var dragPosition = CGSize.zero
   var body: some View {      
      Text("Tap Me & Drag Me")
         .font(.largeTitle)
         .background(isTap ? .yellow : .pink)
         .foregroundStyle(.white)
         .offset(x: currentPosition.width + dragPosition.width, y: currentPosition.height + dragPosition.height)
         .gesture(
            
            // 使用 ExclusiveGesture() 按顺序运行两个手势
            ExclusiveGesture(
               TapGesture().onEnded {                     
                     // 点击时切换颜色
                     isTap.toggle()
                  },               
               DragGesture()
                  .updating($dragPosition) { 
                      x, dragPosition, _ in
                     
                     // 更新拖拽偏移
                     dragPosition = x.translation
                  }.onEnded { x in
                     
                     // 拖动完成后更新位置
                     currentPosition.width += x.translation.width
                     currentPosition.height += x.translation.height
                  }
            )
         ).animation(.easeInOut, value: isTap)
   }
}
#Preview {
   ContentView()
}

输出

Gesture