IOS 難理解的幾個屏幕接觸問題


1. 首先,

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

 和

pointInside:withEvent:

 函數是什么關系?

2. 具體到某個例子,UITableView是UIScrollView的子類,那么我們點擊一個UITableViewCell的時候,我們是准備上下移動table 還是說要select這個table呢?

3. 如果一個UIScrollView覆蓋住一個UIButton,那么我要調用點擊那個UIButton 怎么辦?

對於第一個問題,hitTest:函數就是判斷當前你的手指觸摸是不是在當前視圖中。如何判斷呢? 這里有一大堆話,我是從網上弄下來的,不愛看就直接看下面的圖

iOS系統檢測到手指觸摸(Touch)操作時會將其放入當前活動Application的事件隊列,UIApplication會從事件隊列中取出觸摸事件並傳遞給key window(當前接收用戶事件的窗口)處理,window對象首先會使用hitTest:withEvent:方法尋找此次Touch操作初始點所在的視圖(View),即需要將觸摸事件傳遞給其處理的視圖,稱之為hit-test view。

window對象會在首先在view hierarchy的頂級view上調用hitTest:withEvent:,此方法會在視圖層級結構中的每個視圖上調用pointInside:withEvent:,如果pointInside:withEvent:返回YES,則繼續逐級調用,直到找到touch操作發生的位置,這個視圖也就是hit-test view。

hitTest:withEvent:方法的處理流程如下:

首先調用當前視圖的pointInside:withEvent:方法判斷觸摸點是否在當前視圖內;
若返回NO,則hitTest:withEvent:返回nil;
若返回YES,則向當前視圖的所有子視圖(subviews)發送hitTest:withEvent:消息,所有子視圖的遍歷順序是從top到bottom,即從subviews數組的末尾向前遍歷,直到有子視圖返回非空對象或者全部子視圖遍歷完畢;
若第一次有子視圖返回非空對象,則hitTest:withEvent:方法返回此對象,處理結束;
如所有子視圖都返回非,則hitTest:withEvent:方法返回自身(self)。
hitTest:withEvent:方法忽略隱藏(hidden=YES)的視圖,禁止用戶操作(userInteractionEnabled=YES)的視圖,以及alpha級別小於0.01(alpha<0.01)的視圖。如果一個子視圖的區域超過父視圖的bound區域(父視圖的clipsToBounds 屬性為NO,這樣超過父視圖bound區域的子視圖內容也會顯示),那么正常情況下對子視圖在父視圖之外區域的觸摸操作不會被識別,因為父視圖的pointInside:withEvent:方法會返回NO,這樣就不會繼續向下遍歷子視圖了。當然,也可以重寫pointInside:withEvent:方法來處理這種情況。

對於每個觸摸操作都會有一個UITouch對象,UITouch對象用來表示一個觸摸操作,即一個手指在屏幕上按下、移動、離開的整個過程。UITouch對象在觸摸操作的過程中在不斷變化,所以在使用UITouch對象時,不能直接retain,而需要使用其他手段存儲UITouch的內部信息。UITouch對象有一個view屬性,表示此觸摸操作初始發生所在的視圖,即上面檢測到的hit-test view,此屬性在UITouch的生命周期不再改變,即使觸摸操作后續移動到其他視圖之上

 也就是這個意思:

+----------------------------+
|A                           |
|+--------+   +------------+ |
||B       |   |C           | |
||        |   |+----------+| |
|+--------+   ||D         || |
|             |+----------+| |
|             +------------+ |
+----------------------------+

 你的繼承圖表是這樣的,然后你的手指放在D視圖上,

那么 ,視圖A調用(繼承圖表最上面的)

hitTest:withEvent:

 然后每個視圖都會調用

pointInside:withEvent:

 A return YES;

B return NO;

C return YES;

D return NO;

凡是返回YES的視圖中,最下面的就是了 也就是D, hitTest 視圖。

然后對於第二個和第三個問題,

解決方式是這樣的,你在任何superView里面重載這個函數就可以了。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
  UIView *result = [super hitTest:point withEvent:event];
  CGPoint buttonPoint = [underButton convertPoint:point fromView:self];
  if ([underButton pointInside:buttonPoint withEvent:event]) {
    return underButton;
  }
  return result;
}

 不明白就看上面理論,碼子好累! :(


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM