iOS 彈幕開發(fā)過程碰到的問題總結(jié)

需求:實現(xiàn)一個彈幕容器胳赌,里面同時會有多行互不重疊的、運動中的彈幕 蜈首。每一條彈幕均需要支持點擊事件岗憋。

用腳底板想的方法:在彈幕容器里面創(chuàng)建幾個 UIButton肃晚,并且 addTarget,增加點擊事件仔戈。最后利用 UIView 的 block API 實現(xiàn)動畫关串。

結(jié)果:嗯...可惜的是,代碼運行起來杂穷,你會發(fā)現(xiàn)在 UIButton 運動過程悍缠,點擊事件并沒有響應(yīng),而且非常奇怪的是:為什么在 UIButton 動畫過程耐量,去點擊 UIButton 動畫的終點,點擊事件竟然響應(yīng)了滤港?廊蜒?這是為什么呢?

Core Anmation 動畫過程原理的引用:

在iOS中溅漾,屏幕每秒鐘重繪60次山叮。如果動畫時長比60分之一秒要長,Core Animation就需要在設(shè)置一次新值和新值生效之間添履,對屏幕上的圖層進行重新組織屁倔。這意味著CALayer除了“真實”值(就是你設(shè)置的值)之外,必須要知道當(dāng)前顯示在屏幕上的屬性值的記錄暮胧。

每個圖層屬性的顯示值都被存儲在一個叫做呈現(xiàn)圖層的獨立圖層當(dāng)中锐借,他可以通過-presentationLayer方法來訪問问麸。這個呈現(xiàn)圖層實際上是模型圖層的復(fù)制,但是它的屬性值代表了在任何指定時刻當(dāng)前外觀效果钞翔。換句話說严卖,你可以通過呈現(xiàn)圖層的值來獲取當(dāng)前屏幕上真正顯示出來的值。

補充:模型圖層在動畫開始的那一刻就已經(jīng)達到終點位置布轿,響應(yīng)點擊事件的也是它哮笆。

解決辦法:重寫彈幕容器 view 的 touchesBegan 方法。代碼如下:

@interface ZYYBarrageView ()

@property (nonatomic, strong) UIView *redView; // 將要做平移的 subview

@end

@implementation ZYYBarrageView

- (instancetype)initWithFrame:(CGRect)frame {

self = [super initWithFrame:frame];

if (self) {

[self commonInit];

}

return self;

}

- (void)commonInit {

self.redView = [[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, 30.f, 30.f)];

self.redView.backgroundColor = [UIColor redColor];

[self addSubview:self.redView];

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

// 重點開始Lぁ稠肘!UITouch 獲取在 barrageView 坐標(biāo)系下的坐標(biāo)

CGPoint touchPoint = [[touches anyObject] locationInView:self];

// 判斷觸摸點是否在 redView 的呈現(xiàn)樹的框框之中

if ([self.redView.layer.presentationLayer hitTest:touchPoint]) {

// 響應(yīng)紅色塊點擊

return;

} else {

}

}

進一步的需求:在 ZYYBarrageView 的同一層級,但層次偏后會有 UIButton。正常情況下萝毛,因為 ZYYBarrageView 的存在项阴,UIButton 是無法響應(yīng)點擊事件的。代碼如下:

@property (nonatomic, strong) ZYYBarrageView *barrageView; // 彈幕 view 支持多行 view 在里面進行運動

@property (nonatomic, strong) UIButton *yellowBtn; // 靠后的 UIButton

- (void)viewDidLoad {

[super viewDidLoad];

// self.yellowBtn 位于 self.barrageView 之后

[self.view addSubview:self.yellowBtn];

[self.view addSubview:self.barrageView];

}

- (ZYYBarrageView *)barrageView {

if (!_barrageView) {

_barrageView = [[ZYYBarrageView alloc] initWithFrame:CGRectMake(0.f, 30.f, SCREEN_WIDTH, 30.f)];

_barrageView.backgroundColor = [UIColor clearColor];

}

return _barrageView;

}

- (UIButton *)yellowBtn {

if (!_yellowBtn) {

_yellowBtn = [UIButton buttonWithType:UIButtonTypeCustom];

_yellowBtn.frame = CGRectMake(90.f, 30.f, 80.f, 30.f);

_yellowBtn.backgroundColor = [UIColor yellowColor];

[_yellowBtn setTitle:@"黃色按鈕" forState:UIControlStateNormal];

[_yellowBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

[_yellowBtn addTarget:self action:@selector(onYellowBtn:) forControlEvents:UIControlEventTouchUpInside];

}

return _yellowBtn;

}

- (void)onYellowBtn:(id)sender {

// 響應(yīng)黃色按鈕

}

怎么辦珊泳?

Responder Chain 原理講解:手指點擊屏幕鲁冯,經(jīng)過系統(tǒng)響應(yīng)(之前過程省略不說,文末有參考鏈接)色查,調(diào)用 UIApplication 的 sendEvent: 方法薯演,將 UIEvent 傳給 UIWindow, 通過遞歸調(diào)用 UIView 層級的 hitTest(_:with:)秧了,結(jié)合 point(inside:with:) 找到 UIEvent 中每一個UITouch 所屬的 UIView(其實是想找到離觸摸事件點最近的那個 UIView)跨扮。這個過程是從 UIView 層級的最頂層往最底層遞歸查詢。同一層級的 UIView验毡,會優(yōu)先深度遍歷界面靠前的 UIView衡创。找到最底層 UIView 后,沿著 Responder Chain 逐步向上傳遞(UIControl 子類默認會攔截傳遞)晶通。

解決思路:重寫 ZYYBarrageView 的 hitTest(_:with:) 方法璃氢。代碼如下:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

BOOL isPointInsideSubview = [self.redView.layer.presentationLayer hitTest:point];

if (isPointInsideSubview == NO) {

// 如果沒有點擊在移動的 redView 上,返回 nil

// 系統(tǒng)會去遍歷位于 ZYYBarrageView 后面的 UIButton狮辽,UIButton 能得到響應(yīng)

return nil;

} else {

return [super hitTest:point withEvent:event];

}

}

如此一也,可以完美解決啦~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市喉脖,隨后出現(xiàn)的幾起案子椰苟,更是在濱河造成了極大的恐慌,老刑警劉巖树叽,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舆蝴,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機洁仗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門层皱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人京痢,你說我怎么就攤上這事奶甘。” “怎么了祭椰?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵臭家,是天一觀的道長。 經(jīng)常有香客問我方淤,道長钉赁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任携茂,我火速辦了婚禮你踩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘讳苦。我一直安慰自己带膜,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布鸳谜。 她就那樣靜靜地躺著膝藕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咐扭。 梳的紋絲不亂的頭發(fā)上芭挽,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音蝗肪,去河邊找鬼袜爪。 笑死,一個胖子當(dāng)著我的面吹牛薛闪,可吹牛的內(nèi)容都是我干的辛馆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼豁延,長吁一口氣:“原來是場噩夢啊……” “哼怀各!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起术浪,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寿酌,沒想到半個月后胰苏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡醇疼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年硕并,在試婚紗的時候發(fā)現(xiàn)自己被綠了法焰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡倔毙,死狀恐怖埃仪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陕赃,我是刑警寧澤卵蛉,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站么库,受9級特大地震影響傻丝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诉儒,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一葡缰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忱反,春花似錦泛释、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至米者,卻和暖如春韭畸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔓搞。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工胰丁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喂分。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓锦庸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蒲祈。 傳聞我的和親對象是個殘疾皇子甘萧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容