Android CoordinatorLayout Behavior

? ? ? ?Behavior是Android Support Design庫里面新增的布局概念,主要的作用是用來協(xié)調(diào)CoordinatorLayout里面直接Child Views之間交互行為的叔扼。

特別要注意的點(diǎn)是Behavior只能作用于CoordinatorLayout的直接Child View.

? ? ? ?既然Behavior是用來協(xié)調(diào)CoordinatorLayout直接Child View的交互行為的台汇。那Behavior是怎么工作的呢羡微,這個也是我們本文的重點(diǎn)留量。我們準(zhǔn)備從以下四條線路來做簡單的分析丢氢。

  1. Behavior的測量和布局已旧。(Behavior里面onMeasureChild聊记、onLayoutChild函數(shù))

  2. Behavior的普通觸摸事件撒妈。(Behavior里面的onInterceptTouchEvent,onTouchEvent函數(shù))

  3. Behavior的嵌套NestedScrolling觸摸事件排监。(Behavior里面的onStartNestedScroll狰右、onNestedScrollAccepted、onStopNestedScroll舆床、onNestedScroll棋蚌、onNestedPreScroll、onNestedFling挨队、onNestedPreFling函數(shù))

  4. Behavior的依賴關(guān)系谷暮。(Behavior里面的layoutDependsOn、onDependentViewChanged盛垦、onDependentViewRemoved函數(shù))

? ? ? ?CoordinatorLayout直接Child View的LayoutParam里面的Behavior是怎么實(shí)例化得到.有三種方式:第一種湿弦,注解設(shè)置,類似@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)的形似腾夯;第二種颊埃,java代碼設(shè)置;第三種蝶俱,app:layout_behavior來設(shè)置.關(guān)于Behavior的實(shí)例化這里我們就不展開來講班利,有興趣的可以參考CoordinatorLayout里Behavior簡單分析里面Behavior對象是怎么被實(shí)例化的.

第一種注解方式的使用來設(shè)置默認(rèn)Behavior的.

一、Behavior的測量和布局

? ? ? ?Behavior可以引導(dǎo)CoordinatorLayout的直接Child View 進(jìn)行測量和布局榨呆。CoordinatorLayout需要進(jìn)行measure罗标、layout的時候,都會通過Behavior詢問該Behavior對應(yīng)的View是否需要進(jìn)行相應(yīng)的測量和布局操作,如果不需要馒稍,就進(jìn)行默認(rèn)的行為皿哨。如果需要則按照Behavior里面編寫的規(guī)則來測量和布局。這里我們只需要關(guān)注Behavior類的onMeasureChild()纽谒、onLayoutChild()兩個函數(shù)。

? ? ? ?我們以一個具體的例子來簡單的解釋下Behavior怎么引導(dǎo)CoordinatorLayout的直接Child View 進(jìn)行測量和布局的.在上一篇文章Android Design Support Library 控件的使用中有一個CoordinatorLayout + RecyclerView(ViewPager里面放置的是RecyclerView) + AppBarLayout 實(shí)現(xiàn)AppBarLayout里面Toolbar的收縮和展開效果圖的例子.如下圖所示

AppBarLayout.gif

并且他的布局文件如下

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:textColor="@android:color/white"
                android:gravity="center"
                android:text="自定義標(biāo)題"
                android:textSize="18sp" />

        </android.support.v7.widget.Toolbar>

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            style="@style/AppTheme.TabStyle"
            app:tabMode="scrollable"
            app:tabGravity="fill" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/page_collapsing"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

? ? ? ?最外層一個CoordinatorLayout布局如输,并且CoordinatorLayout里面有兩個直接的子View:AppBarLayout和ViewPager.其中AppBarLayout有一個默認(rèn)的AppBarLayout.Behavior鼓黔,同時ViewPager我們通過app:layout_behavior="@string/appbar_scrolling_view_behavior"給設(shè)置了AppBarLayout.ScrollingViewBehavior.這樣CoordinatorLayout兩個直接子View都有對應(yīng)的Behavior了.從界面結(jié)果出咱也能看到剛進(jìn)入界面的時候ViewPager是在AppBarLayout的下面的.咱們就分析分析他是怎么做到的.肯定和測量和布局相關(guān),那出發(fā)點(diǎn)肯定是CoordinatorLayout類的onMeasure()和onLayout().

CoordinatorLayout類onMeasure()函數(shù)

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ......
        for (int i = 0; i < childCount; i++) {
            final CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
            ......
            final CoordinatorLayout.Behavior b = lp.getBehavior();
            if (b == null || !b.onMeasureChild(this, child, childWidthMeasureSpec, keylineWidthUsed,
                                               childHeightMeasureSpec, 0)) {
                onMeasureChild(child, childWidthMeasureSpec, keylineWidthUsed,
                               childHeightMeasureSpec, 0);
            }
            ......
        }
        ......
    }

? ? ? ?分析可以發(fā)現(xiàn)如果對應(yīng)的子View有對應(yīng)的Behavior的時候不见,會先去調(diào)用Behavior里面的onMeasureChild()看Behavior有沒有制定自己的測量方式.這下咱就的進(jìn)入ViewPager對應(yīng)的Behavior AppBarLayout.ScrollingViewBehavior里面的onMeasureChild()方法里面去瞧一瞧了澳化,這里我們就不進(jìn)去了.里面也就是一些正常的測量方法.測量完成接下來就是layout了.CoordinatorLayout類的onLayout()方法.

CoordinatorLayout類onLayout()方法

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        ......
        for (int i = 0; i < childCount; i++) {
            final View child = mDependencySortedChildren.get(i);
            ......
            final CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
            final CoordinatorLayout.Behavior behavior = lp.getBehavior();
            if (behavior == null || !behavior.onLayoutChild(this, child, layoutDirection)) {
                onLayoutChild(child, layoutDirection);
            }
        }
    }

? ? ? ?同樣分析可以得到有對應(yīng)的Behavior就先進(jìn)入到Behavior的onLayoutChild()方法了.ViewPager設(shè)置的AppBarLayout.ScrollingViewBehavior的onLayoutChild()方法里面獲取得到AppBarLayout的區(qū)域,之后把ViewPager布局layout到AppBarLayout的下面.

? ? ? ?這樣咱們以一個簡單的例子對Behavior的測量和布局做了一個非常簡單的分析.里面很多地方也沒有去深究.如果大家有什么疑問的話稳吮,可以留言.在能力范圍之內(nèi)的都會盡力為大家解答的.

二缎谷、Behavior的普通觸摸事件

? ? ? ?Behavior的普通觸摸事件主要和Behavior里面的onInterceptTouchEvent()和onTouchEvent()兩個函數(shù)相關(guān).最終的目的也就是想把對應(yīng)的觸摸時間傳遞到Behavior對應(yīng)的View里面去,讓View做一些相應(yīng)的處理.

? ? ? ?父布局CoordinatorLayout產(chǎn)生的onInterceptTouchEvent灶似,onTouchEvent事件都會先送到Behavior的onInterceptTouchEvent()和onTouchEvent()里面列林,讓去問問Behavior對應(yīng)的View要不要處理.你要處理就先給你處理.你不處理才輪到CoordinatorLayout來處理.關(guān)于這部分的內(nèi)容之前有寫過一個文章.我們就不展開討論了.有興趣的可以參考下CoordinatorLayout里Behavior簡單分析里面Behavior的onInterceptTouchEvent + onTouchEvent一部分的分析.

三、Behavior的嵌套NestedScrolling觸摸事件

? ? ? ?關(guān)于Behavior嵌套滑動主要涉及Behavior里面的onStartNestedScroll(), onNestedScrollAccepted(), onStopNestedScroll(), onNestedScroll(), onNestedPreScroll(), onNestedFling(), onNestedPreFling() 函數(shù).

? ? ? ?這里我們多次提到了嵌套滑動酪惭,有興趣的可以參考我之前寫的Android 嵌套滑動分析一文的簡單分析.

? ? ? ?Behavior的嵌套NestedScrolling事件希痴,大部分情況下是這樣的.CoordinatorLayout里面另一個子View產(chǎn)生了嵌套滑動事件,這個事件先傳遞到CoordinatorLayout春感,然后CoordinatorLayout在把這個嵌套事件過渡到Behavior里面去.之后在讓Beahaior對應(yīng)的View按照實(shí)際情況做不同的處理.同樣關(guān)于這部分內(nèi)容的具體分析砌创,有興趣的可以參考下之前寫的CoordinatorLayout里Behavior簡單分析里面Behavior的onStartNestedScroll + onNestedScrollAccepted + onStopNestedScroll + onNestedScroll + onNestedPreScroll + onNestedFling + onNestedPreFling。嵌套滑動引起的變化部分的簡單分析.

? ? ? ?同樣為了加深理解鲫懒,這里還是以上文CoordinatorLayout + RecyclerView(ViewPager里面放置的是RecyclerView) + AppBarLayout 實(shí)現(xiàn)AppBarLayout里面Toolbar的收縮和展開效果圖的例子來做一個簡單的說明.這也是ViewPager里面為什么一定要放置實(shí)現(xiàn)了NestedScrollingChild2接口的View.這里ViewPager里面放了RecyclerView(RecyclerView實(shí)現(xiàn)了NestedScrollingChild接口).當(dāng)RecyclerView有對應(yīng)的NestedScrollingChild滑動的時候嫩实,都會先傳遞到CoordinatorLayout里面對應(yīng)函數(shù)里面去,然后CoordinatorLayout又會原封不動的傳遞到Behavior對應(yīng)的onStartNestedScroll()窥岩, onNestedScrollAccepted()甲献,onStopNestedScroll(),onNestedScroll()谦秧, onNestedPreScroll()竟纳,onNestedFling(),onNestedPreFling()的函數(shù)里面去.換句話說就是傳遞到了AppBarLayout對應(yīng)的AppBarLayout.Behavior里面去.在里面讓AppBarLayout對某個View的上移和下移的處理.

四疚鲤、Behavior的依賴關(guān)系

? ? ? ?關(guān)于Behavior依賴關(guān)系對應(yīng)Behavior里面的layoutDependsOn()锥累, onDependentViewChanged(),onDependentViewRemoved()這三個函數(shù).

? ? ? ?Behavior的依賴指的是當(dāng)前Behavior對應(yīng)的View依賴于哪個View.當(dāng)依賴的View有變化的時候.會調(diào)用Behavior里面對應(yīng)的函數(shù).然我們對Behavior對應(yīng)的View做相應(yīng)的處理.同樣關(guān)于這一部分的具體分析可以參考之前寫的CoordinatorLayout里Behavior簡單分析里面Behavior的layoutDependsOn + onDependentViewChanged + onDependentViewRemoved集歇。View引起的變化部分.這里我們就不重新拿出來講了桶略,而且里面有一個簡單的例子.

? ? ? ?為了加深理解,咱們還是以上文提到的CoordinatorLayout + RecyclerView(ViewPager里面放置的是RecyclerView) + AppBarLayout 實(shí)現(xiàn)AppBarLayout里面Toolbar的收縮和展開效果圖的例子來做一個簡單的說明哈,其實(shí)在這個里面ViewPager會依賴AppBarLayout的變化.為什么這么說呢.看ViewPager對應(yīng)的AppBarLayout.ScrollingViewBehavior里面

        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
            // We depend on any AppBarLayouts
            return dependency instanceof AppBarLayout;
        }

        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
                View dependency) {
            offsetChildAsNeeded(parent, child, dependency);
            return false;
        }

看到了吧惶翻,如果是AppBarLayout就依賴他.并且在onDependentViewChanged函數(shù)中ViewPager也會跟著AppBarLayout的移動而移動.

五、Behavior的具體使用

5.1 BottomSheetBehavior的使用

? ? ? ?BottomSheetBehavior:實(shí)現(xiàn)底部彈出框的一個Behavior鹅心,注意BottomSheetBehavior一定要配合CoordinatorLayout一起使用才有效果吕粗。

BottomSheetBehavior對應(yīng)的View的狀態(tài):

狀態(tài) 解釋
STATE_EXPANDED bottom sheet 處于完全展開的狀態(tài):當(dāng)bottom sheet的高度低于CoordinatorLayout容器時,整個bottom sheet都可見旭愧;或者CoordinatorLayout容器已經(jīng)被bottom sheet填滿
STATE_COLLAPSED 折疊狀態(tài)(默認(rèn))颅筋, bottom sheets只在底部顯示一部分布局。顯示高度可以通過 app:behavior_peekHeight 設(shè)置
STATE_DRAGGING 過渡狀態(tài)输枯,此時用戶正在向上或者向下拖動bottom sheet
STATE_SETTLING 視圖從脫離手指自由滑動到最終停下的這一小段時間
STATE_HIDDEN 默認(rèn)無此狀態(tài)(需要通過app:behavior_hideable 啟用此狀態(tài))议泵,啟用后用戶將能通過向下滑動完全隱藏 bottom sheet

BottomSheetBehavior屬性設(shè)置

屬性 解釋
app:behavior_hideable bottom sheet是否可以完全隱藏,默認(rèn)為false
app:behavior_peekHeight bottom sheet為STATE_COLLAPSED(折疊)狀態(tài)的時殘留的高度
app:behavior_skipCollapsed 是否跳過STATE_COLLAPSED狀態(tài)

? ? ? ?BottomSheetBehavior有兩種實(shí)現(xiàn)方式桃熄,一個之直接嵌套在布局里面先口,一個是通過dialog的方式彈出.兩種使用方式都不難.所以我們也就以一個具體的實(shí)例來說明.效果圖如下:

BottomSheet.gif
5.2 自定義Behavior

? ? ? ?關(guān)于自定義Behavior,我們也實(shí)現(xiàn)了兩個簡單的效果.

5.2.1 上滑下滑的時候FloatingActionButton底部彈入或者彈出

效果圖

bottom.gif

Behavior

public class FabBottomInOutBehavior extends FloatingActionButton.Behavior {

    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();

    private boolean mAnimatingOut = false;

    public FabBottomInOutBehavior() {
    }

    public FabBottomInOutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                       @NonNull FloatingActionButton child,
                                       @NonNull View directTargetChild,
                                       @NonNull View target,
                                       int axes,
                                       int type) {
        //需要垂直的滑動
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||
               super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
    }


    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                               @NonNull FloatingActionButton child,
                               @NonNull View target,
                               int dxConsumed,
                               int dyConsumed,
                               int dxUnconsumed,
                               int dyUnconsumed,
                               int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
        if (dyConsumed > 0 && !mAnimatingOut) {
            //向上滑動
            animateOut(child);
        } else if (dyConsumed < 0) {
            //向下滑動
            animateIn(child);
        }
    }

    private void animateOut(final FloatingActionButton button) {
        ViewCompat.animate(button)
                  .translationY(button.getHeight() + getMarginBottom(button))
                  .setInterpolator(INTERPOLATOR)
                  .withLayer()
                  .setListener(new ViewPropertyAnimatorListener() {
                      public void onAnimationStart(View view) {
                          mAnimatingOut = true;
                      }

                      public void onAnimationCancel(View view) {
                          mAnimatingOut = false;
                      }

                      public void onAnimationEnd(View view) {
                          mAnimatingOut = false;
                      }
                  })
                  .start();
    }


    private void animateIn(FloatingActionButton button) {
        ViewCompat.animate(button).translationY(0).setInterpolator(INTERPOLATOR).withLayer().setListener(null).start();
    }

    private int getMarginBottom(View v) {
        final ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
        if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
            return ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
        }
        return 0;
    }
}
5.2.2 上滑的時候以覆蓋的方式蓋住頭部

效果圖

cover.gif

Behavior

public class HeaderCoverBehavior extends CoordinatorLayout.Behavior<View> {

    public HeaderCoverBehavior() {
    }

    public HeaderCoverBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return super.layoutDependsOn(parent, child, dependency);
    }

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
        if (params != null && params.height == CoordinatorLayout.LayoutParams.MATCH_PARENT) {
            child.layout(0, 0, parent.getWidth(), parent.getHeight());
            child.setTranslationY(getFirstChildHeight(parent));
            return true;
        }

        return super.onLayoutChild(parent, child, layoutDirection);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                       @NonNull View child,
                                       @NonNull View directTargetChild,
                                       @NonNull View target,
                                       int axes,
                                       int type) {
        return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                  @NonNull View child,
                                  @NonNull View target,
                                  int dx,
                                  int dy,
                                  @NonNull int[] consumed,
                                  int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        // 在這個方法里面只處理向上滑動
        if (dy < 0) {
            return;
        }
        float transY = child.getTranslationY() - dy;
        if (transY > 0) {
            child.setTranslationY(transY);
            consumed[1] = dy;
        }
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                               @NonNull View child,
                               @NonNull View target,
                               int dxConsumed,
                               int dyConsumed,
                               int dxUnconsumed,
                               int dyUnconsumed,
                               int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
        // 在這個方法里只處理向下滑動
        if (dyUnconsumed > 0) {
            return;
        }
        float transY = child.getTranslationY() - dyUnconsumed;
        if (transY > 0 && transY < getFirstChildHeight(coordinatorLayout)) {
            child.setTranslationY(transY);
        }
    }

    /**
     * 這里有優(yōu)化的空間,這里純粹的去取了第一個view的measure height 有點(diǎn)限制的太死了
     */
    private int getFirstChildHeight(CoordinatorLayout coordinatorLayout) {
        return coordinatorLayout.getChildAt(0).getMeasuredHeight();
    }

}

? ? ? ?關(guān)于Behavior所要想分享的東西就這些了,如果后面自定義Behavior實(shí)現(xiàn)的特別有意思的效果也會第一時間分享給大家.最后上文涉及的所有實(shí)例的下載地址 https://github.com/tuacy/DesignWidget

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末往扔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子收夸,更是在濱河造成了極大的恐慌,老刑警劉巖血崭,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卧惜,死亡現(xiàn)場離奇詭異,居然都是意外死亡夹纫,警方通過查閱死者的電腦和手機(jī)咽瓷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舰讹,“玉大人茅姜,你說我怎么就攤上這事≡孪唬” “怎么了钻洒?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锄开。 經(jīng)常有香客問我素标,道長,這世上最難降的妖魔是什么萍悴? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任头遭,我火速辦了婚禮寓免,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘计维。我一直安慰自己袜香,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布鲫惶。 她就那樣靜靜地躺著蜈首,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剑按。 梳的紋絲不亂的頭發(fā)上疾就,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音艺蝴,去河邊找鬼。 笑死鸟废,一個胖子當(dāng)著我的面吹牛猜敢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盒延,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缩擂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了添寺?” 一聲冷哼從身側(cè)響起胯盯,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎计露,沒想到半個月后博脑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡票罐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年叉趣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片该押。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡疗杉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚕礼,到底是詐尸還是另有隱情烟具,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布奠蹬,位于F島的核電站朝聋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏罩润。R本人自食惡果不足惜玖翅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一翼馆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧金度,春花似錦应媚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至跟伏,卻和暖如春丢胚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背受扳。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工携龟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勘高。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓峡蟋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親华望。 傳聞我的和親對象是個殘疾皇子蕊蝗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

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