高級(jí)UI<第四十八篇>:NestedScrolling升級(jí)方案

前兩章講解了NestedScrolling的基礎(chǔ)入篮,NestedScrolling本質(zhì)上是父view和子view在滾動(dòng)的時(shí)候相互協(xié)調(diào)工作营搅。
許多App的設(shè)計(jì)大致是:
頭部一張圖片,下面是recyclerview做為NestedScrolling的子view幔崖,默認(rèn)情況下信认,頭部圖片是不顯示的奴迅,當(dāng)手指按住recyclerview慢慢向下滑動(dòng)時(shí)青责,會(huì)逐漸顯示圖片,如果當(dāng)前recyclerview已經(jīng)被向下滾動(dòng)了,那么手指滑動(dòng)recyclerview時(shí)脖隶,先滾動(dòng)recyclerview本身扁耐,當(dāng)recyclerview到頂時(shí)頭部圖片才會(huì)慢慢顯示。
這就是NestedScrolling被設(shè)計(jì)出來(lái)的初衷浩村,Android 5.0之后做葵,NestedScrollingParent和NestedScrollingChild被設(shè)計(jì)出來(lái),以完成以上功能心墅。
但是酿矢,recyclerview快速滾動(dòng)后觸發(fā)fling動(dòng)作后,recyclerview達(dá)到頂部會(huì)立即停下來(lái)怎燥,不再會(huì)繼續(xù)通過(guò)fling的慣性將頂部圖片展示出來(lái)瘫筐,也就是說(shuō),NestedScrollingParent和NestedScrollingChild對(duì)fling的設(shè)計(jì)并不友好铐姚。
好在Android 8.0之后Google彌補(bǔ)了這個(gè)缺陷策肝,推出了NestedScrollingParent2NestedScrollingChild2,他們可以非常友好的處理fling事件隐绵。

前面兩篇文章我已經(jīng)講解了NestedScrollingParent和NestedScrollingChild的各種方法的作用以及用法之众,NestedScrollingParent2NestedScrollingChild2內(nèi)方法實(shí)現(xiàn)的原理其實(shí)和前者差不多,這里偷個(gè)懶就不寫了依许。其實(shí)也沒(méi)必要自己實(shí)現(xiàn)了棺禾,在Android SDK自帶組件中有NestedScrollView組件,來(lái)看一下這個(gè)控件:

[NestedScrollView]

NestedScrollView到底是什么樣的存在峭跳?我覺(jué)得它是ScrollView替代品膘婶,因?yàn)?code>NestedScrollView具有ScrollView的所有特性,除此之外蛀醉,還支持嵌套滑動(dòng)機(jī)制悬襟,看一下源碼:

public class NestedScrollView extends FrameLayout implements NestedScrollingParent2, 
   NestedScrollingChild2, ScrollingView {

顯然,NestedScrollView已經(jīng)實(shí)現(xiàn)了NestedScrollingParent2NestedScrollingChild2拯刁,在AndroidX中推出了NestedScrollingParent3NestedScrollingChild3脊岳,比xxx2新增了水平和垂直方向消費(fèi)的距離控制。再來(lái)看一下AndroidX中NestedScrollView的源碼:

public class NestedScrollView extends FrameLayout implements NestedScrollingParent3,
    NestedScrollingChild3, ScrollingView {

說(shuō)不定以后會(huì)推出NestedScrollingParent4NestedScrollingChild4垛玻,但是這已經(jīng)不重要了割捅。

完成嵌套滑動(dòng)機(jī)制不僅僅需要一個(gè)實(shí)現(xiàn)NestedScrollingParent的父view還需要一個(gè)實(shí)現(xiàn)NestedScrollingChild的子view,NestedScrollView不僅實(shí)現(xiàn)了NestedScrollingParent夭谤,還實(shí)現(xiàn)了NestedScrollingChild,那么巫糙,NestedScrollView是否可以當(dāng)做子view朗儒?答案是可以的。
但是,結(jié)合實(shí)際app開(kāi)發(fā)套路醉锄,NestedScrollView一般做為嵌套滑動(dòng)機(jī)制的父view乏悄。
問(wèn)題來(lái)了,有什么控件可以當(dāng)作嵌套滑動(dòng)機(jī)制的子view恳不?

RecyclerView是我們常用的數(shù)據(jù)顯示控件檩小,ListView將被它所替代(之所以被替代不是因?yàn)镽ecyclerView的性能比ListView好,而是因?yàn)镽ecyclerView加入了其它方面的支持烟勋,RecyclerView支持嵌套滑動(dòng)機(jī)制就是其中之一)

RecyclerView部分源碼如下:

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {

在AndroidX版本中规求,NestedScrollingChild2升級(jí)到了NestedScrollingChild3

public class RecyclerView extends ViewGroup implements ScrollingView,
    NestedScrollingChild2, NestedScrollingChild3 {

所以,可以將RecyclerView做為嵌套滑動(dòng)機(jī)制的子view卵惦。

[NestedScrollView和RecyclerView實(shí)現(xiàn)嵌套滑動(dòng)]

首先看一下以下布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="center"
            android:src="@mipmap/top_pic" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="權(quán)威發(fā)布"
            android:textColor="@color/colorAccent"
            android:background="@color/colorPrimary"
            android:padding="20dp"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

</androidx.core.widget.NestedScrollView>

在預(yù)覽界面的效果如下:

圖片.png

但是阻肿,在真機(jī)或者模擬器顯示的效果是:

52.gif

當(dāng)recyclerview具有慣性并且慣性滑動(dòng)到recyclerview頂部時(shí),會(huì)直接現(xiàn)實(shí)頂部圖片沮尿,解決了NestedScrollingParentNestedScrollingChild會(huì)卡在recyclerview頂部的弊端丛塌,如下圖:

54.gif

NestedScrollView + RecyclerView雖然可以實(shí)現(xiàn)嵌套滑動(dòng)機(jī)制,但是卻很有問(wèn)題:

【問(wèn)題一】 NestedScrollView破壞了RecyclerView的復(fù)用機(jī)制

RecyclerView的強(qiáng)大之處就在于它具有復(fù)用機(jī)制畜疾,那么赴邻,如果它復(fù)用的特性被破壞了,那么RecyclerView將一無(wú)是處啡捶。

【問(wèn)題二】 RecyclerView初始位置異常

52.gif

如圖姥敛,第一次打開(kāi)頁(yè)面只能看到RecyclerView,頂部的圖片盡然看不到届慈,因?yàn)镽ecyclerView默認(rèn)設(shè)置焦點(diǎn)徒溪,導(dǎo)致RecyclerView滾動(dòng),在頁(yè)面復(fù)雜的情況下金顿,也能還會(huì)導(dǎo)致頭部和RecyclerView跳動(dòng)臊泌,在網(wǎng)絡(luò)上存在大量的解決方案,但是揍拆,我認(rèn)為NestedScrollView下嵌套R(shí)ecyclerView本身就是錯(cuò)誤的渠概。

不管是NestedScrollView還是RecyclerView,它們都實(shí)現(xiàn)了ScrollingView接口嫂拴,所以NestedScrollViewRecyclerView都具備滾動(dòng)特性播揪,既然都具備滾動(dòng)特性,那為什么還要嵌套筒狠?猪狈?

我們看一下這樣的布局,如下:

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
        
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

當(dāng)兩種不同數(shù)據(jù)的集合被要求放入一個(gè)列表下時(shí)辩恼,有些研發(fā)人員為了省事雇庙,便擅作主張的寫了這樣的布局谓形,為了能夠讓兩個(gè)RecyclerView一起滾動(dòng),便添加了NestedScrollView疆前,修改后的代碼如下:

<androidx.core.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="center"
            android:src="@mipmap/top_pic" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="權(quán)威發(fā)布"
            android:textColor="@color/colorAccent"
            android:background="@color/colorPrimary"
            android:padding="20dp"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

</androidx.core.widget.NestedScrollView>

然而寒跳,這樣寫破壞了RecyclerView自身的慣性滑動(dòng),上下兩個(gè)RecyclerView的fling事件無(wú)法被觸發(fā)竹椒,為了解決這個(gè)問(wèn)題童太,解決這個(gè)問(wèn)題也簡(jiǎn)單,將兩個(gè)RecyclerView分別設(shè)置如下屬性即可:

    mRecyclerView.setNestedScrollingEnabled(false);

這下胸完,終于完成了需求书释。

但是,我想說(shuō)舶吗,如果程序員這樣設(shè)計(jì)是及其不負(fù)責(zé)任的行為征冷,或者他的技能等級(jí)沒(méi)有達(dá)到一定的水平。NestedScrollView嵌套RecyclerView的做法是不可取的誓琼,即使能解決一系列沖突問(wèn)題检激,那么性能方面怎么說(shuō)?NestedScrollView破壞了RecyclerView的復(fù)用功能腹侣。

既然叔收,NestedScrollView嵌套RecyclerView的做法不可取,那么應(yīng)該怎么完美實(shí)現(xiàn)嵌套滑動(dòng)機(jī)制呢傲隶?

[CoordinatorLayout控件]

我們可以使用CoordinatorLayout控件替換上文的NestedScrollView饺律,老規(guī)矩,看一下源碼

public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent2 {

在AndroidX后支持NestedScrollingParent3

public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent2,
    NestedScrollingParent3 {

CoordinatorLayout是專門為嵌套滑動(dòng)機(jī)制設(shè)計(jì)的跺株,CoordinatorLayout控件必須和Behavior一起使用复濒。

在這里需要聲明一下:目前而言,CoordinatorLayout & Behavior是實(shí)現(xiàn)嵌套滑動(dòng)的最優(yōu)方案乒省,其中經(jīng)常使用自定義Behavior巧颈。

自定義Behavior的講解先放一放,文章后面會(huì)講到袖扛。

說(shuō)到Behavior砸泛,我想說(shuō),Android有自帶的Behavior蛆封,AppBarLayout控件是Android中自帶Behavior的控件唇礁,老規(guī)矩,簡(jiǎn)單看一下它的源碼:

@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {

從源碼中可以看到

CoordinatorLayout.DefaultBehavior是自定義注解惨篱,AppBarLayout.Behavior.class是這個(gè)注解想要傳遞的值盏筐,點(diǎn)開(kāi)這個(gè)注解,發(fā)現(xiàn)在CoordinatorLayout控件類中自定義了這樣一個(gè)注解:

@Deprecated
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultBehavior {
    Class<? extends Behavior> value();
}

即使這個(gè)注解在AndroidX中是過(guò)時(shí)的砸讳,但是這并不是一個(gè)巧合琢融。AppBarLayout通過(guò)自定義注解的方式將“AppBarLayout.Behavior.class”傳遞給CoordinatorLayout控件楷拳,在CoordinatorLayout控件中通過(guò)反射機(jī)制獲取Behavior對(duì)象

圖片.png

如上圖所示,這個(gè)Behavior必須是Behavior的子類吏奸。

CoordinatorLayout中,有這樣一個(gè)方法:

LayoutParams getResolvedLayoutParams(View child) {
    final LayoutParams result = (LayoutParams) child.getLayoutParams();
    if (!result.mBehaviorResolved) {
        if (child instanceof AttachedBehavior) {
            Behavior attachedBehavior = ((AttachedBehavior) child).getBehavior();
            if (attachedBehavior == null) {
                Log.e(TAG, "Attached behavior class is null");
            }
            result.setBehavior(attachedBehavior);
            result.mBehaviorResolved = true;
        } else {
            // The deprecated path that looks up the attached behavior based on annotation
            Class<?> childClass = child.getClass();
            DefaultBehavior defaultBehavior = null;
            while (childClass != null
                    && (defaultBehavior = childClass.getAnnotation(DefaultBehavior.class))
                    == null) {
                childClass = childClass.getSuperclass();
            }
            if (defaultBehavior != null) {
                try {
                    result.setBehavior(
                            defaultBehavior.value().getDeclaredConstructor().newInstance());
                } catch (Exception e) {
                    Log.e(TAG, "Default behavior class " + defaultBehavior.value().getName()
                            + " could not be instantiated. Did you forget"
                            + " a default constructor?", e);
                }
            }
            result.mBehaviorResolved = true;
        }
    }
    return result;
}

這段代碼比較簡(jiǎn)單陶耍,如果子View實(shí)現(xiàn)了AttachedBehavior奋蔚,可以直接獲取Behavior,并將Behavior設(shè)置到view的屬性中烈钞,否則讀取CoordinatorLayout控件的子view泊碑,如果存在Behavior的自定義注解,則采用反射機(jī)制獲取自定義注解中的傳值毯欣,這個(gè)傳值就是Behavior馒过,最后將Behavior設(shè)置到view的屬性中。

看一下這個(gè)布局:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="visible">

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="center"
            app:layout_scrollFlags="scroll"
            android:src="@mipmap/top_pic" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="權(quán)威發(fā)布"
            android:textColor="@color/colorAccent"
            android:background="@color/colorPrimary"
            android:padding="20dp"
            android:textAlignment="center"
            android:textSize="20sp"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>



</androidx.coordinatorlayout.widget.CoordinatorLayout>

這個(gè)布局被CoordinatorLayout包裹酗钞,CoordinatorLayout有兩個(gè)子view腹忽,分別是AppBarLayout和RecyclerView,在RecyclerView的屬性中看到了這樣一句話:

app:layout_behavior="@string/appbar_scrolling_view_behavior"

layout_behavior是系統(tǒng)自定義屬性砚作,appbar_scrolling_view_behavior是系統(tǒng)資源文件中的字符串窘奏,這個(gè)字符串如下:

<string name="appbar_scrolling_view_behavior" translatable="false">
    com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior</string>

到這里,我想這個(gè)邏輯就完全貫通了葫录,邏輯是:(重要)

CoordinatorLayout獲取子view屬性時(shí)着裹,首先判斷這個(gè)子view是否直接或間接實(shí)現(xiàn)了AttachedBehavior,
顯然米同,RecyclerView并沒(méi)有繼承AttachedBehavior骇扇,從而走到else分支,讀取RecyclerView的所有屬性面粮,發(fā)現(xiàn)了一個(gè)默認(rèn)的Behavior少孝,
這個(gè)Behavior就是`AppBarLayout$ScrollingViewBehavior`,也就是說(shuō)但金,AppBarLayout的內(nèi)部類`ScrollingViewBehavior`韭山。

ScrollingViewBehavior間接繼承于CoordinatorLayout.Behavior

以上xml布局的效果如下:

55.gif

那么冷溃,自定義Behavior該怎么實(shí)現(xiàn)呢钱磅?

自定義Behavior需要實(shí)現(xiàn)layoutDependsOnonDependentViewChanged方法,我已經(jīng)寫好似枕,如下:

public class MyBehavior extends CoordinatorLayout.Behavior {

    //必須要寫構(gòu)造方法
    public MyBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        //我們這里監(jiān)聽(tīng)的是一個(gè)RecyclerView盖淡,當(dāng)RecyclerView變化后,捕獲
        return dependency instanceof AppBarLayout || super.layoutDependsOn(parent, child, dependency);
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        //偏移量
        int offset = dependency.getBottom() - child.getTop();
        child.setTranslationY(offset);
        return false;
    }
}

layoutDependsOn決定依賴的對(duì)象凿歼,這個(gè)demo的RecyclerView必須依賴AppBarLayout來(lái)變化褪迟,當(dāng)RecyclerView滑動(dòng)到頂部時(shí)冗恨,依賴對(duì)象AppBarLayout會(huì)發(fā)生變化,這時(shí)onDependentViewChanged被執(zhí)行味赃,相應(yīng)的修改RecyclerView的位置掀抹。

使用這個(gè)自定義Behavior有兩種方法:

[方法一]

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior=".MyBehavior"/>

這種方式在AndroidX被放棄,被另一種方式替代心俗,請(qǐng)看方法二傲武。

[方法二]

public class MyRecyclerView extends RecyclerView implements CoordinatorLayout.AttachedBehavior {

    private Context context;
    private AttributeSet attrs;

    public MyRecyclerView(@NonNull Context context) {
        this(context, null);
    }

    public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        this.attrs = attrs;
    }


    @NonNull
    @Override
    public CoordinatorLayout.Behavior getBehavior() {
        return new MyBehavior(context, attrs);
    }
}

自定義一個(gè)MyRecyclerView,getBehavior的返回值是MyBehavior城榛,在xml中的代碼如下:

<com.juexing.nestedscrollingdemo.MyRecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

這個(gè)Behavior的效果和Android自帶Behavior是一致的揪利,然而,修改MyBehavior中的代碼可以實(shí)現(xiàn)其它效果狠持,顯然疟位,自定義Behavior的擴(kuò)展性更高,在以后的開(kāi)發(fā)中喘垂,基本上都會(huì)使用自定義Behavior來(lái)完成相應(yīng)的需求甜刻。

AppBarLayout布局內(nèi)有兩個(gè)view,分別是ImageView和TextView正勒,ImageView被設(shè)置了滾動(dòng)標(biāo)志

        app:layout_scrollFlags="scroll"

而TextView卻沒(méi)有罢吃,所以只有ImageView被滾動(dòng)尿招。

那么里覆,如果變動(dòng)一下需求,當(dāng)ImageView漸漸消失后车荔,TextView從上而下慢慢顯示出來(lái)帽借,這個(gè)效果怎么實(shí)現(xiàn)呢?

其實(shí)很簡(jiǎn)單,重新自定義一個(gè)Behavior孤澎,將AppBarLayout和TextView產(chǎn)生依賴寂祥,代碼如下:

public class MyBehavior2 extends CoordinatorLayout.Behavior {

    //必須要寫構(gòu)造方法
    public MyBehavior2(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        //我們這里監(jiān)聽(tīng)的是一個(gè)RecyclerView惜犀,當(dāng)RecyclerView變化后莉御,捕獲
        return dependency instanceof AppBarLayout || super.layoutDependsOn(parent, child, dependency);
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

        //偏移量
        float offset = -child.getHeight();

        //獲取TextView的高度
        int textHeight = child.getHeight();
        //獲取AppBarLayout的高度
        int appBarLayoutHeight = dependency.getHeight();

        if(appBarLayoutHeight > textHeight){
            offset = (Math.abs(dependency.getY()) * textHeight / (appBarLayoutHeight - textHeight)) - textHeight;
            if(offset > 0){
                offset = 0;
            }
        }else{
            //這里自由發(fā)揮噪奄,就不寫了
        }
        child.setTranslationY(offset);
        return false;
    }
}

xml布局代碼如下:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="visible"
        android:orientation="vertical"
        app:elevation="0dp">

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="center"
            app:layout_scrollFlags="scroll"
            android:src="@mipmap/top_pic" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior=".MyBehavior"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="權(quán)威發(fā)布"
        android:textColor="@color/colorAccent"
        android:background="@color/colorPrimary"
        android:padding="20dp"
        android:textAlignment="center"
        app:layout_behavior=".MyBehavior2"
        android:textSize="20sp"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

效果如下:

57.gif

如果加上透明度的話,只需要在代碼中添加透明度即可:

圖片.png

效果如下:

56.gif

最后都毒,有關(guān)layout_scrollFlags屬性的配置色罚,可以查看這篇文章:

http://www.reibang.com/p/f3a2fed6fd6e

[本章完...]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市账劲,隨后出現(xiàn)的幾起案子戳护,更是在濱河造成了極大的恐慌,老刑警劉巖瀑焦,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腌且,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡榛瓮,警方通過(guò)查閱死者的電腦和手機(jī)铺董,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)禀晓,“玉大人精续,你說(shuō)我怎么就攤上這事〈饫粒” “怎么了重付?”我有些...
    開(kāi)封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)凫乖。 經(jīng)常有香客問(wèn)我确垫,道長(zhǎng),這世上最難降的妖魔是什么帽芽? 我笑而不...
    開(kāi)封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任森爽,我火速辦了婚禮,結(jié)果婚禮上嚣镜,老公的妹妹穿的比我還像新娘爬迟。我一直安慰自己,他們只是感情好菊匿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布付呕。 她就那樣靜靜地躺著,像睡著了一般跌捆。 火紅的嫁衣襯著肌膚如雪徽职。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天佩厚,我揣著相機(jī)與錄音姆钉,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛潮瓶,可吹牛的內(nèi)容都是我干的陶冷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼毯辅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼埂伦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起思恐,我...
    開(kāi)封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沾谜,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后胀莹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體基跑,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年描焰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了媳否。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡栈顷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嵌巷,到底是詐尸還是另有隱情萄凤,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布搪哪,位于F島的核電站靡努,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏晓折。R本人自食惡果不足惜惑朦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漓概。 院中可真熱鬧漾月,春花似錦、人聲如沸胃珍。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)觅彰。三九已至吩蔑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間填抬,已是汗流浹背烛芬。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赘娄。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓仆潮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親擅憔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸵闪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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