MaterialDesign--(9)AppBarLayout+CollapsingToolbarLayout的使用及源碼分析

AppBarLayout

這個(gè)玩意去年就特別火了,主要是因?yàn)楹糜茫凑乙呀?jīng)在 app 里面用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+Toolbar實(shí)現(xiàn)了好多讓 iOS 目瞪狗呆的效果。不過話說回來,實(shí)現(xiàn)歸實(shí)現(xiàn),每次實(shí)現(xiàn)都是去找別人的博客,然后一頓 CV 大法,然后屬性參數(shù)到處亂配置,最終效果達(dá)到,然后提交代碼不管。
至于各個(gè)類是干嘛的,有哪些方法,我都不 care。當(dāng)然咯,程序員首先得先滿足產(chǎn)品的需求,CV 大法的前提也是你知道CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+Toolbar這些東西能夠?qū)崿F(xiàn)你的需求。所以,程序員的見識很重要。這里我給廣大的 Android 猿們推薦一款Chrome瀏覽器插件“掘金”。對,沒錯(cuò),就是稀土掘金發(fā)布的,我覺得這個(gè)插件用起來別稀土掘金的官網(wǎng)簡潔多了,主要是便捷,節(jié)省信息檢索時(shí)間。扯遠(yuǎn)了,會用是程序員的最低要求,想要更進(jìn)一步,當(dāng)然是去看源碼,理解如何實(shí)現(xiàn)。

* AppBarLayout is a vertical {@link LinearLayout} which implements many of the features of
* material designs app bar concept, namely scrolling gestures.
* <p>
* Children should provide their desired scrolling behavior through
* {@link LayoutParams#setScrollFlags(int)} and the associated layout xml attribute:
* {@code app:layout_scrollFlags}.
*
* <p>
* This view depends heavily on being used as a direct child within a {@link CoordinatorLayout}.
* If you use AppBarLayout within a different {@link ViewGroup}, most of it's functionality will
* not work.
* <p>
* AppBarLayout also requires a separate scrolling sibling in order to know when to scroll.
* The binding is done through the {@link ScrollingViewBehavior} behavior class, meaning that you
* should set your scrolling view's behavior to be an instance of {@link ScrollingViewBehavior}.
* A string resource containing the full class name is available.
……省略了一個(gè) xml 布局 demo

簡單翻譯一下吧,反正我英語不好,翻譯的也不一定對~
AppBarLayout是一個(gè)實(shí)現(xiàn)了許多 MaterialDesign app bar 思想(即滾動手勢)的垂直布局。子控件需要通過setScrollFlags()或 app:"layout_scrollFlags"來提供他們的滑動行為。這個(gè) View 作為一個(gè)子 View,對 CoordinatorLayout 依賴性很強(qiáng),如果CoordinatorLayout不是父View,很多功能會失效。最后一句話翻譯起來有點(diǎn)別扭,就是說 AppBarLayout 需要給他依賴度 View 設(shè)置 ScrollingViewBehavoir 來監(jiān)聽依賴的 View 什么時(shí)候滾動。

按照國際慣例,我們先看一下 attrs 和 public 方法把

attributes

<declare-styleable name="AppBarLayout">
    <attr name="elevation"/>
    <attr name="android:background"/>
    <attr format="boolean" name="expanded"/>
</declare-styleable>
<declare-styleable name="AppBarLayoutStates">
    <attr format="boolean" name="state_collapsed"/>
    <attr format="boolean" name="state_collapsible"/>
</declare-styleable>
<declare-styleable name="AppBarLayout_Layout">
    <attr name="layout_scrollFlags">
        <flag name="scroll" value="0x1"/>
        <flag name="exitUntilCollapsed" value="0x2"/>        
        <flag name="enterAlways" value="0x4"/>        
        <flag name="enterAlwaysCollapsed" value="0x8"/>        
        <flag name="snap" value="0x10"/>
    </attr>
    <attr format="reference" name="layout_scrollInterpolator"/>
</declare-styleable>
  • expanded 是否展開
  • AppBarLayoutStates 我也不知道這玩意是干嘛的,以后知道了再來修改
  • layout_scrollFlags 這個(gè)屬性是用來控制子 view 的伴隨滾動處理,一共有5個(gè)值,5個(gè)值之間是可以進(jìn)行或運(yùn)算的,也就是說可以同時(shí)設(shè)置多種狀態(tài)。

為了便于理解這5個(gè)值得效果,我從源碼里面找到了這5個(gè)值的解釋

/**
  * The view will be scroll in direct relation to scroll events. This flag needs to be
  * set for any of the other flags to take effect. If any sibling views
  * before this one do not have this flag, then this value has no effect.
  * 1.view 會和滾動事件關(guān)聯(lián)。
  * 2.如果要設(shè)置其他任何flag,必須同時(shí)設(shè)置這個(gè) flag
  * 3.如果在這個(gè) view 之前,沒有任何同層級 view 設(shè)置過這個(gè) flag,那么這個(gè)值也沒有任何效果
  */
 public static final int SCROLL_FLAG_SCROLL = 0x1;
 
/**
  * When exiting (scrolling off screen) the view will be scrolled until it is
  * 'collapsed'. The collapsed height is defined by the view's minimum height.
  *當(dāng)上拉的時(shí)候,這個(gè) view 也會滾動,直到滾動到最小高度,固定在屏幕頂部
  * @see ViewCompat#getMinimumHeight(View)
  * @see View#setMinimumHeight(int)
  */
 public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 0x2;

/**
  * When entering (scrolling on screen) the view will scroll on any downwards
  * scroll event, regardless of whether the scrolling view is also scrolling. This
  * is commonly referred to as the 'quick return' pattern.
  * 當(dāng)下拉的時(shí)候,優(yōu)先顯示被隱藏的 view
  */
 public static final int SCROLL_FLAG_ENTER_ALWAYS = 0x4;

/**
  * An additional flag for 'enterAlways' which modifies the returning view to
  * only initially scroll back to it's collapsed height. Once the scrolling view has
  * reached the end of it's scroll range, the remainder of this view will be scrolled
  * into view. The collapsed height is defined by the view's minimum height.
  * 下拉的時(shí)候優(yōu)先顯示被隱藏的 view
  * @see ViewCompat#getMinimumHeight(View)
  * @see View#setMinimumHeight(int)
  */
 public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;

/**
  * Upon a scroll ending, if the view is only partially visible then it will be snapped
  * and scrolled to it's closest edge. For example, if the view only has it's bottom 25%
  * displayed, it will be scrolled off screen completely. Conversely, if it's bottom 75%
  * is visible then it will be scrolled fully into view.
  * 就是一個(gè)自動回滾的效果,比如說滑動到25%松手,就會自動滾回0
  */
 public static final int SCROLL_FLAG_SNAP = 0x10;

這里的設(shè)計(jì)挺棒的,我簡單提一下,用位運(yùn)算,一個(gè) int 值記錄了5種狀態(tài)的排列組合。一共五個(gè)狀態(tài),五個(gè)不同的 flag,但是源碼里面,就用了一個(gè) int 型的變量就記錄了五個(gè)不同狀態(tài)的排列與組合。正常如果是我們自己寫的話,是不是一不小心就定義了5個(gè)變量去記錄這些值,比如說:mCanScroll,mSnap,然后代碼里面會有類似的代碼:“if(mSnap)do sth”。好了,不扯遠(yuǎn)了,五個(gè) flag 的值分別是1、2、4、8、16,轉(zhuǎn)換成二進(jìn)制分別占了第0、1、2、3、4個(gè)位數(shù),第 n 個(gè)位數(shù)如果為0,則沒有這個(gè) flag,為1則表示有。比如scroll|enterAlways 這個(gè)flag,位運(yùn)算|就是1|4,得到的值是5,然后賦值給了 mFlag,這個(gè) mFlag 則表示scroll、enterAlways兩種狀態(tài),然后如果要判斷是否可以 scroll,則只需要 mFlag&scroll==scroll即可。
類似的代碼設(shè)計(jì)還有 manifeast里面的 android:windowSoftInputMode="adjustPan|adjustResize|stateVisible"
不知道我說明百了沒,沒看懂的小伙伴可以跳過。。。。。

Public methods

  • addOnOffsetChangedListener 添加便宜量監(jiān)聽,就是監(jiān)聽 AppBarLayout 的可見高度變化
  • removeOnOffsetChangedListener 移除
  • setExpanded 設(shè)置展開或者收縮
  • generateLayoutParams 生成 LayoutParams。一般用不到
  • setOrientation 不用關(guān)心的方法,方向只能是 vertical
  • getTotalScrollRange 獲取最大滾動偏移量
  • setTargetElevation 設(shè)置 Z 軸高度

CollapsingToolbarLayout

  • CollapsingToolbarLayout is a wrapper for {@link Toolbar} which implements a collapsing app bar.
  • It is designed to be used as a direct child of a {@link AppBarLayout}.
  • CollapsingToolbarLayout contains the following features:
  • <h4>Collapsing title</h4>
  • A title which is larger when the layout is fully visible but collapses and becomes smaller as
  • the layout is scrolled off screen. You can set the title to display via
  • {@link #setTitle(CharSequence)}. The title appearance can be tweaked via the
  • {@code collapsedTextAppearance} and {@code expandedTextAppearance} attributes.
  • <h4>Content scrim</h4>
  • A full-bleed scrim which is show or hidden when the scroll position has hit a certain threshold.
  • You can change this via {@link #setContentScrim(Drawable)}.
  • <h4>Status bar scrim</h4>
  • A scrim which is show or hidden behind the status bar when the scroll position has hit a certain
  • threshold. You can change this via {@link #setStatusBarScrim(Drawable)}. This only works
  • on {@link android.os.Build.VERSION_CODES#LOLLIPOP LOLLIPOP} devices when we set to fit system
  • windows.
  • <h4>Parallax scrolling children</h4>
  • Child views can opt to be scrolled within this layout in a parallax fashion.
  • See {@link LayoutParams#COLLAPSE_MODE_PARALLAX} and
  • {@link LayoutParams#setParallaxMultiplier(float)}.
  • <h4>Pinned position children</h4>
  • Child views can opt to be pinned in space globally. This is useful when implementing a
  • collapsing as it allows the {@link Toolbar} to be fixed in place even though this layout is
  • moving. See {@link LayoutParams#COLLAPSE_MODE_PIN}.
  • <p><strong>Do not manually add views to the Toolbar at run time</strong>.
  • We will add a 'dummy view' to the Toolbar which allows us to work out the available space
  • for the title. This can interfere with any views which you add.</p>

咦,copy 出來的類注釋竟然支持 MarkDown 排版,哈哈哈哈
好了,不說題外話,先看類注釋吧~
一共五個(gè)小標(biāo)題

  • Collapsing title 折疊標(biāo)題
  • Content scrim 內(nèi)容布
  • Status bar scrim 狀態(tài)欄布
  • parallax scrolling children 視差滾動子 View
  • pinned position children 固定子 view 的位置

總結(jié):如果需要折疊標(biāo)題之類的如上功能,則把 AppBarLayout 里面的所有子 view 移到CollapsingToolbarLayout節(jié)點(diǎn)下,然后把CollapsingToolbarLayout作為 AppBarLayout 的唯一子節(jié)點(diǎn)。

attributes

<declare-styleable name="CollapsingToolbarLayout">
    <attr format="dimension" name="expandedTitleMargin"/>
    <attr format="dimension" name="expandedTitleMarginStart"/>
    <attr format="dimension" name="expandedTitleMarginTop"/>
    <attr format="dimension" name="expandedTitleMarginEnd"/>
    <attr format="dimension" name="expandedTitleMarginBottom"/>
    <attr format="reference" name="expandedTitleTextAppearance"/>
    <attr format="reference" name="collapsedTitleTextAppearance"/>
    <attr format="color" name="contentScrim"/>
    <attr format="color" name="statusBarScrim"/>
    <attr format="reference" name="toolbarId"/>
    <attr format="dimension" name="scrimVisibleHeightTrigger"/>
    <attr format="integer" name="scrimAnimationDuration"/>
    <attr name="collapsedTitleGravity">
        <flag name="top" value="0x30"/>        
        <flag name="bottom" value="0x50"/>            
        <flag name="left" value="0x03"/>            
        <flag name="right" value="0x05"/>            
        <flag name="center_vertical" value="0x10"/>            
        <flag name="fill_vertical" value="0x70"/>           
        <flag name="center_horizontal" value="0x01"/>          
        <flag name="center" value="0x11"/>          
        <flag name="start" value="0x00800003"/>            
        <flag name="end" value="0x00800005"/>
    </attr>
    <attr name="expandedTitleGravity">            
        <flag name="top" value="0x30"/>            
        <flag name="bottom" value="0x50"/>            
        <flag name="left" value="0x03"/>            
        <flag name="right" value="0x05"/>            
        <flag name="center_vertical" value="0x10"/>            
        <flag name="fill_vertical" value="0x70"/>            
        <flag name="center_horizontal" value="0x01"/>            
        <flag name="center" value="0x11"/>            
        <flag name="start" value="0x00800003"/>            
        <flag name="end" value="0x00800005"/>
    </attr>
    <attr format="boolean" name="titleEnabled"/>
    <attr name="title"/>
</declare-styleable>
<declare-styleable name="CollapsingToolbarLayout_Layout">
    <attr name="layout_collapseMode">            
        <enum name="none" value="0"/>            
        <enum name="pin" value="1"/>            
        <enum name="parallax" value="2"/>
    </attr>
    <attr format="float" name="layout_collapseParallaxMultiplier"/>
</declare-styleable>
  • expandedTitleMargin 展開時(shí) title 的 margin
  • expandedTitleTextAppearance 展開時(shí)候title 的文字 style
  • contentScrim 在縮放時(shí),內(nèi)容遮蓋的顏色
  • statusBarScrim 狀態(tài)欄顏色
  • toolbarId 指定了 toolbar 而已,用不用無所謂,源碼里面有就用,沒有就遍歷子 View 找到 toolbar。
  • scrimVisibleHeightTrigger 設(shè)置收起多少高度時(shí),顯示內(nèi)容遮蓋顏色
  • scrimAnimationDuration 內(nèi)容遮蓋顏色動畫持續(xù)時(shí)間
  • collapsedTitleGravity 折疊時(shí),title 的位置
  • expandedTitleGravity 展開時(shí),title 的位置
  • titleEnabled 是否開啟折疊 title
  • layout_collapseMode
  • none 跟隨滾動的手勢進(jìn)行折疊
  • parallax 視差滾動
  • pin 不動
  • layout_collapseParallaxMultiplier 滾動因子,取值0-1,1是完全不動

public methods

此處省略 N 個(gè)方法,都是和 attrs對應(yīng)的屬性修改/獲取方法。

問題

可能有些同學(xué)會遇到statusBarScrim不生效的情況,反正我是碰到過,原因是因?yàn)楸幌到y(tǒng)的 statusBar 覆蓋了,在 style 里面或者 activity 里面把狀態(tài)欄設(shè)為透明的就好。

Demo

說了這么久,寫個(gè) demo 吧,把上面講到的東西盡量用一個(gè) demo 演示出來,不過我感覺效果大家應(yīng)該都看到過~~~

AppBarLayout.gif

就一個(gè)這樣的效果吧,沒有什么特別的特色,當(dāng)然如果讓我自己手?jǐn)]我表示很操蛋~~
1.滑動 ScrollView/RecyclerView 的時(shí)候 優(yōu)先把頂部的圖片頂上去,然后固定TabLayout ,再滾動 ScrollView/RecyclerView 的內(nèi)容,下拉的時(shí)候可以設(shè)置優(yōu)先拖出圖片或者拉到頂部在拖出圖片。
2.Toolbar 的 title 伴隨滾動移動位置和改變顏色,圖片滾動到一定位置的時(shí)候會漸變一個(gè)主題色的蒙版遮蓋住。

xml 代碼實(shí)現(xiàn)

<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.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
    ...省略內(nèi)容

</android.support.v4.widget.NestedScrollView>

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:collapsedTitleTextAppearance="@style/ToolbarTextAppearanceTitle"
        app:contentScrim="@color/colorPrimary_pinkDark"
        app:expandedTitleGravity="center_horizontal|bottom"
        app:expandedTitleTextAppearance="@style/expandedToolbarTextAppearance"
        app:layout_scrollFlags="scroll|snap|enterAlways"
        app:scrimAnimationDuration="2000"
        app:scrimVisibleHeightTrigger="40dp"
        app:titleEnabled="true">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@mipmap/material_img"
            app:layout_collapseMode="parallax"
            app:layout_collapseParallaxMultiplier="0.5"/>


        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll"
            app:navigationIcon="@mipmap/abc_ic_ab_back_mtrl_am_alpha"
            app:title="湖南農(nóng)業(yè)大學(xué)校歌"/>

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

    <android.support.design.widget.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        />

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

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

源碼分析

還是寫點(diǎn)源碼分析吧,感覺不分析一下源碼就相當(dāng)于只學(xué)了一個(gè) api,以后出現(xiàn)類似的特效,然后現(xiàn)有的東西不能滿足定制,我們也能模仿這些效果自己手?jǐn)]出來。
好了,說正事~
今天的源碼分析就不一行一行的看代碼了,我們就根據(jù)上面的效果來分析怎么實(shí)現(xiàn)的把

1.滑動 ScrollView/RecyclerView 的時(shí)候 優(yōu)先把頂部的圖片頂上去,然后固定TabLayout ,再滾動 ScrollView/RecyclerView 的內(nèi)容,下拉的時(shí)候可以設(shè)置優(yōu)先拖出圖片或者拉到頂部在拖出圖片。
2.Toolbar 的 title 伴隨滾動移動位置和改變顏色,圖片滾動到一定位置的時(shí)候會漸變一個(gè)主題色的蒙版遮蓋住。

額,這里不止兩個(gè)點(diǎn),不糾結(jié)了,一個(gè)一個(gè)來吧

  • 我們給 ScrollView/RecyclerView 設(shè)置了 Behavior,在滑動的過程中,會調(diào)用 Behavior 里面的onStartNestedScroll、onNestedPreScroll、onNestedScroll、onStopNestedScroll等方法,然后 Behavior 持有對 AppBarLayout 的引用,會在這些方法里面根據(jù)狀態(tài)做一系列的事情。至于這個(gè) Behavior 是怎么調(diào)用的,我會在下一篇里面重點(diǎn)講 Behavior。
  • 這里的效果實(shí)現(xiàn)全部由CollapsingToolbarLayout,主要是 title 的位置和顏色, 然后就是mContentScrim和 mStatusBarScrim 這兩個(gè)遮蓋布的繪制,方法很簡單
    @Override
    public void draw(Canvas canvas) {
    super.draw(canvas);

    // If we don't have a toolbar, the scrim will be not be drawn in drawChild() below.
    // Instead, we draw it here, before our collapsing text.
    ensureToolbar();
    if (mToolbar == null && mContentScrim != null && mScrimAlpha > 0) {
        mContentScrim.mutate().setAlpha(mScrimAlpha);
        mContentScrim.draw(canvas);
    }

    // Let the collapsing text helper draw its text
    if (mCollapsingTitleEnabled && mDrawCollapsingTitle) {
        mCollapsingTextHelper.draw(canvas);
    }

    // Now draw the status bar scrim
    if (mStatusBarScrim != null && mScrimAlpha > 0) {
        final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
        if (topInset > 0) {
            mStatusBarScrim.setBounds(0, -mCurrentOffset, getWidth(),
                    topInset - mCurrentOffset);
            mStatusBarScrim.mutate().setAlpha(mScrimAlpha);
            mStatusBarScrim.draw(canvas);
        }
    }
    }

ensureToolbar()再次確保了有一次對子 view toolbar 的引用。然后就是三個(gè) if 控制繪制 contentScrim、CollapsingText、statusBarScrim。
其中CollapsingTextHelper保存了折疊 TextTitle 的各種繪制信息。
可能有人會問,如何控制 contentScrim,剛剛我們在 draw()的方法里面看到了判斷條件,如果mScrimAlpha>0 則繪制,那么我們可以大膽的猜測,肯定是在收縮的過程中根據(jù)高度設(shè)置 mScrimAlpha來控制顏色布的顯示與隱藏。

    final void updateScrimVisibility() {
    if (mContentScrim != null || mStatusBarScrim != null) {
        setScrimsShown(getHeight() + mCurrentOffset < getScrimVisibleHeightTrigger());
        }
    }

這個(gè)方法控制了 mScrimAlpha,getScrimVisibleHeightTrigger()方法獲取scrimVisibleHeightTrigger這個(gè)屬性大家肯定也不陌生。然后我們通過搜索發(fā)現(xiàn)updateScrimVisibility的調(diào)用在onLayout里面。
熟悉 view 繪制流程的童鞋肯這時(shí)候應(yīng)該都懂了吧。我們在滾動的時(shí)候高度是不斷發(fā)生變化的,而我們的高度發(fā)生變化則會重新 onMeasure,onMeasure 之后則會調(diào)用 onLayout,然后 onLayout里面調(diào)用updateScrimVisibility修改了 mScrimAlpha 的值,最后在 draw 方法里面繪制出來。

好了,就到這里吧,這里沒有酷炫的 demo,什么防簡書首頁、仿知乎等等,但是看懂了這些api,我相信都能夠自己動手防一個(gè)。
有點(diǎn)懶,很多應(yīng)該錄 gif 圖的都沒錄,還請諒解~
不諒解也沒事,反正你也打不到我

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評論 2 375

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