iOS 事件鏈&響應(yīng)鏈 理解

平時(shí)開發(fā)中經(jīng)常會(huì)遇到子view超出父view時(shí),超出的部分不會(huì)響應(yīng)點(diǎn)擊事件
原因就在于:iOS的事件響應(yīng)機(jī)制
接下來(lái)簡(jiǎn)單了解一下事件的響應(yīng)鏈和傳遞鏈

響應(yīng)鏈流程

基本流程

大家都知道 iOS 的響應(yīng)鏈?zhǔn)?UIApplication 收到用戶觸摸屏幕的事件以后通過(guò)逐層尋找最后得到用戶觸摸的 View 也就是第一響應(yīng)者,然后調(diào)用 View 的 touchesBegan:withEvent: 方法處理事件任務(wù)的流程.大概流程是這樣的:

image.png

圖片很清晰的說(shuō)明了查找流程 AppDelegate 收到事件逐層查找.最終找到 UIButton 這個(gè)響應(yīng)者 然后調(diào)用 UIButton 的touchesBegan:withEvent: 方法處理事件.
可以總結(jié)為一下幾點(diǎn)
一個(gè)觸摸事件的響應(yīng)過(guò)程如下:

  • 用戶觸摸屏幕時(shí)瑰抵,UIKit會(huì)生成UIEvent對(duì)象來(lái)描述觸摸事件。對(duì)象內(nèi)部包含了觸摸點(diǎn)坐標(biāo)等信息谅河。
  • 通過(guò)Hit Test確定用戶觸摸的是哪一個(gè)UIView雄卷。這個(gè)步驟通過(guò)- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event方法來(lái)完成。
  • 找到被觸摸的UIView之后谴蔑,如果它能夠響應(yīng)用戶事件冕象,相應(yīng)的響應(yīng)函數(shù)就會(huì)被調(diào)用代承。如果不能響應(yīng),就會(huì)沿著響應(yīng)鏈(Responder Chain)尋找能夠響應(yīng)的UIResponder對(duì)象(UIView是UIResponder的子類)來(lái)響應(yīng)觸摸事件渐扮。

如何查找第一響應(yīng)者

查找第一響應(yīng)者主要涉及以下兩個(gè)方法

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;

系統(tǒng)會(huì)先執(zhí)行- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
如果不在響應(yīng)的point內(nèi)的話直接返回 false,接下來(lái)- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;會(huì)直接返回nil

pointInside:
通過(guò) point 參數(shù)確定觸碰點(diǎn)是否在當(dāng)前 View 的響應(yīng)范圍內(nèi) 是則返回YES 否則返回 NO 實(shí)現(xiàn)方法大概是這個(gè)樣子的

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    
    return CGRectContainsPoint(self.bounds, point);
}

hitTest方法:

  1. 它首先會(huì)通過(guò)調(diào)用自身的 pointInside 方法判斷用戶觸摸的點(diǎn)是否在當(dāng)前對(duì)象的響應(yīng)范圍內(nèi),如果 pointInside 方法返回 NO hitTest方法直接返回 nil
  2. 如果 pointInside 方法返回 YES hitTest方法接著會(huì)判斷自身是否有子視圖.如果有則調(diào)用頂層子視圖的 hitTest 方法 直到有子視圖返回 View
  3. 如果所有子視圖都返回 nil hitTest 方法返回自身.

尋找 hit-TestView 的過(guò)程的總結(jié)

通過(guò) hit-Testing 找到觸摸點(diǎn)所在的 View( hit-TestView )论悴。尋找過(guò)程總結(jié)如下(默認(rèn)情況下) :

  • 尋找順序如下
  1. 從視圖層級(jí)最底層的 window 開始遍歷它的子 View。
  2. 默認(rèn)的遍歷順序是按照 UIView 中 Subviews 的逆順序墓律。
  3. 找到 hit-TestView 之后膀估,尋找過(guò)程就結(jié)束了。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (self.hidden || !self.userInteractionEnabled || self.alpha < 0.01 || ![self pointInside:point withEvent:event] || ![self _isAnimatedUserInteractionEnabled]) {
        return nil;
    } else {
// 判斷觸摸位置是否在當(dāng)前視圖內(nèi)
    if ([self pointInside:point withEvent:event]) {
        NSArray<UIView *> * superViews = self.subviews;
        // 倒序 從最上面的一個(gè)視圖開始查找
        for (NSUInteger i = superViews.count; i > 0; i--) {
            UIView * subview = superViews[i - 1];
            // 轉(zhuǎn)換坐標(biāo)系 使坐標(biāo)基于子視圖
            CGPoint newPoint = [self convertPoint:point toView:subview];
            // 得到子視圖 hitTest 方法返回的值
            UIView * view = [subview hitTest:newPoint withEvent:event];
            // 如果子視圖返回一個(gè)view 就直接返回 不在繼續(xù)遍歷
            if (view) {
                return view;
            }
        }
        // 所有子視圖都沒(méi)有返回 則返回自身
        return self;
        //for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
//            UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:self] withEvent:event];
    //        if (hitView) {
        //        return hitView;
            //}
        } else {
          return nil;
      }
    }
}

根據(jù)以上源碼分析
確定一個(gè) View 是不是 hit-TestView 的過(guò)程如下:

  1. 如果 View 的 userInteractionEnabled = NO耻讽,enabled = NO( UIControl )察纯,或者 alpha <= 0.01, hidden = YES 直接返回 nil(不再往下判斷)。
  2. 如果觸摸點(diǎn)不在 view 中饼记,直接返回 nil香伴。
  3. 如果觸摸點(diǎn)在 view 中,逆序遍歷它的子 View 具则,重復(fù)上面的過(guò)程瞒窒,如果子View沒(méi)有subView了,那子View就是hit-TestView乡洼。
  4. 如果 view 的 子view 都返回 nil(都不是 hit-TestVeiw ),那么返回自身(自身是 hit-TestView )匕坯。

image.png

圖來(lái)自https://liangdahong.com/2018/06/08/2018/淺談-iOS-事件的傳遞和響應(yīng)過(guò)程/

看過(guò)這個(gè)束昵,我們也就懂了為什么超出屏幕不能響應(yīng)點(diǎn)擊事件-----如果超出邊界,UIKit無(wú)法根據(jù)這個(gè)觸摸點(diǎn)找到父視圖葛峻,自然也就無(wú)法找到子視圖锹雏。尋找過(guò)程有點(diǎn)像遞歸,可以理解理解术奖。

找到 hit-TestView 之后礁遵,事件就交給它來(lái)處理,hit-TestView 就是 firstResponder(第一響應(yīng)者)采记,如果它無(wú)法響應(yīng)事件(不處理事件)佣耐,則把事件交給它的 nextResponder(下一個(gè)響應(yīng)者)

第一響應(yīng)者在這幾個(gè)方法中處理響應(yīng)的事件,處理完成后根據(jù)需要調(diào)用 nextResponder 的 touch 方法,通常 nextResponder 就是第一響應(yīng)者的 superView 文章的第一張圖倒著看就是nextResponder 的順序

nextResponder 過(guò)程如下:

當(dāng)一個(gè)view被add到superView上的時(shí)候,他的nextResponder屬性就會(huì)被指向它的superView唧龄,當(dāng)controller被初始化的時(shí)候兼砖,self.view(topmost view)的nextResponder會(huì)被指向所在的controller,而controller的nextResponder會(huì)被指向self.view的superView既棺,這樣讽挟,整個(gè)app就通過(guò)nextResponder串成了一條鏈,也就是我們所說(shuō)的響應(yīng)鏈,他只是一條虛擬鏈丸冕,所以總結(jié)各個(gè)可響應(yīng)者的nextResponder如下:

  1. UIView 的 c 是直接管理它的 UIViewController (也就是 VC.view.nextResponder = VC )耽梅,如果當(dāng)前 View 不是 ViewController 直接管理的 View,則 nextResponder 是它的 superView( view.nextResponder = view.superView )胖烛。
  2. UIViewController 的 nextResponder 是它直接管理的 View 的 superView( VC.nextResponder = VC.view.superView )眼姐。
  3. UIWindow 的 nextResponder 是 UIApplication 。
  4. UIApplication 的 nextResponder 是 AppDelegate洪己。
    基于以上過(guò)程妥凳,那么上面尋找hit_testView例子的響應(yīng)者鏈就是viewB.1-viewB-mainView-UIWindow

有了響應(yīng)鏈,并且找到了第一個(gè)響應(yīng)事件的對(duì)象答捕,接下來(lái)就是把事件發(fā)送給這個(gè)響應(yīng)者了逝钥。 UIApplication中有個(gè)sendEvent:的方法,在UIWindow中同樣也可以發(fā)現(xiàn)一個(gè)同樣的方法。UIApplication是通過(guò)這個(gè)方法把事件發(fā)送給UIWindow艘款,然后UIWindow通過(guò)同樣的API持际,把事件發(fā)送給hit-testview。

接下來(lái)我們看一下事件的傳遞(傳遞鏈)

找到第一響應(yīng)者 application 便會(huì)根據(jù) event 調(diào)用第一響應(yīng)者響應(yīng)的
touch 方法:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);

當(dāng)我們點(diǎn)擊了Button之后哗咆,UIWindow會(huì)通過(guò)一個(gè)私有方法蜘欲,在里面會(huì)去調(diào)用按鈕的touchesBegan和touchesEnded方法,touchesBegan里面有設(shè)置按鈕的高亮等之類的動(dòng)作晌柬,這樣就實(shí)現(xiàn)了事件的傳遞姥份。而事件的響應(yīng),也就是按鈕上綁定的action年碘,是在touchEnded里面通過(guò)調(diào)用UIApplication的sendAction:to:from:forEvent:方法來(lái)實(shí)現(xiàn)的澈歉,至于這個(gè)方法里面是怎么去響應(yīng)action,就只能猜測(cè)了(可能是通過(guò)oc底層消息機(jī)制的相關(guān)接口
objc_msgSend
來(lái)發(fā)送消息實(shí)現(xiàn)的屿衅,可以參考message.h文件)埃难。如果第一響應(yīng)者沒(méi)有響應(yīng)這個(gè)事件,那么就會(huì)根據(jù)響應(yīng)鏈涤久,把事件冒泡傳遞給nextResponder來(lái)響應(yīng)涡尘。

注意這里是怎么把事件傳遞給nextResponder的呢?拿touch事件來(lái)說(shuō)响迂,UIResponder里面touch四個(gè)階段的方法里面考抄,實(shí)際上是什么事都沒(méi)有做的,UIView繼承了它進(jìn)行重寫蔗彤,重寫的內(nèi)容也是沒(méi)有什么東西座泳,就是把事件傳遞給nextResponder,UIView繼承于 UIResponder,而UIResponder只是重寫了touch 四個(gè)方法幕与,真正的實(shí)現(xiàn)在UIControl里挑势,可以看UIKit源碼
UIControl->UiView->UIResponder->NSObject這個(gè)繼承關(guān)系
UIResponder有touch的四個(gè)方法,而實(shí)現(xiàn)都在UIControl

UIResponder中touch方法實(shí)現(xiàn)如下啦鸣,默認(rèn)不做任何操作潮饱,只是沿著響應(yīng)鏈傳遞事件

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self nextResponder] touchesBegan:touches withEvent:event];
}

所以當(dāng)一個(gè)view或者controller里面沒(méi)有重寫touch事件,那么這個(gè)事件就會(huì)一直傳遞下去诫给,直到UIApplication香拉,這也就是事件往上冒泡的原理。如果view重寫了touch方法中狂,我們一般會(huì)看到的效果是凫碌,這個(gè)view響應(yīng)了事件之后,事件就被截?cái)嗔宋搁牛膎extResponder不會(huì)收到這個(gè)事件盛险,即使重寫了nextResponder的touch方法。這個(gè)時(shí)候如果想事件繼續(xù)傳遞下去,可以調(diào)用[super
touchesBegan:touches withEvent:event]苦掘,不建議直接調(diào)[self.nextResponder
touchesBegan:touches withEvent:event]换帜。
注意這里是怎么把事件傳遞給nextResponder的呢?拿touch事件來(lái)說(shuō)鹤啡,UIResponder里面touch四個(gè)階段的方法里面惯驼,實(shí)際上是什么事都沒(méi)有做的,UIView繼承了它進(jìn)行重寫递瑰,重寫的內(nèi)容也是沒(méi)有什么東西祟牲,就是把事件傳遞給nextResponder,UIView繼承于 UIResponder,而UIResponder只是重寫了touch 四個(gè)方法抖部,真正的實(shí)現(xiàn)在UIControl里疲眷,可以看UIKit源碼
UIControl->UiView->UIResponder->NSObject這個(gè)繼承關(guān)系
UIResponder有touch的四個(gè)方法,而實(shí)現(xiàn)都在UIControl

UIResponder中touch方法實(shí)現(xiàn)如下您朽,默認(rèn)不做任何操作,只是沿著響應(yīng)鏈傳遞事件

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self nextResponder] touchesBegan:touches withEvent:event];
}

剛才提到UIControl
在.h中能看到特別像touch四個(gè)方法的四個(gè)方法Tracking系列

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)cancelTrackingWithEvent:(UIEvent *)event;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    _touchInside = YES;
    _tracking = [self beginTrackingWithTouch:touch withEvent:event];

    self.highlighted = YES;

    if (_tracking) {
        UIControlEvents currentEvents = UIControlEventTouchDown;

        if (touch.tapCount > 1) {
            currentEvents |= UIControlEventTouchDownRepeat;
        }

        [self _sendActionsForControlEvents:currentEvents withEvent:event];
    }
}

根據(jù)上面的源碼看到 touch內(nèi)部調(diào)用了Tracking一系列的 touch 方法
如果你點(diǎn)擊UIButton的響應(yīng)事件的話换淆,打個(gè)斷點(diǎn)哗总,看到方法調(diào)用


image.png

就直接是UIApplication 調(diào)用sendAction方法,相當(dāng)于直接到鏈頭了吧

首先劃重點(diǎn):所有響應(yīng)者的基類都是 UIResponder倍试,UIApplication/UIView/UIViewController 都是 UIResponder 的子類

尋找響應(yīng)者過(guò)程如下:

當(dāng)我們知道最合適的 View 后讯屈,事件會(huì) 由上向下【子view -> 父view,控制器view -> 控制器】來(lái)找出合適響應(yīng)事件的 View县习,來(lái)響應(yīng)相關(guān)的事件涮母。那怎么就是真正的響應(yīng)者呢?

  1. 如果當(dāng)前的 View 有添加手勢(shì)躁愿,那么直接響應(yīng)相應(yīng)的事件叛本,不會(huì)繼續(xù)向下尋找了,因?yàn)槭謩?shì)比響應(yīng)鏈擁有更高的優(yōu)先級(jí)

  2. 如果沒(méi)有手勢(shì)事件彤钟,那么會(huì)看其是否實(shí)現(xiàn)了如下的方法:

(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

經(jīng)過(guò)驗(yàn)證一二步是并行的来候,甚至touchBegin響應(yīng)更早一丟丟,所以只要有以上兩個(gè)之一實(shí)現(xiàn)逸雹,都會(huì)阻斷響應(yīng)鏈傳遞

舉例

image.png

藍(lán)色圓加在紅色方塊上营搅,重疊部分如果想響應(yīng)紅色塊的點(diǎn)擊事件,應(yīng)該怎么辦呢

  • 重寫藍(lán)色圓的hiteTest
//self.btn為紅色塊
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    //藍(lán)色的點(diǎn)轉(zhuǎn)換給紅色
    CGPoint redBtnPoint = [self convertPoint:point toView:self.btn];
    if([self.btn pointInside:redBtnPoint withEvent:event]) {
        return _btn;
    }
    return view;
}

事件攔截

通常第一響應(yīng)者都是響應(yīng)鏈中最末端的響應(yīng)者,事件攔截就是在響應(yīng)鏈中截獲事件,停止下發(fā).將事件交由中間的某個(gè)響應(yīng)者執(zhí)行.比如這樣:


image.png

通常點(diǎn)擊紅色 view 事件將交由 紅色 view 處理.如果想讓粉色 View 或者綠色 view 處理事件應(yīng)該怎么辦?
有兩種辦法

  1. 在紅色 view 的的 touch 方法中調(diào)用父類或者 nextResponder 的
    touch 方法
  2. 在需要攔截的 view 中重寫 hitTest 方法改變第一響應(yīng)者

首先來(lái)看第一種

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 將事件傳遞給下一響應(yīng)者
    [self.nextResponder touchesBegan:touches withEvent:event];
    // 調(diào)用父類的touch方法 和上面的方法效果一樣 這兩句只需要其中一句
    [super touchesBegan:touches withEvent:event];  
}

這種方法有兩個(gè)問(wèn)題,你需要重寫所有的 touch 方法并且還要重寫要攔截事件的 view 與頂級(jí) view 之間的所有 view 的 touch 方法

第二種方法
重寫攔截事件的 view 的 hitTest 方法 比如要讓綠色的 view 處理事件 就重寫綠色 view 的 hitTest 方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    // 如果在當(dāng)前 view 中 直接返回 self 這樣自身就成為了第一響應(yīng)者 subViews 不再能夠接受到響應(yīng)事件
    if ([self pointInside:point withEvent:event]) {
        return self;
    }
    return nil;
}

這種方法比較簡(jiǎn)單粗暴.實(shí)現(xiàn)后 所有 subview 將不再能夠接受任何事件 具體使用那種方式看需求.當(dāng)然還可以通過(guò) event 或者 point 有針對(duì)性的攔截

事件轉(zhuǎn)發(fā)

有時(shí)候還需要將事件轉(zhuǎn)發(fā)出去.讓本來(lái)不能響應(yīng)事件的 view 響應(yīng)事件,最常用的場(chǎng)景就是讓子視圖超出父視圖的部分也能響應(yīng)事件,比如要實(shí)現(xiàn)這樣的 tabbar


image.png

橙色按鈕有兩個(gè)區(qū)域 a 區(qū)超出父視圖 b 區(qū)沒(méi)有超出父視圖,如果不作處理,那么點(diǎn)擊 a 區(qū)是無(wú)法響應(yīng)事件的,因?yàn)?a 區(qū)域的坐標(biāo)不在父視圖的范圍內(nèi),當(dāng)執(zhí)行到父視圖的 pointInside 的時(shí)候就會(huì)返回 NO
想要讓 a 區(qū)響應(yīng)事件 就需要重寫父視圖的 pointInside 或 hitTest 方法讓 pointInside 返回 YES 或 讓hitTest 直接返回橙色視圖
重寫hitTest

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    
    // 觸摸點(diǎn)在視圖范圍內(nèi) 則交由父類處理
    if ([self pointInside:point withEvent:event]) {
        return [super hitTest:point withEvent:event];
    }
    
    // 如果觸摸點(diǎn)不在范圍內(nèi) 而在子視圖范圍內(nèi)依舊返回子視圖
    NSArray<UIView *> * superViews = self.subviews;
    // 倒序 從最上面的一個(gè)視圖開始查找
    for (NSUInteger i = superViews.count; i > 0; i--) {
        UIView * subview = superViews[i - 1];
        // 轉(zhuǎn)換坐標(biāo)系 使坐標(biāo)基于子視圖
        CGPoint newPoint = [self convertPoint:point toView:subview];
        // 得到子視圖 hitTest 方法返回的值
        UIView * view = [subview hitTest:newPoint withEvent:event];
        // 如果子視圖返回一個(gè)view 就直接返回 不在繼續(xù)遍歷
        if (view) {
            return view;
        }
    }
    return nil;
}

重寫 pointInside 方法原理相同 重點(diǎn)注意轉(zhuǎn)換坐標(biāo)系 就算他們不是一條響應(yīng)鏈上 也可以通過(guò)重寫 hitTest 方法轉(zhuǎn)發(fā)事件.原理相同的東西就不再寫了

參考地址http://www.reibang.com/p/db3518be5ebb
https://blog.csdn.net/qiangshuting/article/details/90317936

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梆砸,一起剝皮案震驚了整個(gè)濱河市转质,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帖世,老刑警劉巖休蟹,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鸡挠,警方通過(guò)查閱死者的電腦和手機(jī)辉饱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拣展,“玉大人彭沼,你說(shuō)我怎么就攤上這事”赴#” “怎么了姓惑?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)按脚。 經(jīng)常有香客問(wèn)我于毙,道長(zhǎng),這世上最難降的妖魔是什么辅搬? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任唯沮,我火速辦了婚禮,結(jié)果婚禮上堪遂,老公的妹妹穿的比我還像新娘介蛉。我一直安慰自己,他們只是感情好溶褪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布币旧。 她就那樣靜靜地躺著,像睡著了一般猿妈。 火紅的嫁衣襯著肌膚如雪吹菱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天彭则,我揣著相機(jī)與錄音鳍刷,去河邊找鬼。 笑死俯抖,一個(gè)胖子當(dāng)著我的面吹牛倾剿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚌成,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼前痘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了担忧?” 一聲冷哼從身側(cè)響起芹缔,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瓶盛,沒(méi)想到半個(gè)月后最欠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體示罗,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年芝硬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚜点。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拌阴,死狀恐怖绍绘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迟赃,我是刑警寧澤陪拘,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站纤壁,受9級(jí)特大地震影響左刽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酌媒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一欠痴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秒咨,春花似錦喇辽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疫诽。三九已至舅世,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奇徒,已是汗流浹背雏亚。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摩钙,地道東北人罢低。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像胖笛,于是被迫代替她去往敵國(guó)和親网持。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • 重點(diǎn)參考鏈接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi閱讀 4,397評(píng)論 0 15
  • 本文主要講解iOS觸摸事件的一系列機(jī)制长踊,涉及的問(wèn)題大致包括: 觸摸事件由觸屏生成后如何傳遞到當(dāng)前應(yīng)用功舀? 應(yīng)用接收觸...
    baihualinxin閱讀 1,193評(píng)論 0 9
  • 在iOS開發(fā)中經(jīng)常會(huì)涉及到觸摸事件。本想自己總結(jié)一下身弊,但是遇到了這篇文章辟汰,感覺(jué)總結(jié)的已經(jīng)很到位列敲,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 5,988評(píng)論 4 26
  • 本文將簡(jiǎn)單介紹 iOS 的點(diǎn)擊事件( TouchEvents )分發(fā)機(jī)制和一些使用場(chǎng)景帖汞。詳解請(qǐng)看參考部分戴而。 從以下...
    記憶阿閱讀 5,419評(píng)論 2 18
  • 生活,只有當(dāng)下的時(shí)刻翩蘸。如果我們?cè)诋?dāng)下做了正確的事情所意,我們就是在朝著進(jìn)步的方向邁進(jìn)。相反鹿鳖,如果我們的行為不是符合...
    selfconfid_a068閱讀 767評(píng)論 0 0