iOS 动画过程中view响应点击事件

对Core Animation来说,不管是显式动画还是隐式动画,对其设置frame都是立即设置的,比如说给一个UIView做移动动画,虽然看起来frame在持续改变,但其实它的frame已经是最终值了,这种情况下,哪怕这个UIView是UIButton的实例,其触发touch事件的范围还是最终frame的地方。比如一个Button的frame是(0,0,100,100),要把它从0,0移动到200,200,在这种情况下:

1.如果你使用的是显式动画(CAKeyframeAnimation和CABasicAnimation),是通过指定path或values来进行动画的,它的frame并没有改变,touch范围还是(0,0,100,100)这个范围内

2.如果你使用的是隐式动画(UIView的animate方法),是通过设置frame来进行动画的,那么它的touch范围就是(200,200,100,100)这个范围内

这个区别很重要,你只用记住,如果是用UIView做动画,设置的frame是有效的;

如果CALaye做动画设置的frame是无效的,你应该在动画结束后显式地指定position的值

动画的过程只是看起来是动态变换的,其内部的值已经是固定的了。

简单说下Core Animation,Core Animation用三个Tree来完成动画:

Layer Tree,图层树

Presentation Tree,表示数

Render Tree,渲染树

Layer Tree用来存储Layer最终的值,即不考虑动画的发生,你只要对一个Layer进行了一些诸如backgroundColor、position、alpha之类的赋值,其Layer Tree中存储的值立刻改变;Presentation Tree用来存储所有的要在动画过程中显示的值,与Layer Tree相反;Render Tree专门用来渲染Presentation Tree中的值,也是与Core Animation交互的唯一纽带,这一过程被系统隐藏了,我们不用管也没办法管。

这就是说Layer Tree与Presentation Tree其实都相当于是模型对象,只存储Layer的状态,当我们要读取动画进行中的状态的时候,调用layer的presentationLayer属性就可以了,这个属性从Presentation Tree中返回代表当前动画状态的Layer,接下来就是判断点击的点是否在 动画view.layer.presentationLayer 中了,  CGRectContainsPoint 或者 调用Layer的hitTest方法就能判断是不是一次有效点击了。

既然已经知道了原理, 那就试试. 我这里是重写了touchesBegan, 也可以添加手势到动画view的父视图上.

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) UIView *redView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    _redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.redView];
    self.redView.userInteractionEnabled = NO ;

}

- (IBAction)buttonAction:(id)sender {
    
    [UIView animateWithDuration:15 delay:0 options:UIViewAnimationOptionCurveEaseInOut  animations:^{
        
        self.redView.frame = CGRectMake(300, 500, 100, 100);
    } completion:^(BOOL finished) {
        self.redView.frame = CGRectMake(100, 100, 100, 100);

    }];

}

// 想做的动画
- (void)tapAction {
    NSLog(@"想要处理的动画过程中点击");

    self.redView.backgroundColor = [UIColor colorWithRed:(arc4random()%255)/ 255.f green:(arc4random()%255)/ 255.f blue:(arc4random()%255)/ 255.f alpha:1];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 获取到点击的位置
    UITouch * touch = touches.anyObject;
    CGPoint point = [touch locationInView:self.view];
    NSLog(@"point %@",NSStringFromCGPoint(point));
    NSLog(@"point %@",NSStringFromCGRect(self.redView.layer.presentationLayer.frame) );
    // 判断redView.layer.presentationLayer是否包含这个点
    // 方式1:CGRectContainsPoint
    if ( CGRectContainsPoint(self.redView.layer.presentationLayer.frame, point) ) {
        [self tapAction];
    }
    // 方式2:hitTest
//    if ([self.redView.layer.presentationLayer hitTest:point] != nil) {
//        [self tapAction];
//    }
    
    
}

@end


locationInView:与translationInView:的区别

translationInView : 手指在视图上移动的位置(x,y)向下和向右为正,向上和向左为负。

locationInView : 手指在视图上的位置(x,y)就是手指在视图本身坐标系的位置。

velocityInView: 手指在视图上移动的速度(x,y), 正负也是代表方向,值得一体的是在绝对值上|x| > |y| 水平移动, |y|>|x| 竖直移动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值