詳解iOS觸摸事件與手勢(shì)識(shí)別

本文主要想講的是觸摸事件和手勢(shì)混合使用的一個(gè)問(wèn)題畜号,但作為知識(shí)儲(chǔ)備帚呼,還是把兩者再單獨(dú)介紹一下质涛。兩者的基本知識(shí)點(diǎn)都是iOS開(kāi)發(fā)文檔或者參考其他博客的,算是一個(gè)總結(jié)箱蝠,文章最后會(huì)標(biāo)出參考鏈接续捂。

iOS的事件有Touch EventsMotion Events宦搬、Remote Events牙瓢,最常見(jiàn)的是觸摸事件Touch Events。觸摸事件除了是view來(lái)處理间校,還有高級(jí)的手勢(shì)可以處理矾克。所以,本文分別來(lái)講講觸摸事件和手勢(shì)憔足,并結(jié)合例子講講兩者混合使用的問(wèn)題胁附。

由于本文講的東西有點(diǎn)繁雜,特在此列一個(gè)目錄四瘫,方便大家有一個(gè)清晰的第一印象汉嗽。

  • UITouch對(duì)象
  • UIEvent對(duì)象
  • 響應(yīng)鏈
  • Hit-Testing
  • 手勢(shì)識(shí)別
  • 手勢(shì)識(shí)別與事件響應(yīng)混用

UITouch對(duì)象

一個(gè)手指第一次點(diǎn)擊屏幕,就會(huì)生成一個(gè)UITouch對(duì)象找蜜,到手指離開(kāi)時(shí)銷毀。當(dāng)我們有多個(gè)手指觸摸屏幕時(shí)稳析,會(huì)生成多個(gè)UITouch對(duì)象洗做。UITouch對(duì)象可以表明觸摸的位置、狀態(tài)彰居,其狀態(tài)的類型有:

typedef NS_ENUM(NSInteger, UITouchPhase) {
    UITouchPhaseBegan,             // whenever a finger touches the surface.
    UITouchPhaseMoved,             // whenever a finger moves on the surface.
    UITouchPhaseStationary,        // whenever a finger is touching the surface but hasn't moved since the previous event.
    UITouchPhaseEnded,             // whenever a finger leaves the surface.
    UITouchPhaseCancelled,         // whenever a touch doesn't end but we need to stop tracking (e.g. putting device to face)
};

UIEvent對(duì)象

一個(gè)UIEvent對(duì)象代表iOS的一個(gè)事件诚纸。一個(gè)觸摸事件定義為第一個(gè)手指開(kāi)始觸摸屏幕到最后一個(gè)手指離開(kāi)屏幕。所以陈惰,一個(gè)UIEvent對(duì)象實(shí)際上對(duì)應(yīng)多個(gè)UITouch對(duì)象畦徘。

響應(yīng)鏈

響應(yīng)鏈可以理解為一種虛擬的鏈表,每一個(gè)節(jié)點(diǎn)是一個(gè)UIResponder對(duì)象抬闯。UIResponder是事件接收與處理的基類井辆,UIApplicationUIViewControllerUIView都繼承自UIResponder溶握。UIResponder提供了幾個(gè)事件處理的方法:

- (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;

UIResponder對(duì)象之間的聯(lián)系靠nextResponder指針杯缺。

#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly, nullable) UIResponder *nextResponder;
#else
- (nullable UIResponder*)nextResponder;
#endif

一個(gè)觸摸事件到達(dá)真正處理它的對(duì)象時(shí)經(jīng)過(guò)了一個(gè)搜索路徑,這就是響應(yīng)鏈的一部分睡榆。事件沿著這個(gè)響應(yīng)鏈一直傳遞萍肆,直到碰到可以處理這個(gè)事件的UIResponder對(duì)象或者到達(dá)響應(yīng)鏈的末尾(UIApplication)袍榆。

響應(yīng)鏈的構(gòu)造規(guī)則如下:

  1. 程序啟動(dòng)時(shí),UIApplication會(huì)生成一個(gè)單例塘揣,并會(huì)關(guān)聯(lián)一個(gè)APPDelegate包雀。APPDelegate作為整個(gè)響應(yīng)鏈的根建立起來(lái),UIApplication的nextResponser為APPDelegate亲铡。
  1. 程序啟動(dòng)后馏艾,任何的UIWindow被創(chuàng)建時(shí),UIWindow內(nèi)部都會(huì)把nextResponser設(shè)置為UIApplication單例奴愉。
  2. UIWindow初始化rootViewController, rootViewController的nextResponser會(huì)設(shè)置為UIWindow琅摩。
  3. UIViewController初始化View,View的nextResponser會(huì)設(shè)置為rootViewController锭硼。
  4. AddSubView時(shí)房资,如果subView不是ViewController的View,那么subView的nextResponser會(huì)被設(shè)置為superView。否則就是 subView -> subView.VC ->superView檀头。
responder_chain

有了這個(gè)響應(yīng)鏈轰异,事件就可以按照這個(gè)路徑逐級(jí)傳遞了。當(dāng)前的對(duì)象不能處理這個(gè)事件暑始,就交給nextResponser搭独,一直到UIApplication單例。如果仍然不能處理廊镜,就丟棄牙肝。

實(shí)際應(yīng)用中,一個(gè)事件都是由一個(gè)響應(yīng)對(duì)象來(lái)處理嗤朴,不會(huì)繼續(xù)向下傳遞配椭,不過(guò)有了上面的知識(shí),我們是可以手動(dòng)傳遞的雹姊,做我們想做的事情股缸。

Hit-Testing

當(dāng)我們觸摸屏幕時(shí),到底應(yīng)該由哪個(gè)對(duì)象最先響應(yīng)這個(gè)事件呢吱雏?這就需要去探測(cè)敦姻,這個(gè)過(guò)程稱為Hit-Testing,最后的結(jié)果稱為hit-test view歧杏。涉及到兩個(gè)方法是:

//先判斷點(diǎn)是否在View內(nèi)部镰惦,然后遍歷subViews
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 
//判斷點(diǎn)是否在這個(gè)View內(nèi)部
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

Hit-Testing是一個(gè)遞歸的過(guò)程,每一步監(jiān)測(cè)觸摸位置是否在當(dāng)前view中得滤,如果是陨献,就遞歸監(jiān)測(cè)subviews;否則懂更,返回nil眨业。
遞歸的根節(jié)點(diǎn)是UIWindow急膀,對(duì)subviews的遍歷順序按照 后添加的先遍歷 原則。大致過(guò)程的代碼如下:

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event {
    //判斷是否合格
    if (!self.hidden && self.alpha > 0.01 && self.isUserInteractionEnabled) {
        //判斷點(diǎn)擊位置是否在自己區(qū)域內(nèi)
        if ([self pointInside: point withEvent:event]) {
            UIView *attachedView;
            for (int i = self.subviews.count - 1; i >= 0; i--) {
                UIView *view  = self.subviews[i];
                //對(duì)子view進(jìn)行hitTest
                attachedView =  [view hitTest:point withEvent:event];
                if (attachedView)
                    break;
            }
            if (attachedView)  {
                return attachedView;
            } else {
                return self;
            }
        }
    }
    return nil;
}

來(lái)看最經(jīng)典的示例圖:

hit_testing.png

當(dāng)點(diǎn)擊E時(shí)龄捡,探測(cè)的步驟是:

1 觸摸點(diǎn)在A的范圍內(nèi)卓嫂,所以繼續(xù)探測(cè)A的subView,既view B和view C聘殖。
2 觸摸點(diǎn)不在view B里晨雳,在view C里,所以繼續(xù)探測(cè)C的subView D 和 E奸腺。
3 觸摸點(diǎn)不在D里餐禁,在E里,E已經(jīng)是最低級(jí)的View突照,故返回E帮非。

綜上,我們可以看出有兩個(gè)幾乎相反的鏈讹蘑,一是響應(yīng)鏈末盔,一是探測(cè)鏈。 有觸摸事件時(shí)座慰,先依賴探測(cè)鏈來(lái)確定響應(yīng)鏈的開(kāi)始節(jié)點(diǎn)(UIResponder對(duì)象)陨舱,然后依賴響應(yīng)鏈來(lái)確定最終處理事件的對(duì)象。

手勢(shì)識(shí)別

手勢(shì)是Apple提供的更高級(jí)的事件處理技術(shù)版仔,可以完成更多更復(fù)雜的觸摸事件游盲,比如旋轉(zhuǎn)、滑動(dòng)邦尊、長(zhǎng)按等背桐。基類是UIGestureRecognizer蝉揍,派生的類有:

Gesture UIKit Class
Tapping (any number of taps) UITapGestureRecognizer
Pinching in and out (for zooming a view) UIPinchGestureRecognizer
Panning or dragging UIPanGestureRecognizer
Swiping (in any direction) UISwipeGestureRecognizer
Rotating (fingers moving in opposite directions) UIRotationGestureRecognizer
Long press (also known as “touch and hold”) UILongPressGestureRecognizer

手勢(shì)綁定到一個(gè)View上,一個(gè)View上可以綁定多個(gè)手勢(shì)畦娄。
UIGestureRecognizerUIResponder一樣也有四個(gè)方法

//UIGestureRecognizer
- (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;

手勢(shì)會(huì)在以上四個(gè)方法中去對(duì)手勢(shì)的State做更改又沾,手勢(shì)的State表明當(dāng)前手勢(shì)是識(shí)別還是失敗等等。比如單擊手勢(shì)會(huì)在touchesBegan 時(shí)記錄點(diǎn)擊位置熙卡,然后在touchesEnded判斷點(diǎn)擊次數(shù)杖刷、時(shí)間、是否移動(dòng)過(guò)驳癌,最后得出否識(shí)別該手勢(shì)滑燃。這幾個(gè)方法一般在自定義手勢(shì)里面使用。
手勢(shì)的State有:

typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
    UIGestureRecognizerStatePossible,   // the recognizer has not yet recognized its gesture, but may be evaluating touch events. this is the default state
    UIGestureRecognizerStateBegan,      // the recognizer has received touches recognized as the gesture. the action method will be called at the next turn of the run loop
    UIGestureRecognizerStateChanged,    // the recognizer has received touches recognized as a change to the gesture. the action method will be called at the next turn of the run loop
    UIGestureRecognizerStateEnded,      // the recognizer has received touches recognized as the end of the gesture. the action method will be called at the next turn of the run loop and the recognizer will be reset to UIGestureRecognizerStatePossible
    UIGestureRecognizerStateCancelled,  // the recognizer has received touches resulting in the cancellation of the gesture. the action method will be called at the next turn of the run loop. the recognizer will be reset to UIGestureRecognizerStatePossible
    UIGestureRecognizerStateFailed,     // the recognizer has received a touch sequence that can not be recognized as the gesture. the action method will not be called and the recognizer will be reset to UIGestureRecognizerStatePossible
// Discrete Gestures – gesture recognizers that recognize a discrete event but do not report changes (for example, a tap) do not transition through the Began and Changed states and can not fail or be cancelled
    UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // the recognizer has received touches recognized as the gesture. the action method will be called at the next turn of the run loop and the recognizer will be reset to UIGestureRecognizerStatePossible
};

手勢(shì)在這些狀態(tài)之間變化颓鲜,形成了一個(gè)有限狀態(tài)機(jī):

gesture_state_transitions.png

左側(cè)是非連續(xù)手勢(shì)(比如單擊)的狀態(tài)機(jī)表窘,右側(cè)是連續(xù)手勢(shì)(比如滑動(dòng))的狀態(tài)機(jī)典予。所有的手勢(shì)的開(kāi)始狀態(tài)都是UIGestureRecognizerStatePossible
非連續(xù)的手勢(shì)要么識(shí)別成功(UIGestureRecognizerStateRecognized)乐严,要么識(shí)別失敗(UIGestureRecognizerStateFailed)瘤袖。
連續(xù)的手勢(shì)識(shí)別到第一個(gè)手勢(shì)時(shí),變成UIGestureRecognizerStateBegan昂验,然后變成UIGestureRecognizerStateChanged捂敌,并且不斷地在這個(gè)狀態(tài)下循環(huán),當(dāng)用戶最后一個(gè)手指離開(kāi)view時(shí)既琴,變成UIGestureRecognizerStateEnded占婉,當(dāng)然如果手勢(shì)不再符合它的模式的時(shí)候,狀態(tài)也可能變成UIGestureRecognizerStateCancelled甫恩。

手勢(shì)識(shí)別與事件響應(yīng)混用

重點(diǎn)來(lái)了逆济!前面我們知道觸摸事件可以通過(guò)響應(yīng)鏈來(lái)傳遞與處理,也可以被綁定在view上的手勢(shì)識(shí)別和處理填物。那么這兩個(gè)一起用會(huì)出現(xiàn)什么問(wèn)題纹腌?我們來(lái)看一個(gè)簡(jiǎn)單的例子。

example

圖中baseView 有兩個(gè)subView滞磺,分別是testView和testBtn升薯。我們?cè)赽aseView和testView都重載touchsBegan:withEventtouchsEnded:withEvent击困、
touchsMoved:withEvent涎劈、touchsCancelled:withEvent方法,并且在baseView上添加單擊手勢(shì)阅茶,action名為tapAction蛛枚,給testBtn綁定action名為testBtnClicked
主要代碼如下:

//baseView
- (void)viewDidLoad {
    [super viewDidLoad];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
    [self.view addGestureRecognizer:tap];
    ...
    [_testBtn addTarget:self action:@selector(testBtnClicked) forControlEvents:UIControlEventTouchUpInside];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"=========> base view touchs Began");
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
     NSLog(@"=========> base view touchs Moved");
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
     NSLog(@"=========> base view touchs Ended");
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
     NSLog(@"=========> base view touchs Cancelled");
}
- (void)tapAction {
     NSLog(@"=========> single Tapped");
}
- (void)testBtnClicked {
     NSLog(@"=========> click testbtn");
}
//test view
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"=========> test view touchs Began");
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"=========> test view touchs Moved");
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"=========> test view touchs Ended");
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"=========> test view touchs Cancelled");
}

情景A :?jiǎn)螕鬮aseView脸哀,輸出結(jié)果為:

=========> base view touchs Began
=========> single Tapped
=========> base view touchs Cancelled

情景B :?jiǎn)螕魌estView蹦浦,輸出結(jié)果為:

=========> test view touchs Began
=========> single Tapped
=========> test view touchs Cancelled

情景C :?jiǎn)螕魌estBtn, 輸出結(jié)果為:

=========> click testbtn

情景D :按住testView,過(guò)5秒后或更久釋放撞蜂,輸出結(jié)果為:

=========> test view touchs Began
=========> test view touchs Ended

何解懊は狻?

原來(lái)蝌诡,手勢(shì)有更高的優(yōu)先級(jí)來(lái)識(shí)別一個(gè)觸摸事件溉贿。

Gesture Recognizers Get the First Opportunity to Recognize a Touch
A window delays the delivery of touch objects to the view so that the gesture recognizer can analyze the touch first. During the delay, if the gesture recognizer recognizes a touch gesture, then the window never delivers the touch object to the view, and also cancels any touch objects it previously sent to the view that were part of that recognized sequence.

既觸摸事件首先傳遞到手勢(shì)上,如果手勢(shì)識(shí)別成功浦旱,就會(huì)取消事件的繼續(xù)傳遞宇色,否則,事件還是會(huì)被響應(yīng)鏈處理。具體地宣蠕,系統(tǒng)維持了與響應(yīng)鏈關(guān)聯(lián)的所有手勢(shì)例隆,事件首先發(fā)給這些手勢(shì),然后再發(fā)給響應(yīng)鏈植影。

path_of_touches.png

這就可以解釋了情景A和B了裳擎,首先我們的單擊事件傳遞到了tap手勢(shì)上了,不過(guò)這個(gè)是手勢(shì)識(shí)別需要一點(diǎn)時(shí)間思币,手勢(shì)還在Possible狀態(tài)的時(shí)候事件傳遞到了響應(yīng)鏈的第一個(gè)響應(yīng)對(duì)象(baseView或者testView)鹿响,于是就回調(diào)用它們的touchsBegan:withEvent:方法,然后手勢(shì)識(shí)別成功谷饿,就會(huì)去cancel之前傳遞到的所有響應(yīng)對(duì)象惶我,于是就會(huì)調(diào)用它們的touchsCancelled:withEvent:方法。

按照這個(gè)道理博投,情景C也應(yīng)該是這樣才對(duì)俺窆薄!這就涉及到一個(gè)響應(yīng)級(jí)別的問(wèn)題了毅哗,iOS開(kāi)發(fā)文檔里說(shuō)到

In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button’s parent view, and the user taps the button, then the button’s action method receives the touch event instead of the gesture recognizer. This applies only to gesture recognition that overlaps the default action for a control, which includes:

  • A single finger single tap on a UIButton, UISwitch, UISegmentedControl, UIStepper,and UIPageControl.
  • A single finger swipe on the knob of a UISlider, in a direction parallel to the slider.
  • A single finger pan gesture on the knob of a UISwitch, in a direction parallel to the switch.

所以testBtn的action會(huì)覆蓋手勢(shì)听怕。

在情景D中,由于長(zhǎng)按住testView不釋放虑绵,tap手勢(shì)就會(huì)識(shí)別失敗尿瞭,然后就可以繼續(xù)正常傳遞給testView處理。

假如實(shí)際應(yīng)用中我們?cè)趖estview中有UITableView,上面的方式就不能點(diǎn)擊UITableViewCell了翅睛,除非長(zhǎng)按cell再釋放声搁。 要解決這個(gè)問(wèn)題,需要了解UIGestureRecognizer的cancelsTouchsInView屬性:

//default is YES. causes touchesCancelled:withEvent: or pressesCancelled:withEvent: to 
//be sent to the view for all touches or presses recognized as part of this gesture immediately
//before the action method is called.
@property(nonatomic) BOOL cancelsTouchesInView;      

既在手勢(shì)識(shí)別成功之后,是否取消傳遞給響應(yīng)鏈的觸摸事件捕发。

我們?cè)O(shè)置tap的cancelsTouchsInView為NO疏旨,那么輸出結(jié)果就變成

//A
=========> base view touchs Began
=========> single Tapped
=========> base view touchs Ended
//B
=========> test view touchs Began
=========> single Tapped
=========> test view touchs Ended
//C
=========> single Tapped
=========> click testbtn
//D
=========> test view touchs Began
=========> test view touchs Ended

此時(shí),baseView 和testView上的觸摸事件就可以完整執(zhí)行扎酷。

順便再提一下delaysTouchesBegan屬性:

// default is NO.  causes all touch or press events to be delivered to 
//the target view only after this gesture has failed recognition. set to 
//YES to prevent views from processing any touches or presses that 
//may be recognized as part of this gesture
@property(nonatomic) BOOL delaysTouchesBegan;       

既延遲傳遞事件給view檐涝,我們?cè)O(shè)置tap的delaysTouchesBegan為YES,那么輸出結(jié)果就變成

//A
=========> single Tapped
//B
=========> single Tapped
//C
=========> click testbtn
//D
=========> test view touchs Began
=========> test view touchs Ended

所以事件先被手勢(shì)識(shí)別了法挨,就不再傳遞給響應(yīng)鏈了骤铃。

參考鏈接

iOS開(kāi)發(fā)者文檔
深入淺出iOS事件機(jī)制
iOS 觸摸事件處理詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坷剧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喊暖,老刑警劉巖惫企,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡狞尔,警方通過(guò)查閱死者的電腦和手機(jī)丛版,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)偏序,“玉大人页畦,你說(shuō)我怎么就攤上這事⊙腥澹” “怎么了豫缨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)端朵。 經(jīng)常有香客問(wèn)我好芭,道長(zhǎng),這世上最難降的妖魔是什么冲呢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任舍败,我火速辦了婚禮,結(jié)果婚禮上敬拓,老公的妹妹穿的比我還像新娘邻薯。我一直安慰自己,他們只是感情好乘凸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布厕诡。 她就那樣靜靜地躺著,像睡著了一般翰意。 火紅的嫁衣襯著肌膚如雪木人。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天冀偶,我揣著相機(jī)與錄音醒第,去河邊找鬼。 笑死进鸠,一個(gè)胖子當(dāng)著我的面吹牛稠曼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播客年,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼霞幅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了量瓜?” 一聲冷哼從身側(cè)響起司恳,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绍傲,沒(méi)想到半個(gè)月后扔傅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體耍共,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年猎塞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了试读。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荠耽,死狀恐怖钩骇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铝量,我是刑警寧澤倘屹,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站款违,受9級(jí)特大地震影響唐瀑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜插爹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一厢汹、第九天 我趴在偏房一處隱蔽的房頂上張望颠悬。 院中可真熱鬧泌神,春花似錦拷橘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至寸宵,卻和暖如春崖面,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梯影。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工巫员, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人甲棍。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓简识,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親感猛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子七扰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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