Android事件分發(fā)機(jī)制(View篇)

紙上得來終覺淺蠢护,看了很多別人寫的有關(guān)View的事件分發(fā)機(jī)制的博客,但別人的終究
是別人的箍土,把自己的理解寫下來逢享,才是自己的,但萬變不離其宗涮帘。本篇將從另外一個(gè)
角度帶你理解View的事件分發(fā)機(jī)制拼苍。

序言

關(guān)于 ViewViewGroup 的事件分發(fā)機(jī)制 我打算用兩篇博客來寫,
本篇主要講述 View 的事件分發(fā)機(jī)制调缨,下一篇講述ViewGroup的事件分發(fā)機(jī)制

View 的事件分發(fā)和領(lǐng)導(dǎo)派發(fā)任務(wù)是很相似的疮鲫,所以我們先通過這個(gè)生活中常見的場景引入,以便大家更好的理解View的事件分發(fā)

場景描述:

當(dāng)老板有一個(gè)問題需要解決的時(shí)候弦叶,他可以自己直接解決俊犯,也可以將問題交給經(jīng)理去解決,當(dāng)然老板不可能所有問題都
要自己解決伤哺,那樣還要經(jīng)理和員工干什么燕侠,所以老板一般會(huì)將任務(wù)派發(fā)給經(jīng)理,一般經(jīng)理也不會(huì)自己解決立莉,他會(huì)將問題
派發(fā)給員工去解決绢彤,員工嘛就是干活的,否則就得走人了蜓耻,當(dāng)然不排除有些問題員工沒有能力解決那只能將問題返回給
經(jīng)理茫舶,經(jīng)理有能力解決就解決了,如果經(jīng)理也解決不了刹淌,那就把這個(gè)問題扔回給老板饶氏,最后只能由老板自己解決了。

類似地:

我們的View的事件分發(fā)也是這樣的有勾,當(dāng)我們手接觸到手機(jī)屏幕的時(shí)候疹启,屏幕接收到一個(gè)Touch事件,系統(tǒng)會(huì)將這Touch
事件封裝成一個(gè)對象MotionEvent蔼卡,之后所有的事件處理都將與這個(gè)MotionEvent相關(guān)喊崖,和領(lǐng)導(dǎo)派發(fā)任務(wù)一樣,我們的
Touch事件會(huì)首先到達(dá)最外層的ViewGroup(Activity)雇逞,然后再一層一層地向子View派發(fā)荤懂,最終會(huì)到達(dá)最內(nèi)層的View,
最內(nèi)層的View可以處理這個(gè)Touch事件,也可以將這個(gè)Touch事件扔回給自己的父View

對于View和ViewGroup我們需要關(guān)注下面的個(gè)方法:

View 兩個(gè)方法:

  • dispatchTouchEvent (MotionEvent event)//負(fù)責(zé)事件分發(fā)
  • onTouchEvent(MotionEvent event)//當(dāng)前View自己處理當(dāng)前事件

ViewGroup 三個(gè)方法:

  • dispatchTouchEvent (MotionEvent event)//負(fù)責(zé)事件分發(fā)
  • onInterCeptTouchEvent(MotionEvent event)//處理是否攔截當(dāng)前事件
  • onTouchEvent(MotionEvent event)//當(dāng)前View自己處理當(dāng)前事件

我們注意到上面的方法都參數(shù)都是一個(gè) MotionEvent 對象喝峦,ViewViewGroup少了一個(gè)onInterCeptTouchEvent()方法势誊,這時(shí)因?yàn)閷τ?code>View來講,它是不能有子View的谣蠢,所以不需要攔截事件的方法

正文:

我們先從Android中兩種不同類型的控件開始介紹

  • 可被點(diǎn)擊的: Button粟耻、ImageButton... //即本身CLICKABLE為true
  • 不可被點(diǎn)擊的: ImageView、TextView...//即本身CLICKABLE為false

注意:上面兩點(diǎn)很重要眉踱,大家一定要記在心里挤忙。也可能你會(huì)有疑問我們平常用的ImageViewTextView都能點(diǎn)擊呀,請注意我說的是本身可被點(diǎn)擊的谈喳,ImageViewTextView能被點(diǎn)擊是因?yàn)槲覀兘o他們設(shè)置了setOnClickListener(),這樣就把這兩種ViewCLICKABLE置為true了级历,關(guān)于這一點(diǎn)大家可以通過調(diào)用這個(gè)方法前后添加log日志去驗(yàn)證初狰。

我們先新建一個(gè)project: ViewDemo

ViewDemo 很簡單:在布局文件中添加一個(gè) ImageView 和一個(gè) Button 控件
MainActivity中初始化并給兩個(gè)控件都設(shè)置setOnTouchListener

先看布局文件

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按鈕"/>
</LinearLayout>

MainActivity中初始化ImageViewButton并設(shè)置setOnTouchListener
onTouch()方法中添加log日志

MainActivity主要代碼

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mImageView = findViewById(R.id.imageView);
    mButton = findViewById(R.id.button);

    mImageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.e(TAG,"----mImageView-----onTouch---->"+motionEvent.getAction());
            return false;
        }
    });
    mButton.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.e(TAG,"----mButton--------onTouch---->"+motionEvent.getAction());
            return false;
        }
    });

}

運(yùn)行程序依次點(diǎn)擊 ImageViewButton

其中 motionEvent.getAction() 的值代表的含義:

0:ACTION_DOWN
2:ACTION_MOVE
1:ACTION_UP

打印log如下:

10-30 11:50:06.439 10517-10517/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->0

10-30 11:50:07.276 10517-10517/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->0
10-30 11:50:07.285 10517-10517/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->2
10-30 11:50:07.313 10517-10517/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->1

我們可以看到點(diǎn)擊ImageView的時(shí)候日志打印了一次枣购,點(diǎn)擊Button的時(shí)候日志打印了三次
如果我們把兩個(gè)onTouch()方法的返回值都返回true即:

mImageView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        Log.e(TAG,"----mImageView-----onTouch---->"+motionEvent.getAction());
        return true;
    }
});
mButton.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        Log.e(TAG,"----mButton--------onTouch---->"+motionEvent.getAction());
        return true;
    }
});

}

分別點(diǎn)擊 ImageViewButton 再來看日志:

10-30 12:55:16.427 20779-20779/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->0
10-30 12:55:16.442 20779-20779/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->2
10-30 12:55:16.487 20779-20779/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->1

10-30 12:55:19.514 20779-20779/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->0
10-30 12:55:19.533 20779-20779/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->2
10-30 12:55:19.574 20779-20779/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->1

此時(shí)可以看到兩個(gè)控件的日志打印都是三次爹耗,DOWNMOVE岗仑、UP

一分鐘時(shí)間思考一下這是為什么?

下面讓我?guī)Т蠹覐脑创a角度分析一下為什么會(huì)這樣:
前面我們提到過對于View來講我們關(guān)注兩個(gè)方法:

  • dispatchTouchEvent (MotionEvent event)//負(fù)責(zé)事件分發(fā)
  • onTouchEvent(MotionEvent event)//當(dāng)前View自己處理當(dāng)前事件

我們需要知道,當(dāng)一個(gè)View接收到Touch事件的時(shí)候挽绩,首先被調(diào)用的是當(dāng)前ViewdispatchTouchEvent()方法:
下面我們看一下View源碼中的這個(gè)方法:dispatchTouchEvent()

為了便于理解,我省略了部分干擾代碼驾中,只保留了有效的部分

dispatchTouchEvent(MotionEvent event)

/**
 * Pass the touch screen motion event down to the target view, or this
 * view if it is the target.
 *
 * @param event The motion event to be dispatched.
 * @return True if the event was handled by the view, false otherwise.
 */
public boolean dispatchTouchEvent(MotionEvent event) {
    boolean result = false;
    ......
        
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }

        if (!result && onTouchEvent(event)) {
            result = true;
        }
    ......

    return result;
}

從方法的注釋我們可以知道:這個(gè)方法是處理事件分發(fā)的唉堪,如果return true說明當(dāng)前事件被消費(fèi)了,便不再繼續(xù)分發(fā)肩民,否則繼續(xù)分發(fā)

我們主要看方法中的兩個(gè)if判斷:先看第一個(gè)

li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED

&& li.mOnTouchListener.onTouch(this, event)

因?yàn)槲覀兘o控件設(shè)置了onTouchLishener所以mListenerInfo不為空唠亚,li != nulltrue,li.mOnTouchListener != null也為true,這個(gè)mOnTouchListener就是我們mImageView.setOnTouchListener(new View.OnTouchListener())的時(shí)候new出來的持痰,第三個(gè)條件主要取決于mViewFlags灶搜,在Android系統(tǒng)中所有控件默認(rèn)都是enable的,除非我們對一個(gè)控件設(shè)置view.setEnable(false),所以(mViewFlags & ENABLED_MASK) == ENABLED也為true共啃,那么能不能進(jìn)入到if()內(nèi)部關(guān)鍵看li.mOnTouchListener.onTouch(this, event)占调,這個(gè)方法的返回值就是我們最開始setOnTouchListener中重寫的onTouch()方法的返回值,默認(rèn)為false移剪,后來被我們改成了true究珊。

onTouch()方法中默認(rèn)false,也就是說此處的第一個(gè)if()條件不成立纵苛,那么將到第二個(gè)if()判斷:剿涮!resulttrue,那么我們主要看onTouchEvent(event)的返回值攻人,那么這個(gè)onTouchEvent(event)有時(shí)什么東東呢取试?我們進(jìn)入到這個(gè)方法中(干擾代碼已省略):

onTouchEvent(MotionEvent event)

 /*
  * @param event The motion event.
  * @return True if the event was handled, false otherwise.
  */
public boolean onTouchEvent(MotionEvent event) {
   ......

    if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                  ......
                    if (!post(mPerformClick)) {
                         performClick();
                     }
                  ......
                break;

            case MotionEvent.ACTION_DOWN:

                ......

                break;

            case MotionEvent.ACTION_CANCEL:

                ......

                break;

            case MotionEvent.ACTION_MOVE:

                ......

                break;
        }

        return true;
    }

    return false;
}

從方法中我們可以看到這個(gè)方法的返回值也是 boolean 類型的,看到這里不知道大家能不能想起我在開頭說的Android中兩種不同類型怀吻,一種是默認(rèn)可以點(diǎn)擊的瞬浓,一種是默認(rèn)不可以點(diǎn)擊,我們的 ImageViewButton 的可點(diǎn)擊與否的作用就在這個(gè)方法中的到了體現(xiàn)蓬坡,讓我們來看一下這個(gè) if() 條件判斷吧

先說默認(rèn)條件下兩個(gè)Touch方法都返回false

- ImageView

如果是 ImageView不用想猿棉,默認(rèn)就是不可點(diǎn)擊的,也就是說CLICKABLELONG_CLICKABLE都為false屑咳,那么好萨赁,這個(gè)條件我們是進(jìn)不去的,再看最后return值是false兆龙,也就是說只要if()判斷進(jìn)不去杖爽,全都會(huì)返回false,回到我們之前的dispatchTouchEvent()中,既然onTouchEvent()也返回了false慰安,那么最終dispatchTouchEvent()的返回值也是false腋寨,說明這個(gè)TouchDOWN事件沒有被消費(fèi),既然DOWN事件沒有被消費(fèi)泻帮,也就沒有后面的MOVEUP精置,所以最初的ImageView值打印了一行l(wèi)og计寇,

- Button

如果是Button默認(rèn)就是可點(diǎn)擊的CLICKABLELONG_CLICKABLE都為true锣杂,也就是說if()判斷能夠進(jìn)入,那么就說明番宁,里面的DOWN元莫、MOVEUP事件都會(huì)響應(yīng),另外我們再看蝶押,進(jìn)入if()后最后一句: return true;這句返回了true踱蠢,也就是說,只要進(jìn)入了這個(gè)if()判斷棋电,就回返回true茎截,也就是我們的dispatchTouchEvent()中的第二個(gè)if()判斷會(huì)返回true,那么我們的dispatchTouchEvent()最終也就回返回true赶盔,也就是說我們的Touch事件被消費(fèi)了企锌。當(dāng)然DOWNMOVE于未、UP事件都會(huì)響應(yīng)撕攒,所以我們的Button打印了三行log

再說之后我們把兩個(gè)Touch方法都返回true

當(dāng)這兩個(gè)onTouch()方法都返回true的時(shí)候烘浦,就更簡單了抖坪,還是看我們的dispatchTouchEvent(),即第一個(gè)if()判斷中mOnTouchListener.onTouch(this, event)true闷叉,前面我們已經(jīng)判斷了擦俐,if()中其他的都為true,所以第一個(gè)if()判斷可以進(jìn)入握侧,最終返回了true蚯瞧,dispatchTouchEvent()的返回值為true,根本就走不到第二個(gè)if()條件判斷藕咏,所以跟后面的onTouchEvent()就沒什么關(guān)系了状知。所以最終這個(gè)Touch事件在dispatchTouchEvent()中的回調(diào)的onTouch()方法中得消費(fèi)掉了。

注意:不知道有沒有同學(xué)發(fā)現(xiàn)我上面onTouchEvent()方法中除了省略的代碼之外孽查,還留下了一行這個(gè)方法就與我們的Click事件又關(guān)了饥悴,我們先看一下這個(gè)方法:performClick();

performClick()

/**
 * Call this view's OnClickListener, if it is defined.  Performs all normal
 * actions associated with clicking: reporting accessibility event, playing
 * a sound, etc.
 *
 * @return True there was an assigned OnClickListener that was called, false
 *         otherwise is returned.
 */
public boolean performClick() {
    final boolean result;
    final ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        li.mOnClickListener.onClick(this);
        result = true;
    } else {
        result = false;
    }

    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    return result;
}

不過要想執(zhí)行到 performClick() 這個(gè)方法要想執(zhí)行到,首先得能進(jìn)入到上面 onTouchEvent() 方法中的 if() 條件判斷

下面我們在MainActivity的onCreate方法中給ImageViewButton設(shè)置兩個(gè)click監(jiān)聽事件,把onTouch事件還原到默認(rèn)的false返回值

    mImageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.e(TAG,"----mImageView-----onTouch---->"+motionEvent.getAction());
            return false;
        }
    });
    mButton.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.e(TAG,"----mButton--------onTouch---->"+motionEvent.getAction());
            return false;
        }
    });


    mImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.e(TAG,"----mImageView--------onClick---->");
        }
    });
    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.e(TAG,"----mButton--------onClick---->");
        }
    });

先點(diǎn)擊ImageView打印log:

10-30 14:17:01.255 11719-11719/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->0
10-30 14:17:01.272 11719-11719/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->2
10-30 14:17:01.305 11719-11719/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->1
10-30 14:17:01.309 11719-11719/com.marco.viewdemo E/MainActivity: ----mImageView-----onClick---->

再點(diǎn)擊Button打印log:

10-30 14:18:00.624 11719-11719/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->0
10-30 14:18:00.641 11719-11719/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->2
10-30 14:18:00.671 11719-11719/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->1
10-30 14:18:00.674 11719-11719/com.marco.viewdemo E/MainActivity: ----mButton--------onClick---->

咦西设?竟然一樣瓣铣?你可能要問了,對于Button打印的結(jié)果我們可以理解贷揽,但是我們只給ImageViewButton添加了Click監(jiān)聽事件棠笑,其他都沒變,兩個(gè)onTouch()方法返回的竟然也都一樣禽绪,按照我們最初只添加兩個(gè)setOnTouchListener方法蓖救,ImageView應(yīng)該只打印一次才對呀,怎么添加了一個(gè)setOnClickListener印屁,就打印三次了呢循捺?而切如果按照我們最開始的推論,既然ImageView是默認(rèn)不可點(diǎn)擊的雄人,那么在onTouchEvent方法中的if()判斷條件不可能進(jìn)入呀从橘,更不會(huì)執(zhí)行到performClick()方法,怎么會(huì)也打印出除了最后一行onClicklog呢础钠?

猜想:上面log既然顯示執(zhí)行了performClick()恰力,也就是說onTouchEvent()中的if()判斷條件進(jìn)入了,而我們只設(shè)置了setOnClickListener方法旗吁,莫非這個(gè)方法做了什么手腳踩萎?是不是把ImageViewCLICKABLE的值改變了呢?
我們進(jìn)入到setOnClickListener中一探究竟:

/**
 * Register a callback to be invoked when this view is clicked. If this view is not
 * clickable, it becomes clickable.
 *
 * @param l The callback that will run
 *
 * @see #setClickable(boolean)
 */
public void setOnClickListener(OnClickListener l) {
    if (!isClickable()) {
        setClickable(true);
    }
    getListenerInfo().mOnClickListener = l;
}

天吶阵漏,setClickable(true);看到了吧驻民?我們的猜想是對的,一旦我們設(shè)置了setOnClickListener當(dāng)前ViewCLICKABLE的值就會(huì)被置為true履怯,這就不難理解為什么ImageView也能進(jìn)入到if()判斷中回还,而且執(zhí)行了performClick()方法。

通過上面例子我們也的出來一個(gè)結(jié)論:ViewonTouch()方法是先于onClick()方法執(zhí)行的叹洲,如果onTouch()方法返回true即被消費(fèi)了柠硕,就不會(huì)執(zhí)行onTouchEvent()方法,也就執(zhí)行不到onClick()方法运提,
這點(diǎn)我們也可以驗(yàn)證一下蝗柔,就是把上面兩個(gè)setOnTouchListener中的onTouch方法都置為true然后分別點(diǎn)擊ImageViewButton然后看log
點(diǎn)擊ImageViewhe

10-30 14:43:54.142 29165-29165/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->0
10-30 14:43:54.150 29165-29165/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->2
10-30 14:43:54.202 29165-29165/com.marco.viewdemo E/MainActivity: ----mImageView-----onTouch---->1

點(diǎn)擊Button

10-30 14:44:13.478 29165-29165/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->0
10-30 14:44:13.494 29165-29165/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->2
10-30 14:44:13.641 29165-29165/com.marco.viewdemo E/MainActivity: ----mButton--------onTouch---->1

看到了吧?即使我們給ImageViewButton也都設(shè)置了setOnClickListener民泵,但是在onTouch()方法中返回了true癣丧,所以onclick都沒有執(zhí)行

總結(jié)

  • Android中分為兩種類型的View,即默認(rèn)可點(diǎn)擊的和默認(rèn)不可點(diǎn)擊的(重點(diǎn))

  • 當(dāng)一個(gè)Touch事件發(fā)出的時(shí)候,View中最先執(zhí)行的是dispatchTouchEvent()

  • 在dispatchTouchEvent()方法內(nèi)部先判斷onTouch()的返回值栈妆,根據(jù)返回值確定是否執(zhí)行onTouchEvent()方法

  • 一個(gè)View的onTouch事件是優(yōu)先于onClick執(zhí)行的

  • onTouch()和onTouchEvent()的共同點(diǎn)是胁编,都在dispatchTouchEvent中執(zhí)行判斷厢钧;區(qū)別是,onTouch()優(yōu)先于onTouchEvent()執(zhí)行嬉橙,而且其返回值決定了onTouchEvent()能不能夠得到執(zhí)行

好了以上就是我對View的事件分發(fā)機(jī)制的全部理解早直,不足之處或者又不理解的地方請?jiān)谠u論區(qū)留下您的評論,大家共同進(jìn)步市框。
最后附上ViewDemo源碼:github下載
下一篇:Android事件分發(fā)機(jī)制( ViewGroup篇)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末霞扬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子枫振,更是在濱河造成了極大的恐慌喻圃,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒋得,死亡現(xiàn)場離奇詭異级及,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)额衙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怕吴,“玉大人窍侧,你說我怎么就攤上這事∽粒” “怎么了伟件?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長议经。 經(jīng)常有香客問我斧账,道長,這世上最難降的妖魔是什么煞肾? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任咧织,我火速辦了婚禮,結(jié)果婚禮上籍救,老公的妹妹穿的比我還像新娘习绢。我一直安慰自己,他們只是感情好蝙昙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布闪萄。 她就那樣靜靜地躺著,像睡著了一般奇颠。 火紅的嫁衣襯著肌膚如雪败去。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天烈拒,我揣著相機(jī)與錄音圆裕,去河邊找鬼三椿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛葫辐,可吹牛的內(nèi)容都是我干的搜锰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼耿战,長吁一口氣:“原來是場噩夢啊……” “哼蛋叼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起剂陡,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤狈涮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鸭栖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歌馍,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年晕鹊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了松却。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溅话,死狀恐怖晓锻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情飞几,我是刑警寧澤砚哆,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站屑墨,受9級特大地震影響躁锁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卵史,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一战转、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧程腹,春花似錦匣吊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至见转,卻和暖如春命雀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斩箫。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工吏砂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撵儿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓狐血,卻偏偏與公主長得像淀歇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子匈织,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

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