以下所有內(nèi)容均為個人觀點睡扬,轉(zhuǎn)載請注明出處<簡書--小蝸牛吱呀之悠悠 >,謝謝黍析!
最近項目中需要實現(xiàn)一個視圖從右向左滑動卖怜,動畫播放過程子視圖需要能響應(yīng)點擊事件,效果和彈幕滾動過程支持點擊類似阐枣。
1马靠、首先想到的方案是在UIView視圖上放一個按鈕,然后使用animation動畫播放
[UIView animateWithDuration:15 animations:^{
self.colorView.transform = CGAffineTransformMakeTranslation(-700, 0);
} completion:^(BOOL finished) {
}];
運行后發(fā)現(xiàn)侮繁,動畫播放過程中虑粥,點擊上面的按鈕,點擊事件不響應(yīng)宪哩。why!!
2旦事、從動畫過程看,會不會是animation動畫播放過程涕癣,系統(tǒng)自動將視圖的用戶交互給關(guān)掉了呢仿贬?于是帶著這個疑問去查看animation動畫的頭文件,發(fā)現(xiàn)果然有這么一個枚舉UIViewAnimationOptionAllowUserInteraction存在品抽,于是趕緊將動畫修改成下面的樣子:
[UIView animateWithDuration:15 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
self.colorView.transform = CGAffineTransformMakeTranslation(-700, 0);
} completion:^(BOOL finished) {
}];
很可惜储笑,運行后發(fā)現(xiàn)并沒有效果,這是什么原因呢圆恤?經(jīng)過一番研究后發(fā)現(xiàn)突倍,在animation動畫播放過程中,對視圖的坐標(biāo)設(shè)定是立即生效的(即使你看上去視圖是從右往左移動的)盆昙,也就是說此時這個視圖已經(jīng)處于CGAffineTransformMakeTranslation(-700, 0)所在的位置羽历,所以此時你的點擊操作并沒有被這個在滑動的視圖捕獲。既然沒有被捕獲到淡喜,那這個手勢被誰獲取到了呢秕磷?父視圖。
3炼团、既然手勢被父視圖獲取到了澎嚣,那么意味著我們可以獲取到此時手指點擊的坐標(biāo)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// 獲取到點擊的位置
UITouch * touch = touches.anyObject;
CGPoint point = [touch locationInView:self.view];
}
由于animation動畫播放過程,實際上移動的是layer層瘟芝,那么我們考慮是不是可以獲取到這個移動的layer呢易桃,然后通過比較layer的frame與point的位置關(guān)系來判斷這個手勢是否需要響應(yīng)。那么怎么獲取這個layer呢锌俱,我們的layer有這么一個屬性presentationLayer颈抚,這個屬性獲取到的就是當(dāng)前正在播放動畫的layer,于是touchesBegan方法修改如下
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// 獲取到點擊的位置
UITouch * touch = touches.anyObject;
CGPoint point = [touch locationInView:self.view];
CGRect frame1 = self.tapView.layer.presentationLayer.frame;
CGRect frame2 = self.colorView.layer.presentationLayer.frame;
frame1.origin.x += frame2.origin.x;
frame1.origin.y += frame2.origin.y;
if ( CGRectContainsPoint(frame1, point) ) {
NSLog(@"contain");
}
// 方式2:hitT
}
由于tapView是colorView的子視圖,所以frame1的坐標(biāo)是相對于colorView的坐標(biāo)贩汉,但我們的point卻是相對于self.view的驱富,所以此時需要將坐標(biāo)轉(zhuǎn)換一下。修改完成后運行匹舞,效果正是我們想要的褐鸥。
4、通過demo驗證效果后就將效果放到自己的項目上去赐稽,可最后發(fā)現(xiàn)還是不行叫榕,這是為什么呢?于是考慮是不是我這個手勢被別的視圖捕獲了姊舵,沒有傳遞到self.view上面呢晰绎?查看圖層結(jié)構(gòu)后發(fā)現(xiàn),確實如此括丁,我們的點擊手勢被tableview給捕獲了荞下。到這里,我們穿插一下基本的事件傳遞過程史飞,我們的圖層結(jié)構(gòu)如下圖
從圖上我們可以看到尖昏,tableview與滾動視圖是同層級的關(guān)系,tableView是self.view的子視圖构资。那么當(dāng)我們點擊事件發(fā)生時抽诉,根據(jù)事件的傳遞規(guī)律,從self.view開始遍歷子視圖吐绵,前面提到迹淌,滑動視圖此時已經(jīng)不在手勢點擊的位置,所以它無法響應(yīng)事件己单,那么事件就被tableview捕獲了唉窃。
那么好了,原因就出在這里荷鼠,事件被tableview捕獲了,self.view的touchesBegan方法就不響應(yīng)榔幸。那么如何才能讓self.view獲得事件呢允乐?將tableview的userInterface關(guān)了,運行后發(fā)現(xiàn)是OK的削咆。但是牍疏,tableview需要響應(yīng)自己的事件,userInterface關(guān)了以后無法再響應(yīng)了拨齐。因此鳞陨,這個方式不可行。
5、考慮到touchesBegan是UIView的方法厦滤,那么可以為滑動視圖增加一個父視圖援岩,touchesBegan的處理交給這個父視圖來做。
注:關(guān)鍵幀動畫也同樣可以用此方法解決
demo地址鏈接