怎樣選擇最合適處理事件的控件
當(dāng)用戶點(diǎn)擊屏幕后,產(chǎn)生2個(gè)參數(shù) 一個(gè)
touches保存用戶點(diǎn)擊的UITouch對(duì)象到NSSet中,和一個(gè)事件對(duì)象UIEvent,并且加入到UIApplication對(duì)象的事件處理Loop中隊(duì)列由UIApplication查看,當(dāng)前有沒有堵塞,如果沒有就將事件分發(fā)下去,一般是交給主窗口,keyWindow
然后Window 會(huì)用 下面的這個(gè)方法
//Swift
func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?
//Objective-C
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- 該方法是用于查詢當(dāng)前最佳處理事件的控件,如果我們重寫
window的這個(gè)方法后,其他view的觸摸事件沒受影響,那么說(shuō)明我們的思路是對(duì)的,廢話不多說(shuō),代碼帶注釋
Swift
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
/*1.判斷自己可不可以與用戶交互滿足一下幾點(diǎn)
1.self.userInteractionEnabled = YES 可以與用戶交互
2.self.hidden = NO 不是隱藏的
3.self.alpha > 0.01 透明度大于 0.01 也就是用戶可見
*/
//下面是寫的上面的反面
if self.userInteractionEnabled == false || self.hidden == true || self.alpha <= 0.01 {
return nil
}
/*2.這里查看這個(gè)點(diǎn)是不是在控件的bound上了,如果不在就返回nil */
if self.pointInside(point, withEvent: event) == false { return nil }
/*3.遍歷 子控件,由于addSubView 本身是把圖層加到另
一個(gè)圖層上面,導(dǎo)致圖層的順序是最后添加的在最上面,也就是
上面說(shuō)的,后面加入的控件可能會(huì)在蓋住,前面加入的控件圖
層,而響應(yīng)鏈?zhǔn)莾?yōu)先最上面的圖層的,考慮到這個(gè)遞歸算法是
DFS 也就是深度優(yōu)先,所以必須從后面的子控件遍歷
*/
//3.1得到子控制總個(gè)數(shù)
let count = Int(self.subviews.count) - 1
for var i = count ; i >= 0 ; --i {
//1.得到子控件
let childView:UIView = self.subviews[i]
/*2,將父控件的坐標(biāo)點(diǎn)轉(zhuǎn)換到子控件中的形式,其實(shí)就拿
子控件在父控件的frame的x,y ,與用戶觸點(diǎn)的父控件的
x,y,進(jìn)行減法*/
let childPoint = self.convertPoint(point, toView: childView)
//3.繼續(xù)遞歸
let firstView = childView.hitTest(childPoint, withEvent: event)
//4.發(fā)現(xiàn)不為空,就回傳
if let notEmpty = firstView {
return notEmpty
}
}
//5.如果沒知道合適的處理事件控件,就返回自己
return self
}
- 上面說(shuō)的自己寫
self.convertPoint(point, toView: childView)這方法,其實(shí)就是下面的算法
func myConvertPoint(point:CGPoint, toView view:UIView) -> CGPoint {
//1.拿到子控件的x,y
let x = view.frame.origin.x
let y = view.frame.origin.y
//2.進(jìn)行減法,并且返回
return CGPointMake(point.x - x, point.y - y)
}
Objective-C
- 這里我的另一種思路,但是不提倡
/*只要進(jìn)入了這個(gè)方法,那就代表了這個(gè)視圖,是可以與用戶交互,包含那個(gè)點(diǎn)的。
但是站在面向?qū)ο蟮慕嵌?,思考?wèn)題,”誰(shuí)最清楚,控件能否被點(diǎn)擊,
點(diǎn)在不在自己身上,當(dāng)然是自己",所以不提倡這樣的寫法*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
int count = (int)self.subviews.count;
for( int i = count - 1 ; i >= 0 ; --i ) {
//1.拿到子控件
UIView * childView = self.subviews[i];
//2.轉(zhuǎn)換坐標(biāo)點(diǎn)
CGPoint childPoint = [self convertPoint:point toView:childView];
//3.判斷子控件能不能與用戶交互
BOOL flagEnable = childView.userInteractionEnabled == YES || childView.hidden == NO || childView.alpha > 0.01;
//4.判斷點(diǎn)在不在子控件上
BOOL flagInside = [childView pointInside:childPoint withEvent:event];
//5.如果都可以,那么繼續(xù)遞歸
if (flagInside && flagEnable) {
UIView *firstView = [childView hitTest:childPoint withEvent:event];
//6.如果有,就回傳
if (firstView) {
return firstView;
}
}
}
//7.沒找到最合適的就返回自己
return self;
}