实现侧滑效果 Swift

代码示例

开发环境

本系列文章的开发环境为:

1
2
OS X 10.10.3
Xcode Version 6.3 (6D570)

基本数据采集

初步体验,手Q采用的应该是线性动画,即缩放比例等随着手指滑动的距离以一次方程的形式变化。动画达到最大幅度时截图如下(4.7 寸):

提取基本数据:

右侧主视图左边界距离屏幕左边界的距离占屏幕宽度的比例为:78%

右侧主视图的高度占屏幕高度的比例为:77%

找出线性关系

  1. 比例与手指移动距离的关系

字比较丑 o(╯□╰)o。注意:式(1)中的 x 表示「手指移动距离」这个变量,和上面图中表示屏幕宽度的 x 意义不同。

  1. 矩形中心向右移动距离和手指移动距离相等

实现侧滑

  1. 新建项目,在 StoryBoard 中新增一个 View Controller,并新增一个名为 HomeViewController 的 UIViewController 类,并在 StoryBoard 中完成绑定。

  2. 给 HomeViewController 设置背景颜色以示区分。也可以像我一样设一个大 Label 作为更明显的区分。

  1. 给 HomeViewController 拖放一个 UIPanGestureRecognizer 并绑定到代码。

从右下角拖一个 Pan Gesture Recognizer 到主窗体上,这一步会让它与 HomeViewController.view 自动绑定。下图为第二步,绑定到代码。

  1. 编写代码实现效果:

新建 Common.swift,存储屏幕宽度、高度:

1
2
3
4
5
6
import UIKit

struct Common {
static let screenWidth = UIScreen.mainScreen().applicationFrame.maxX
static let screenHeight = UIScreen.mainScreen().applicationFrame.maxY
}

修改 ViewController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import UIKit

class ViewController: UIViewController {

var homeViewController: HomeViewController!
var distance: CGFloat = 0

let FullDistance: CGFloat = 0.78
let Proportion: CGFloat = 0.77

override func viewDidLoad() {
super.viewDidLoad()

// 给主视图设置背景
let imageView = UIImageView(image: UIImage(named: "back"))
imageView.frame = UIScreen.mainScreen().bounds
self.view.addSubview(imageView)

// 通过 StoryBoard 取出 HomeViewController 的 view,放在背景视图上面
homeViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
self.view.addSubview(homeViewController.view)

// 绑定 UIPanGestureRecognizer
homeViewController.panGesture.addTarget(self, action: Selector("pan:"))
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// 响应 UIPanGestureRecognizer 事件
func pan(recongnizer: UIPanGestureRecognizer) {
let x = recongnizer.translationInView(self.view).x
let trueDistance = distance + x // 实时距离

// 如果 UIPanGestureRecognizer 结束,则激活自动停靠
if recongnizer.state == UIGestureRecognizerState.Ended {

if trueDistance > Common.screenWidth * (Proportion / 3) {
showLeft()
} else if trueDistance < Common.screenWidth * -(Proportion / 3) {
showRight()
} else {
showHome()
}

return
}

// 计算缩放比例
var proportion: CGFloat = recongnizer.view!.frame.origin.x >= 0 ? -1 : 1
proportion *= trueDistance / Common.screenWidth
proportion *= 1 - Proportion
proportion /= 0.6
proportion += 1
if proportion <= Proportion { // 若比例已经达到最小,则不再继续动画
return
}
// 执行平移和缩放动画
recongnizer.view!.center = CGPointMake(self.view.center.x + trueDistance, self.view.center.y)
recongnizer.view!.transform = CGAffineTransformScale(CGAffineTransformIdentity, proportion, proportion)
}

// 封装三个方法,便于后期调用

// 展示左视图
func showLeft() {
distance = self.view.center.x * (FullDistance + Proportion / 2)
doTheAnimate(self.Proportion)
}
// 展示主视图
func showHome() {
distance = 0
doTheAnimate(1)
}
// 展示右视图
func showRight() {
distance = self.view.center.x * -(FullDistance + Proportion / 2)
doTheAnimate(self.Proportion)
}
// 执行三种试图展示
func doTheAnimate(proportion: CGFloat) {
UIView.animateWithDuration(0.3, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
self.homeViewController.view.center = CGPointMake(self.view.center.x + self.distance, self.view.center.y)
self.homeViewController.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, proportion, proportion)
}, completion: nil)
}

}

代码示例:https://github.com/johnlui/SwiftSideslipLikeQQ

The Why·Liam·Blog by WhyLiam is licensed under a Creative Commons BY-NC-ND 4.0 International License.

WhyLiam创作并维护的Why·Liam·Blog采用创作共用保留署名-非商业-禁止演绎4.0国际许可证

本文首发于Why·Liam·Blog (https://blog.naaln.com),版权所有,侵权必究。

本文永久链接:https://blog.naaln.com/2017/04/implementation-side-effect/