自定義view

Android自定義View

為什么要自定義View
自定義View的基本方法

自定義View的最基本的三個方法分別是: onMeasure()弓颈、onLayout()笼裳、onDraw(); View在Activity中顯示出來喜德,要經(jīng)歷測量现横、布局和繪制三個步驟奋构,分別對應(yīng)三個動作:measure手趣、layout和draw晌该。

測量:onMeasure()決定View的大小绿渣;
布局:onLayout()決定View在ViewGroup中的位置朝群;
繪制:onDraw()決定繪制這個View。
自定義控件分類
自定義View: 只需要重寫onMeasure()和onDraw()中符,在沒有現(xiàn)成的View姜胖,需要自己實現(xiàn)的時候,就使用自定義View淀散,一般繼承自View右莱,SurfaceView或其他的View
自定義ViewGroup: 則只需要重寫onMeasure()和onLayout()蚜锨,自定義ViewGroup一般是利用現(xiàn)有的組件根據(jù)特定的布局方式來組成新的組件,大多繼承自ViewGroup或各種Layout
自定義View基礎(chǔ)
視圖View主要分為以下兩類:

類別                 解釋                                                                        特點
單一視圖               即一個View隧出,如TextView                                                  不包含子View
視圖組                 即多個View組成的ViewGroup踏志,  如LinearLayout                              包含子View

View類簡介

View類是Android中各種組件的基類,如View是ViewGroup基類胀瞪,ViewGroup是繼承自View類的针余,但是在視圖組中,ViewGroup是父組件凄诞,ViewGroup父組件中會包含多個子View
View表現(xiàn)為顯示在屏幕上的各種視圖
Android中的UI都是有View和ViewGroup組成的

View的構(gòu)造函數(shù)有4個:

// 如果View是在Java代碼里面new的圆雁,則調(diào)用第一個構(gòu)造函數(shù)
public CarsonView(Context context) {
    super(context);
}
// 如果View是在.xml里聲明的,則調(diào)用第二個構(gòu)造函數(shù)
// 自定義屬性是從AttributeSet參數(shù)傳進來的
// 這個方法一般是必須重寫的帆谍,因為在LayoutInfaltor中CreateView的時候伪朽,系統(tǒng)會通過反射調(diào)用該構(gòu)造函數(shù),如果沒有重寫創(chuàng)建View的時候會報錯
public  CarsonView(Context context, AttributeSet attrs) {
    super(context, attrs);
}
// 不會自動調(diào)用
// 一般是在第二個構(gòu)造函數(shù)里主動調(diào)用
// 如View有style屬性時
public  CarsonView(Context context, AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);
}
//API21之后才使用
// 不會自動調(diào)用
// 一般是在第二個構(gòu)造函數(shù)里主動調(diào)用
// 如View有style屬性時
public  CarsonView(Context context, AttributeSet attrs, int defStyleAttr, intdefStyleRes) {
   super(context, attrs, defStyleAttr, defStyleRes);
}

View的創(chuàng)建繪制流程:

image.png

AttributeSet與自定義屬性

系統(tǒng)自帶的View可以在xml中配置屬性汛蝙,對于寫的好的自定義View同樣可以在xml中配置屬性烈涮,為了使自定義的View的屬性可以在xml中配置,需要以下4個步驟:

  1. 通過 <declare-styleable> 為自定義View添加屬性
  2. 在xml中為相應(yīng)的屬性聲明屬性值
  3. 在運行時(一般為構(gòu)造函數(shù))獲取屬性值
  4. 將獲取到的屬性值應(yīng)用到View

View視圖結(jié)構(gòu)

  1. PhoneWindow是Android系統(tǒng)中最基本的窗口系統(tǒng)窖剑,繼承自Windows類坚洽,負責(zé)管理界面顯示以及事件響應(yīng)。它是Activity與View系統(tǒng)交互的接口
  2. DecorView是PhoneWindow中的起始節(jié)點View西土,繼承于View類讶舰,作為整個視圖容器來使用。用于設(shè)置窗口屬性需了。它本質(zhì)上是一個FrameLayout跳昼,DecorView是繼承自FrameLayout的
  3. ViewRoot在Activtiy啟動時創(chuàng)建,負責(zé)管理肋乍、布局鹅颊、渲染窗口UI等等


    image.png

對于多View的視圖,結(jié)構(gòu)是樹形結(jié)構(gòu):最頂層是ViewGroup住拭,ViewGroup下可能有多個ViewGroup或View挪略,如下
圖:

image.png

一定要記住:Android系統(tǒng)無論是measure過程滔岳、layout過程還是draw過程,永遠都是從View樹的根節(jié)點開始測量或計算(即從
樹的頂端開始)挽牢,一層一層谱煤、一個分支一個分支地進行(即樹形遞歸),最終計算整個View樹中各個View禽拔,最終確
定整個View樹的相關(guān)屬性刘离。

Android坐標(biāo)系
Android的坐標(biāo)系定義為:


image.png

屏幕的左上角為坐標(biāo)原點
向右為x軸增大方向
向下為y軸增大方向
區(qū)別于一般的數(shù)學(xué)坐標(biāo)系:

View位置(坐標(biāo))描述

View的位置由4個頂點決定的室叉, 4個頂點的位置描述分別由4個值決定,請記琢蛱琛:View的位置是相對于父控件而言的

  • Top:子View上邊界到父view上邊界的距離
  • Left:子View左邊界到父view左邊界的距離
  • Bottom:子View下邊距到父View上邊界的距離
  • Right:子View右邊界到父view左邊界的距離
    位置獲取方式
    View的位置是通過view.getxxx()函數(shù)進行獲燃牒邸:(以Top為例)

// 獲取Top位置

public final int getTop() { 
  return mTop; 
} 

// 其余如下:

getLeft();    //獲取子View左上角距父View左側(cè)的距離
getBottom();   //獲取子View右下角距父View頂部的距離
getRight();   //獲取子View右下角距父View左側(cè)的距離
與MotionEvent中 get()和getRaw()的區(qū)別

//get() :觸摸點相對于其所在組件坐標(biāo)系的坐標(biāo)
event.getX();   
event.getY();
//getRaw() :觸摸點相對于屏幕默認坐標(biāo)系的坐標(biāo)
event.getRawX();  
event.getRawY();

getX()和getRawX()的區(qū)別參照下圖:

image.png

getMeasureWidth與getWidth的區(qū)別getMeasureWidth

在measure()過程結(jié)束后就可以獲取到對應(yīng)的值;
通過setMeasuredDimension()方法來進行設(shè)置的.
getWidth

在layout()過程結(jié)束后才能獲取到;
通過視圖右邊的坐標(biāo)減去左邊的坐標(biāo)計算出來的.
Android中顏色相關(guān)內(nèi)容
Android支持的顏色模式:以ARGB8888為例

View樹的繪制流程

View樹的繪制流程是誰負責(zé)的?
view樹的繪制流程是通過ViewRoot去負責(zé)繪制的恼除,ViewRoot這個類的命名有點坑踪旷,最初看到這個名字,翻譯過來是
view的根節(jié)點豁辉,但是事實完全不是這樣令野,ViewRoot其實不是View的根節(jié)點,它連view節(jié)點都算不上徽级,它的主要作用
是View樹的管理者气破,負責(zé)將DecorView和PhoneWindow“組合”起來,而View樹的根節(jié)點嚴(yán)格意義上來說只有
DecorView餐抢;每個DecorView都有一個ViewRoot與之關(guān)聯(lián)现使,這種關(guān)聯(lián)關(guān)系是由WindowManager去進行管理的;

View繪制流程如下圖:

image.png

View的添加

image.png

View的繪制流程

image.png

measure

image.png
  1. 系統(tǒng)為什么要有measure過程旷痕?
  2. measure過程都干了點什么事碳锈?
  3. 對于自適應(yīng)的尺寸機制,如何合理的測量一顆View樹苦蒿?
  4. 那么ViewGroup是如何向子View傳遞限制信息的殴胧?
  5. ScrollView嵌套ListView問題?

Layout

  1. 系統(tǒng)為什么要有l(wèi)ayout過程佩迟?
  2. layout過程都干了點什么事团滥?


    image.png

Draw

  1. 系統(tǒng)為什么要有draw過程?
  2. draw過程都干了點什么事


    image.png

LayoutParams

LayoutParams翻譯過來就是布局參數(shù)报强,子View通過LayoutParams告訴父容器(ViewGroup)應(yīng)該如何放置自己灸姊。
從這個定義中也可以看出來LayoutParams與ViewGroup是息息相關(guān)的,因此脫離ViewGroup談LayoutParams是沒
有意義的秉溉。
事實上力惯,每個ViewGroup的子類都有自己對應(yīng)的LayoutParams類,典型的如LinearLayout.LayoutParams和
FrameLayout.LayoutParams等召嘶,可以看出來LayoutParams都是對應(yīng)ViewGroup子類的內(nèi)部類

MarginLayoutParams

MarginLayoutParams是和外間距有關(guān)的父晶。事實也確實如此,和LayoutParams相比弄跌,MarginLayoutParams只是增
加了對上下左右外間距的支持甲喝。實際上大部分LayoutParams的實現(xiàn)類都是繼承自MarginLayoutParams,因為基本
所有的父容器都是支持子View設(shè)置外間距的
屬性優(yōu)先級問題 MarginLayoutParams主要就是增加了上下左右4種外間距铛只。在構(gòu)造方法中埠胖,先是獲取了
margin屬性糠溜;如果該值不合法,就獲取horizontalMargin直撤;如果該值不合法非竿,再去獲取leftMargin和
rightMargin屬性(verticalMargin、topMargin和bottomMargin同理)谋竖。我們可以據(jù)此總結(jié)出這幾種屬性的優(yōu)
先級
margin > horizontalMargin和verticalMargin > leftMargin和RightMargin红柱、topMargin和bottomMargin
屬性覆蓋問題 優(yōu)先級更高的屬性會覆蓋掉優(yōu)先級較低的屬性。此外圈盔,還要注意一下這幾種屬性上的注釋
Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value

LayoutParams與View如何建立聯(lián)系

在XML中定義View
在Java代碼中直接生成View對應(yīng)的實例對象

addView

/**
* 重載方法1:添加一個子View
* 如果這個子View還沒有LayoutParams豹芯,就為子View設(shè)置當(dāng)前ViewGroup默認的LayoutParams
 */
public void addView(View child) {
  addView(child, -1);
}
/**
* 重載方法2:在指定位置添加一個子View
* 如果這個子View還沒有LayoutParams,就為子View設(shè)置當(dāng)前ViewGroup默認的LayoutParams
* @param index View將在ViewGroup中被添加的位置(-1代表添加到末尾)
*/
public void addView(View child, int index) {
  if (child == null) {
    throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
 }
  LayoutParams params = child.getLayoutParams();
  if (params == null) {
    params = generateDefaultLayoutParams();// 生成當(dāng)前ViewGroup默認的LayoutParams
    if (params == null) {
      throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return
null");
   }
 }
  addView(child, index, params);
}
/**
* 重載方法3:添加一個子View
* 使用當(dāng)前ViewGroup默認的LayoutParams驱敲,并以傳入?yún)?shù)作為LayoutParams的width和height
*/
public void addView(View child, int width, int height) {
  final LayoutParams params = generateDefaultLayoutParams();  // 生成當(dāng)前ViewGroup默認的
LayoutParams
  params.width = width;
  params.height = height;
  addView(child, -1, params);
}
/**
* 重載方法4:添加一個子View铁蹈,并使用傳入的LayoutParams
*/
@Override
public void addView(View child, LayoutParams params) {
  addView(child, -1, params);
}
/**
* 重載方法4:在指定位置添加一個子View,并使用傳入的LayoutParams
*/
public void addView(View child, int index, LayoutParams params) {
  if (child == null) {
    throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
 }
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
  // therefore, we call requestLayout() on ourselves before, so that the child's request
  // will be blocked at our level
  requestLayout();
  invalidate(true);
  addViewInner(child, index, params, false);
}
private void addViewInner(View child, int index, LayoutParams params,
    boolean preventRequestLayout) {
 .....
  if (mTransition != null) {
    mTransition.addChild(this, child);
 }
  if (!checkLayoutParams(params)) { // ① 檢查傳入的LayoutParams是否合法
    params = generateLayoutParams(params); // 如果傳入的LayoutParams不合法众眨,將進行轉(zhuǎn)化操作
 }
  if (preventRequestLayout) { // ② 是否需要阻止重新執(zhí)行布局流程
    child.mLayoutParams = params; // 這不會引起子View重新布局(onMeasure->onLayout-
>onDraw)
 } else {
    child.setLayoutParams(params); // 這會引起子View重新布局(onMeasure->onLayout-
>onDraw)
 }
  if (index < 0) {
    index = mChildrenCount;
 }
  addInArray(child, index);
  // tell our children
  if (preventRequestLayout) {
    child.assignParent(this);
 } else {
    child.mParent = this;
 }
 .....
}

自定義LayoutParams

  1. 創(chuàng)建自定義屬性
<resources>
  <declare-styleable name="xxxViewGroup_Layout">
    <!-- 自定義的屬性 -->
    <attr name="layout_simple_attr" format="integer"/>
    <!-- 使用系統(tǒng)預(yù)置的屬性 -->
    <attr name="android:layout_gravity"/>
  </declare-styleable>
</resources>
  1. 繼承MarginLayout
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
  public int simpleAttr;
  public int gravity;
  public LayoutParams(Context c, AttributeSet attrs) {
    super(c, attrs);
    // 解析布局屬性
    TypedArray typedArray = c.obtainStyledAttributes(attrs,
R.styleable.SimpleViewGroup_Layout);
    simpleAttr =
typedArray.getInteger(R.styleable.SimpleViewGroup_Layout_layout_simple_attr, 0);
  
 gravity=typedArray.getInteger(R.styleable.SimpleViewGroup_Layout_android_layout_gravity,
-1);
    typedArray.recycle();//釋放資源
 }
  public LayoutParams(int width, int height) {
    super(width, height);
 }
  public LayoutParams(MarginLayoutParams source) {
    super(source);
 }
  public LayoutParams(ViewGroup.LayoutParams source) {
    super(source);
 }
}
  1. 重寫ViewGroup中幾個與LayoutParams相關(guān)的方法
// 檢查LayoutParams是否合法
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
  return p instanceof SimpleViewGroup.LayoutParams;
}
// 生成默認的LayoutParams
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
  return new SimpleViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
}
// 對傳入的LayoutParams進行轉(zhuǎn)化
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
  return new SimpleViewGroup.LayoutParams(p);
}
// 對傳入的LayoutParams進行轉(zhuǎn)化
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
  return new SimpleViewGroup.LayoutParams(getContext(), attrs);
}

LayoutParams常見的子類

在為View設(shè)置LayoutParams的時候需要根據(jù)它的父容器選擇對應(yīng)的LayoutParams握牧,否則結(jié)果可能與預(yù)期不一致,
這里簡單羅列一些常見的LayoutParams子類:

ViewGroup.MarginLayoutParams
FrameLayout.LayoutParams
LinearLayout.LayoutParams
RelativeLayout.LayoutParams
RecyclerView.LayoutParams
GridLayoutManager.LayoutParams
StaggeredGridLayoutManager.LayoutParams
ViewPager.LayoutParams
WindowManager.LayoutParams
MeasureSpec

測量規(guī)格,封裝了父容器對 view 的布局上的限制娩梨,內(nèi)部提供了寬高的信息( SpecMode 沿腰、 SpecSize ),SpecSize是指
在某種SpecMode下的參考尺寸狈定,其中SpecMode 有如下三種:


image.png

UNSPECIFIED 父控件不對你有任何限制颂龙,你想要多大給你多大,想上天就上天纽什。這種情況一般用于系統(tǒng)內(nèi)部措嵌,表示一種測量狀態(tài)。(這個模式主要用于系統(tǒng)內(nèi)部多次Measure的情形芦缰,并不是真的說你想要多大最后就真有多大)
EXACTLY 父控件已經(jīng)知道你所需的精確大小企巢,你的最終大小應(yīng)該就是這么大。
AT_MOST 你的大小不能大于父控件給你指定的size让蕾,但具體是多少浪规,得看你自己的實現(xiàn)。
MeasureSpecs 的意義
通過將 SpecMode 和 SpecSize 打包成一個 int 值可以避免過多的對象內(nèi)存分配探孝,為了方便操作笋婿,其提供了打包 / 解
包方法

MeasureSpec值的確定

MeasureSpec值到底是如何計算得來的呢?

image.png

子View的MeasureSpec值是根據(jù)子View的布局參數(shù)(LayoutParams)和父容器的MeasureSpec值計算得來的,具
體計算邏輯封裝在ViewGroup的getChildMeasureSpec()方法里

/**
*
* 目標(biāo)是將父控件的測量規(guī)格和child view的布局參數(shù)LayoutParams相結(jié)合顿颅,得到一個
* 最可能符合條件的child view的測量規(guī)格萌抵。 
* @param spec 父控件的測量規(guī)格
* @param padding 父控件里已經(jīng)占用的大小
* @param childDimension child view布局LayoutParams里的尺寸
* @return child view 的測量規(guī)格
*/
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
 int specMode = MeasureSpec.getMode(spec); //父控件的測量模式
 int specSize = MeasureSpec.getSize(spec); //父控件的測量大小
 int size = Math.max(0, specSize - padding);
 int resultSize = 0;
 int resultMode = 0;
 switch (specMode) {
 // 當(dāng)父控件的測量模式 是 精確模式,也就是有精確的尺寸了
 case MeasureSpec.EXACTLY:
   //如果child的布局參數(shù)有固定值元镀,比如"layout_width" = "100dp"
   //那么顯然child的測量規(guī)格也可以確定下來了绍填,測量大小就是100dp,測量模式也是EXACTLY
   if (childDimension >= 0) {
     resultSize = childDimension;
     resultMode = MeasureSpec.EXACTLY;
  }
   //如果child的布局參數(shù)是"match_parent",也就是想要占滿父控件
//而此時父控件是精確模式,也就是能確定自己的尺寸了耽梅,那child也能確定自己大小了
   else if (childDimension == LayoutParams.MATCH_PARENT) {
     resultSize = size;
     resultMode = MeasureSpec.EXACTLY;
  }
   //如果child的布局參數(shù)是"wrap_content"野崇,也就是想要根據(jù)自己的邏輯決定自己大小,
   //比如TextView根據(jù)設(shè)置的字符串大小來決定自己的大小
   //那就自己決定唄阱高,不過你的大小肯定不能大于父控件的大小嘛
   //所以測量模式就是AT_MOST,測量大小就是父控件的size
   else if (childDimension == LayoutParams.WRAP_CONTENT) {
     resultSize = size;
     resultMode = MeasureSpec.AT_MOST;
  }
   break;
 // 當(dāng)父控件的測量模式 是 最大模式,也就是說父控件自己還不知道自己的尺寸锻霎,但是大小不能超過size
 case MeasureSpec.AT_MOST:
   //同樣的,既然child能確定自己大小揪漩,盡管父控件自己還不知道自己大小旋恼,也優(yōu)先滿足孩子的需求?奄容?
   if (childDimension >= 0) {
     resultSize = childDimension;
     resultMode = MeasureSpec.EXACTLY;
  }
   //child想要和父控件一樣大冰更,但父控件自己也不確定自己大小,所以child也無法確定自己大小
   //但同樣的昂勒,child的尺寸上限也是父控件的尺寸上限size
   else if (childDimension == LayoutParams.MATCH_PARENT) {
     resultSize = size;
     resultMode = MeasureSpec.AT_MOST;
  }
   //child想要根據(jù)自己邏輯決定大小蜀细,那就自己決定唄
   else if (childDimension == LayoutParams.WRAP_CONTENT) {
     resultSize = size;
     resultMode = MeasureSpec.AT_MOST;
  }
   break;
 // Parent asked to see how big we want to be
 case MeasureSpec.UNSPECIFIED:
   if (childDimension >= 0) {
     // Child wants a specific size... let him have it
     resultSize = childDimension;
     resultMode = MeasureSpec.EXACTLY;
  } else if (childDimension == LayoutParams.MATCH_PARENT) {
     // Child wants to be our size... find out how big it should
     // be
     resultSize = 0;
     resultMode = MeasureSpec.UNSPECIFIED;
  } else if (childDimension == LayoutParams.WRAP_CONTENT) {
     // Child wants to determine its own size.... find out how
     // big it should be
     resultSize = 0;
     resultMode = MeasureSpec.UNSPECIFIED;
  }
   break;
}
 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
image.png

針對上表,這里再做一下具體的說明
對于應(yīng)用層 View 戈盈,其 MeasureSpec 由父容器的 MeasureSpec 和自身的 LayoutParams 來共同決定
對于不同的父容器和view本身不同的LayoutParams奠衔,view就可以有多種MeasureSpec。 1. 當(dāng)view采用固定寬
高的時候塘娶,不管父容器的MeasureSpec是什么归斤,view的MeasureSpec都是精確模式并且其大小遵循
Layoutparams中的大小血柳; 2. 當(dāng)view的寬高是match_parent時官册,這個時候如果父容器的模式是精準(zhǔn)模式,那么
view也是精準(zhǔn)模式并且其大小是父容器的剩余空間难捌,如果父容器是最大模式膝宁,那么view也是最大模式并且其大
小不會超過父容器的剩余空間; 3. 當(dāng)view的寬高是wrap_content時根吁,不管父容器的模式是精準(zhǔn)還是最大化员淫,
view的模式總是最大化并且大小不能超過父容器的剩余空間。 4. Unspecified模式击敌,這個模式主要用于系統(tǒng)內(nèi)
部多次measure的情況下介返,一般來說,我們不需要關(guān)注此模式(這里注意自定義View放到ScrollView的情況 需要
處理)。

來自:鑒于往事圣蝎,有資于治道

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刃宵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子徘公,更是在濱河造成了極大的恐慌牲证,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件关面,死亡現(xiàn)場離奇詭異坦袍,居然都是意外死亡,警方通過查閱死者的電腦和手機等太,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門捂齐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缩抡,你說我怎么就攤上這事奠宜。” “怎么了缝其?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵挎塌,是天一觀的道長。 經(jīng)常有香客問我内边,道長榴都,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任漠其,我火速辦了婚禮嘴高,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘和屎。我一直安慰自己拴驮,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布柴信。 她就那樣靜靜地躺著套啤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪随常。 梳的紋絲不亂的頭發(fā)上潜沦,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音绪氛,去河邊找鬼唆鸡。 笑死,一個胖子當(dāng)著我的面吹牛枣察,可吹牛的內(nèi)容都是我干的争占。 我是一名探鬼主播燃逻,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼臂痕!你這毒婦竟也來了伯襟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刻蟹,失蹤者是張志新(化名)和其女友劉穎逗旁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舆瘪,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年红伦,在試婚紗的時候發(fā)現(xiàn)自己被綠了英古。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡昙读,死狀恐怖召调,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛮浑,我是刑警寧澤唠叛,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沮稚,受9級特大地震影響艺沼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕴掏,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一障般、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盛杰,春花似錦挽荡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至逗嫡,卻和暖如春青自,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祸穷。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工性穿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雷滚。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓需曾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子呆万,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

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