57、iOS触摸与手势开发实战

iOS触摸与手势开发实战

在iOS开发中,处理触摸和手势是构建交互性应用的重要部分。本文将详细介绍如何处理触摸事件及实现常见手势识别,同时会通过两个具体应用示例进行说明。

触摸事件基础

在处理触摸事件时,并非所有触摸对象都与当前视图或视图控制器相关。例如,表格视图单元格可能不关心其他行或导航栏上的触摸。可以通过以下代码获取特定视图内的触摸集合:

let myTouches = event.touchesForView(self.view)

每个 UITouch 对象代表一根手指,可通过它获取手指在屏幕上的位置,还能将该位置转换为视图的本地坐标系:

let point = touch.locationInView(self.view)  // point是CGPoint类型

以下是几个重要的触摸相关方法:
1. touchesMoved(_, withEvent:) :当用户手指在屏幕上移动时会多次调用该方法,每次调用都会得到一组新的触摸对象和事件。除了能获取手指当前位置,还能获取上次调用 touchesMoved(_, withEvent:) touchesBegan(_, withEvent:) 时手指的位置。
2. touchesEnded(_, withEvent:) :当用户手指离开屏幕时调用,表明一次手势操作结束。
3. touchesCancelled(_, withEvent:) :当用户在进行手势操作时被中断(如来电)会调用该方法。调用此方法后,当前手势不会再调用 touchesEnded(_, withEvent:)

TouchExplorer应用实践

为了更好地理解上述四个触摸相关方法的调用时机,我们来构建一个 TouchExplorer 应用。
1. 创建项目 :在Xcode中使用单视图应用模板创建新项目,产品名称为 TouchExplorer ,设备选择 Universal
2. 添加标签 :该应用需要三个标签,分别用于显示最后调用的方法、当前点击次数和触摸次数。在 ViewController.swift 中添加以下代码:

class ViewController: UIViewController {
    @IBOutlet var messageLabel:UILabel!
    @IBOutlet var tapsLabel:UILabel!
    @IBOutlet var touchesLabel:UILabel!
}
  1. 编辑GUI :选择 Main.storyboard 编辑界面,拖放一个标签到视图左上角,按住 Option 键再拖出两个标签,使其上下排列。
  2. 设置约束 :在文档大纲中,从第一个标签按住 Control 键拖动到主视图,按住 Shift 键选择“Top Space to Top Layout Guide”和“Leading Space to Container Margin”,对其他两个标签执行相同操作。
  3. 连接标签 :从视图控制器图标按住 Control 键拖动到三个标签,分别连接到对应的出口。
  4. 清除标签文本 :双击每个标签并按 Delete 键清除文本。
  5. 启用交互 :点击视图背景或文档大纲中的视图图标,打开属性检查器,确保“User Interaction Enabled”和“Multiple Touch”都被勾选。
  6. 修改代码 :在 ViewController.swift 中添加以下代码:
class ViewController: UIViewController {
    @IBOutlet var messageLabel:UILabel!
    @IBOutlet var tapsLabel:UILabel!
    @IBOutlet var touchesLabel:UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // 加载视图后进行额外设置,通常从nib加载
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 释放可重新创建的资源
    }

    func updateLabelsFromTouches(touches:NSSet!) {
        let touch = touches.anyObject() as UITouch
        let numTaps = touch.tapCount
        let tapsMessage = "\(numTaps) taps detected"
        tapsLabel.text = tapsMessage

        let numTouches = touches.count
        let touchMsg = "\(numTouches) touches detected"
        touchesLabel.text = touchMsg
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        messageLabel.text = "Touches Began"
        updateLabelsFromTouches(event.allTouches())
    }

    override func touchesCancelled(touches: NSSet, withEvent event: UIEvent) {
        messageLabel.text = "Touches Cancelled"
        updateLabelsFromTouches(event.allTouches())
    }

    override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
        messageLabel.text = "Touches Ended"
        updateLabelsFromTouches(event.allTouches())
    }

    override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
        messageLabel.text = "Drag Detected"
        updateLabelsFromTouches(event.allTouches())
    }
}

在这个控制器类中,实现了四个触摸相关方法,每个方法都会设置 messageLabel 以显示调用时机,并调用 updateLabelsFromTouches() 更新其他两个标签。
9. 编译运行 :编译并运行应用。在模拟器中,可多次点击屏幕增加点击次数,点击并按住鼠标拖动模拟触摸和拖动操作。还可以通过按住 Option 键模拟双指捏合,按住 Option Shift 键模拟双指滑动。

Swipes应用实践

接下来构建一个 Swipes 应用,用于检测水平和垂直滑动手势。
1. 创建项目 :在Xcode中使用单视图应用模板创建新项目,设备选择 Universal ,项目名称为 Swipes
2. 添加代码 :在 ViewController.swift 中添加以下代码:

class ViewController: UIViewController {
    @IBOutlet var label:UILabel!
    private var gestureStartPoint:CGPoint!
}
  1. 编辑界面 :选择 Main.storyboard ,确保视图的“User Interaction Enabled”和“Multiple Touch”都被勾选。从库中拖动一个标签到视图上部,设置文本居中,调整其他文本属性。在文档大纲中,从标签按住 Control 键拖动到视图,按住 Shift 键选择“Top Space to Top Layout Guide”和“Center Horizontally in Container”。从视图控制器图标按住 Control 键拖动到标签,连接到 label 出口,双击标签删除文本。
  2. 进一步添加代码 :在 ViewController.swift 中继续添加以下代码:
class ViewController: UIViewController {
    @IBOutlet var label:UILabel!
    private var gestureStartPoint:CGPoint!

    private let minimumGestureLength = Float(25.0)
    private let maximumVariance = Float(5)

    override func viewDidLoad() {
        super.viewDidLoad()
        // 加载视图后进行额外设置,通常从nib加载
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 释放可重新创建的资源
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        let touch = touches.anyObject() as UITouch
        gestureStartPoint = touch.locationInView(self.view)
    }

    override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
        let touch = touches.anyObject() as UITouch
        let currentPosition = touch.locationInView(self.view)

        let deltaX = fabsf(Float(gestureStartPoint.x - currentPosition.x))
        let deltaY = fabsf(Float(gestureStartPoint.y - currentPosition.y))

        if deltaX >= minimumGestureLength && deltaY <= maximumVariance {
            label.text = "Horizontal swipe detected"
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
                           dispatch_get_main_queue(),
                           { self.label.text = "" })
        } else if deltaY >= minimumGestureLength && deltaX <= maximumVariance {
            label.text = "Vertical swipe detected"
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
                           dispatch_get_main_queue(),
                           { self.label.text = "" })
        }
    }
}

touchesBegan(_, withEvent:) 方法中,获取触摸点并存储。在 touchesMoved(_, withEvent:) 方法中,计算手指水平和垂直移动的距离,判断是否构成滑动手势。如果构成,则设置标签文本并在2秒后清除。
5. 编译运行 :编译并运行应用,在模拟器中进行滑动操作测试。

自动手势识别

iOS提供了 UIGestureRecognizer 类,可简化手势识别的实现。以下是修改 Swipes 应用使用手势识别器的步骤:
1. 删除原有方法 :在 ViewController.swift 中删除 touchesBegan(_, withEvent:) touchesMoved(_, withEvent:) 方法。
2. 添加新方法 :添加以下方法:

func reportHorizontalSwipe(recognizer:UIGestureRecognizer) {
    label.text = "Horizontal swipe detected"
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(),
                   { self.label.text = "" })
}

func reportVerticalSwipe(recognizer:UIGestureRecognizer) {
    label.text = "Vertical swipe detected"
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(),
                   { self.label.text = "" })
}
  1. 修改viewDidLoad方法
override func viewDidLoad() {
    super.viewDidLoad()
    // 加载视图后进行额外设置,通常从nib加载

    let vertical = UISwipeGestureRecognizer(target: self, action: "reportVerticalSwipe:")
    vertical.direction = .Up | .Down
    view.addGestureRecognizer(vertical)

    let horizontal = UISwipeGestureRecognizer(target: self, action: "reportHorizontalSwipe:")
    horizontal.direction = .Left | .Right
    view.addGestureRecognizer(horizontal)
}

这里创建了两个手势识别器,分别用于检测垂直和水平滑动。当识别到相应手势时,调用对应的方法设置标签文本。
4. 清理代码 :可以删除 gestureStartPoint 属性声明和两个常量值。
5. 编译运行 :编译并运行应用,测试新的手势识别器。

实现多手指滑动

之前的 Swipes 应用只处理单手指滑动,若要处理多手指滑动,可通过配置 UISwipeGestureRecognizer 来实现。
1. 修改viewDidLoad方法

override func viewDidLoad() {
    super.viewDidLoad()
    // 加载视图后进行额外设置,通常从nib加载

    for var touchCount = 1; touchCount <= 5; touchCount++ {
        let vertical = UISwipeGestureRecognizer(target: self, action: "reportVerticalSwipe:")
        vertical.direction = .Up | .Down
        vertical.numberOfTouchesRequired = touchCount
        view.addGestureRecognizer(vertical)

        let horizontal = UISwipeGestureRecognizer(target: self, action: "reportHorizontalSwipe:")
        horizontal.direction = .Left | .Right
        horizontal.numberOfTouchesRequired = touchCount
        view.addGestureRecognizer(horizontal)
    }
}

通过循环创建多个手势识别器,每个识别器可识别不同数量的手指滑动。
2. 添加描述方法 :在 ViewController 类底部添加以下方法:

func descriptionForTouchCount(touchCount:Int) -> String {
    switch touchCount {
    case 1:
        return "Single"
    case 2:
        return "Double"
    case 3:
        return "Triple"
    case 4:
        return "Quadruple"
    case 5:
        return "Quintuple"
    default:
        return ""
    }
}
  1. 修改报告方法 :修改两个滑动报告方法:
func reportHorizontalSwipe(recognizer:UIGestureRecognizer) {
    label.text = "Horizontal swipe detected"
    let count = descriptionForTouchCount(recognizer.numberOfTouches())
    label.text = "\(count) Horizontal swipe detected"
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(),
                   { self.label.text = "" })
}

这样,不同数量手指的滑动会有相应的描述显示在标签上。

通过以上步骤,我们详细介绍了iOS中触摸事件的处理和手势识别的实现,从基础的触摸方法到使用手势识别器,再到多手指滑动的处理,希望能帮助你更好地开发具有交互性的iOS应用。

以下是一个简单的流程图,展示了 Swipes 应用使用手势识别器的流程:

graph TD;
    A[启动应用] --> B[创建手势识别器];
    B --> C[添加到视图];
    C --> D[等待手势];
    D --> E{识别到手势?};
    E -- 是 --> F[调用相应方法];
    F --> G[设置标签文本];
    G --> H[2秒后清除文本];
    E -- 否 --> D;

同时,为了更清晰地对比手动处理滑动和使用手势识别器的代码差异,以下是一个简单的表格:
| 方法 | 手动处理滑动 | 使用手势识别器 |
| ---- | ---- | ---- |
| 代码复杂度 | 较高,需要手动计算手指移动距离和判断 | 较低,只需创建识别器并配置 |
| 可读性 | 相对较低,涉及较多数学计算 | 较高,代码逻辑清晰 |
| 扩展性 | 较难实现复杂手势和多手指滑动 | 容易配置不同数量手指的滑动和复杂手势 |

iOS触摸与手势开发实战

多手指滑动配置详解

在实现多手指滑动时,我们通过循环创建了多个 UISwipeGestureRecognizer 实例。下面详细解释每个步骤的作用和好处。

首先是修改 viewDidLoad 方法的循环部分:

override func viewDidLoad() {
    super.viewDidLoad()
    // 加载视图后进行额外设置,通常从nib加载

    for var touchCount = 1; touchCount <= 5; touchCount++ {
        let vertical = UISwipeGestureRecognizer(target: self, action: "reportVerticalSwipe:")
        vertical.direction = .Up | .Down
        vertical.numberOfTouchesRequired = touchCount
        view.addGestureRecognizer(vertical)

        let horizontal = UISwipeGestureRecognizer(target: self, action: "reportHorizontalSwipe:")
        horizontal.direction = .Left | .Right
        horizontal.numberOfTouchesRequired = touchCount
        view.addGestureRecognizer(horizontal)
    }
}
  • 循环目的 :通过循环从1到5,为每个触摸数量(即手指数量)创建垂直和水平的滑动手势识别器。这样可以让应用识别从单指到五指的滑动操作。
  • 手势识别器配置
    • target: self :指定手势识别器触发时调用方法的对象为当前视图控制器。
    • action: "reportVerticalSwipe:" "reportHorizontalSwipe:" :指定手势识别成功时调用的方法。
    • direction :设置手势的方向, .Up | .Down 表示垂直方向, .Left | .Right 表示水平方向。
    • numberOfTouchesRequired = touchCount :指定该手势识别器需要的触摸数量,也就是手指数量。

接着是添加的描述方法:

func descriptionForTouchCount(touchCount:Int) -> String {
    switch touchCount {
    case 1:
        return "Single"
    case 2:
        return "Double"
    case 3:
        return "Triple"
    case 4:
        return "Quadruple"
    case 5:
        return "Quintuple"
    default:
        return ""
    }
}

这个方法通过 switch 语句根据触摸数量返回对应的描述字符串,方便在报告滑动时显示更详细的信息。

最后修改的报告方法:

func reportHorizontalSwipe(recognizer:UIGestureRecognizer) {
    label.text = "Horizontal swipe detected"
    let count = descriptionForTouchCount(recognizer.numberOfTouches())
    label.text = "\(count) Horizontal swipe detected"
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(),
                   { self.label.text = "" })
}

在这个方法中,先设置初始的滑动检测信息,然后通过 descriptionForTouchCount 方法获取触摸数量的描述,并更新标签文本。最后使用 dispatch_after 在2秒后清除标签文本,以便用户可以进行多次滑动操作。

手势识别器的优势总结

使用 UISwipeGestureRecognizer 等手势识别器具有以下明显优势:
1. 代码简洁 :相比手动处理触摸事件来检测滑动,使用手势识别器的代码量大大减少,逻辑更加清晰。例如,手动处理滑动需要在 touchesBegan touchesMoved 方法中进行复杂的计算和判断,而使用手势识别器只需要创建和配置识别器即可。
2. 易于扩展 :可以轻松配置不同数量的手指滑动和复杂手势。如上述的多手指滑动实现,通过简单的循环和配置就能实现从单指到五指的滑动识别。
3. 可读性高 :代码逻辑更符合人类思维,易于理解和维护。开发者不需要关注底层的触摸事件处理细节,只需要关注手势识别成功后的操作。

自定义手势识别器的展望

虽然iOS提供了丰富的内置手势识别器,但在某些场景下,可能需要自定义手势识别器来满足特定的需求。例如,应用需要识别一些独特的手势组合,如特定形状的滑动轨迹。

自定义手势识别器的基本步骤如下:
1. 继承 UIGestureRecognizer :创建一个新的类,继承自 UIGestureRecognizer
2. 重写方法 :重写 touchesBegan touchesMoved touchesEnded touchesCancelled 等方法,在这些方法中实现自定义的手势识别逻辑。
3. 状态管理 :根据手势的识别情况,设置手势识别器的状态,如 .began .changed .ended 等。

以下是一个简单的自定义手势识别器流程图:

graph TD;
    A[启动应用] --> B[创建自定义手势识别器];
    B --> C[等待触摸事件];
    C --> D{触摸开始?};
    D -- 是 --> E[调用touchesBegan];
    E --> F{手势识别中?};
    F -- 是 --> G[调用touchesMoved];
    G --> F;
    F -- 否 --> H{触摸结束?};
    H -- 是 --> I[调用touchesEnded];
    I --> J{手势识别成功?};
    J -- 是 --> K[设置状态为.ended并触发操作];
    J -- 否 --> L[设置状态为.failed];
    H -- 否 --> M{触摸取消?};
    M -- 是 --> N[调用touchesCancelled并设置状态为.cancelled];
    D -- 否 --> C;
总结

通过本文的介绍,我们深入了解了iOS中触摸事件的处理和手势识别的实现。从基础的触摸事件获取和处理,到使用内置的手势识别器简化开发,再到实现多手指滑动和展望自定义手势识别器,我们逐步掌握了构建交互性iOS应用的关键技术。

在实际开发中,建议优先使用内置的手势识别器,因为它们具有代码简洁、易于扩展和可读性高的优点。当内置识别器无法满足需求时,再考虑自定义手势识别器。希望这些知识能帮助你开发出更加丰富和交互性强的iOS应用。

以下是一个总结性的列表,回顾本文的主要内容:
1. 触摸事件基础:了解如何获取特定视图内的触摸集合和手指位置,以及重要的触摸相关方法。
2. TouchExplorer 应用:通过该应用实践,掌握触摸事件处理方法的调用时机和标签更新操作。
3. Swipes 应用:实现水平和垂直滑动手势的检测,包括手动处理和使用手势识别器两种方式。
4. 多手指滑动:通过配置 UISwipeGestureRecognizer 实现不同数量手指的滑动识别。
5. 手势识别器优势:代码简洁、易于扩展和可读性高。
6. 自定义手势识别器:展望自定义手势识别器的实现步骤和应用场景。

【SCI复现】基于纳什博弈的多微网主体电热双层共享策略研究(Matlab代码实现)内容概要:本文围绕“基于纳什博弈的多微网主体电热双层共享策略研究”展开,结合Matlab代码实现,复现了SCI级别的科研成果。研究聚焦于多个微网主体之间的能源共享问题,引入纳什博弈理论构建双层优化模型,上层为各微网间的非合作博弈策略,下层为各微网内部电热联合优化调度,实现能源高效利用经济性目标的平衡。文中详细阐述了模型构建、博弈均衡求解、约束处理及算法实现过程,并通过Matlab编程进行仿真验证,展示了多微网在电热耦合条件下的运行特性和共享效益。; 适合人群:具备一定电力系统、优化理论和博弈论基础知识的研究生、科研人员及从事能源互联网、微电网优化等相关领域的工程师。; 使用场景及目标:① 学习如何将纳什博弈应用于多主体能源系统优化;② 掌握双层优化模型的建模求解方法;③ 复现SCI论文中的仿真案例,提升科研实践能力;④ 为微电网集群协同调度、能源共享机制设计提供技术参考。; 阅读建议:建议读者结合Matlab代码逐行理解模型实现细节,重点关注博弈均衡的求解过程双层结构的迭代逻辑,同时可尝试修改参数或扩展模型以适应不同应用场景,深化对多主体协同优化机制的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值