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