UI基础 - UIResponder:视图缩放 | 视图拖动

▶ UIResponder

1 - 如果自定义的响应者是 UIview 或是 UIViewController 的子类则必须声明全部四个 UIResponder对象 的处理事件方法!这样做的原因很简单:所有视图都可以接收到完整的触摸事件流。如果自定义响应者是 UIKit 中响应者类,则不必如此

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

注:获得点击次数的最佳时机是在 touchBegan 和 touchEnd 方法中,后者最佳

2 - UITouch属性

tapCount       本次触摸点击了多少次

timestamp     本次触摸何时创建以及最后一次改变的时间

phase            本次触摸所处的阶段

locationView                 触摸视图中的坐标

previousLocationView    上一次触摸的位置

3 - 限制触摸事件给特定视图

缺省情况下视图的 exclusiveTouch 属性设置为 NO,表示该视图并不限制当前窗口中的其他视图接收触摸事件

如果你设置其值 YES 则标识了该视图且只有该视图能对消息进行跟踪处理,窗口中的其他视图则无法接收到触摸事件

4 - 代码示例:实现视图的缩放、拖动效果(前提是要新建一个 UIView 的子类,并且还要重写 UIResponder对象 处理事件方法)

A. 拖动

方式一:直接计算偏移量

// - TouchView.m

 1 #import "TouchView.h"
 2 @interface TouchView ()
 3 @property(nonatomic,assign)CGPoint startPoint;
 4 
 5 @end
 6 
 7 @implementation TouchView
 8 
 9 #pragma mark - overriding_methods
10 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
11     
12     NSLog(@"touchesBegan!");
13     self.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 255.0 green:arc4random() % 256 / 255.0 blue:arc4random() % 256 / 255.0 alpha:1.0];// 随机颜色
14     // 获取手指
15     UITouch *touch = [touches anyObject];
16     // 获取手指触摸坐标
17     self.startPoint = [touch locationInView:self];
18     NSLog(@"%@",NSStringFromCGPoint(self.startPoint));
19 }
20 
21 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
22     NSLog(@"touchesCancelled!");
23 }
24 
25 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
26     NSLog(@"touchesEnded!");
27 }
28 
29 // 实现视图的拖动功能
30 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
31     NSLog(@"touchesMoved!");
32     
33     UITouch *touch = [touches anyObject];
34     CGPoint  currentPoint = [touch locationInView:self];
35     
36     // 获取 X 轴和 Y 轴的偏移量
37     CGFloat offSetX = currentPoint.x - self.startPoint.x;
38     CGFloat offSetY = currentPoint.y - self.startPoint.y;
39     
40     // 获取中心坐标
41     CGPoint newCenter = self.center;
42     newCenter.x += offSetX;
43     newCenter.y += offSetY;
44     self.center = newCenter;
45 }
46 
47 @end

方式二:使用 previousLocationInView: 计算出偏移量

// - TestView

 1 #import "TestView.h"
 2 @implementation TestView
 3 
 4 #pragma mark - overriding_methods
 5 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 6 }
 7 
 8 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
 9     NSLog(@"touchesCancelled!");
10 }
11 
12 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
13     NSLog(@"touchesEnded!");
14 }
15 
16 // 实现视图的拖动功能
17 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
18     NSLog(@"touchesMoved!");
19 
20     UITouch *touch = [touches anyObject];
21     CGPoint currentPoint = [touch locationInView:self];
22     CGPoint prePoint = [touch previousLocationInView:self];
23 
24     CGRect viewFrame = self.frame;
25     // 获取 X 轴和 Y 轴的偏移量
26     CGFloat offSetX = currentPoint.x - prePoint.x;
27     CGFloat offSetY = currentPoint.y - prePoint.y;
28     viewFrame.origin.y =  viewFrame.origin.y + offSetY;
29     viewFrame.origin.x =  viewFrame.origin.x + offSetX;
30     self.frame = viewFrame;
31 
32 }
33 
34 @end

B. 缩放

方式一:通过捏合实现视图缩放

// - PinchView.m

 1 #import "PinchView.h"
 2 @interface PinchView ()
 3 @property(nonatomic,assign)CGFloat beginDistance;
 4 
 5 @end
 6 
 7 @implementation PinchView
 8 
 9 #pragma mark - overrideMethods
10 // 实现缩放功能
11 - (id)initWithFrame:(CGRect)frame{
12     self = [super initWithFrame:frame];
13     if (self) {
14         
15         self.multipleTouchEnabled = YES;// 开启多点触摸(默认是单指触摸)
16     }
17     return self;
18 }
19 
20 // 实现缩放功能:步骤一
21 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
22     
23     if (touches.count == 2) {
24         UITouch *firstTouch = [[touches allObjects] firstObject];
25         UITouch *secondTouch = [[touches allObjects] lastObject];
26         
27         CGPoint firstPiont = [firstTouch locationInView:self];  // 拿到第一根手指点的坐标
28         CGPoint secondPiont = [secondTouch locationInView:self];// 拿到第二根手指点的坐标
29         self.beginDistance = [self distanceWithPointA:firstPiont pointB:secondPiont];// 获取两点间的距离
30     }
31 }
32 
33 // 实现缩放功能:步骤二
34 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
35     if (touches.count == 2) {
36         UITouch *firstTouch = [[touches allObjects] firstObject];
37         UITouch *secondTouch = [[touches allObjects] lastObject];
38 
39         CGPoint firstPiont = [firstTouch locationInView:self];
40         CGPoint secondPiont = [secondTouch locationInView:self];
41         CGFloat newDistance = [self distanceWithPointA:firstPiont pointB:secondPiont];
42         
43         CGFloat scale = newDistance / self.beginDistance;// 缩放系数
44 
45         CGRect newBounds = self.bounds;
46         newBounds.size.width *= scale;
47         newBounds.size.height *= scale;
48         self.bounds = newBounds;
49         
50         self.beginDistance = newDistance;// 计算完毕后记得要把两点间的距离初始化一次
51     }
52 }
53 
54 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
55     
56     NSLog(@"touchesEnded!");
57 }
58 
59 #pragma mark - self-defined-methods
60 - (CGFloat)distanceWithPointA:(CGPoint)pointA pointB:(CGPoint)pointB{
61 
62     // 返回两点间的距离(勾股定理)
63     return sqrt( pow(pointA.x - pointB.x, 2) + pow(pointA.y - pointB.y, 2));
64 }
65 
66 @end

方式二:单击视图缩小;双击视图放大

// - TestView.m

 1 #import "TestView.h"
 2 
 3 @implementation TestView{
 4     NSDictionary *_locationDic; // 实例变量:配合方式二使用
 5 }
 6 
 7 
 8 #pragma mark - overrding_methods
 9 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
10     
11     UITouch *touch = [touches anyObject];
12     if (touch.tapCount - 2 == 0) {
13         
14         // 取消所有延迟操作:这里是取消 单击 1 次时的操作
15         [NSObject cancelPreviousPerformRequestsWithTarget:self];
16         
17         // 方式二:取消某个特定的延迟方法
18         // 注意:参数要和执行的方法所传递的参数保持一致
19         if (_locationDic) {
20             [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleSingleTap:) object:_locationDic];
21         }
22         
23     }
24 }
25 
26 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
27     
28     UITouch *touch = [touches anyObject];
29     
30     // 单击:1 秒后执行
31     if (touch.tapCount - 1 == 0) {
32         
33         _locationDic = [NSDictionary dictionaryWithObject:[NSValue valueWithCGPoint:[touch locationInView:self]] forKey:@"location"];
34         [self performSelector:@selector(handleSingleTap:) withObject:_locationDic afterDelay:1.0];
35     
36     }
37     
38     // 双击:视图扩大
39     else if (touch.tapCount - 2 == 0){
40         
41         CGRect viewFrame = self.frame;
42         // 宽高增加 20%
43         viewFrame.size.width += self.frame.size.width * 0.2;
44         viewFrame.size.height += self.frame.size.height * 0.2;
45         // 更新中心坐标
46         viewFrame.origin.x -= (self.frame.size.width * 0.2)/2.0;
47         viewFrame.origin.y -= (self.frame.size.height * 0.2)/2.0;
48         
49         // 搞一个动画,效果更新然
50         [UIView beginAnimations:nil context:NULL];
51         [UIView setAnimationDuration:1.2];
52         self.frame = viewFrame;
53         [UIView commitAnimations];
54     }
55 }
56 
57 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
58     
59     
60 }
61 
62 - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
63     
64 }
65 
66 
67 #pragma mark - self_defined_methods
68 // 单击:视图缩小
69 -(void)handleSingleTap:(NSDictionary *)touches{
70     
71     CGRect viewFrame = self.frame;
72     // 宽高增加 20%
73     viewFrame.size.width -= self.frame.size.width * 0.2;
74     viewFrame.size.height -= self.frame.size.height * 0.2;
75     // 更新中心坐标
76     viewFrame.origin.x += (self.frame.size.width * 0.2)/2.0;
77     viewFrame.origin.y += (self.frame.size.height * 0.2)/2.0;
78     
79     
80     [UIView beginAnimations:nil context:NULL];
81     [UIView setAnimationDuration:1.2];
82     self.frame = viewFrame;
83     [UIView commitAnimations];
84     
85 }
86 @end

// - ViewController.m

1 - (void)viewDidLoad {
2     [super viewDidLoad];
3     self.view.backgroundColor = [UIColor cyanColor];
4     
5     TestView *tView = [[TestView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 200)/2.0, 80, 200, 160)];
6     tView.backgroundColor = [UIColor redColor];
7     [self.view addSubview:tView];
8     
9 }

运行效果:初始视图  |  单击缩小  |  双击放

    

 

posted on 2018-04-10 14:18  低头捡石頭  阅读(19)  评论(0编辑  收藏  举报

导航