Android View的工作原理

ViewRoot和DecorView

1盐股、ViewRoot是什么?

  1. ViewRoot對(duì)應(yīng)于ViewRootImpl類
  2. 是連接WindowManager和DecorView的紐帶
  3. 發(fā)起并完成View的三大流程(測(cè)量耻卡、布局疯汁、繪制)
  4. ViewRoot需要和DecorView建立聯(lián)系。

2卵酪、ViewRoot如何完成View的三大流程涛目?

WechatIMG125.jpeg
  1. ViewRoot的performTraversals()開(kāi)始View的繪制流程,依次調(diào)用performMeasure()凛澎、performLayout()和performDraw()
  2. performMeasure()最終執(zhí)行父容器的measure()方法,并依此執(zhí)行所有子View的measure方法估蹄。
  3. performLayout()和performDraw()同理

3塑煎、View三大流程的作用

  1. measure決定了View的寬/高,測(cè)量后可以通過(guò)getMeasuredWidth/Height來(lái)獲得View測(cè)量后的寬/高臭蚁,除特殊情況外該值等于View最終的寬/高
  2. layout決定了View的頂點(diǎn)坐標(biāo)以及實(shí)際View的寬/高:完成后可以通過(guò)getTop/Bottom/Left/Right獲取頂點(diǎn)坐標(biāo)最铁,并通過(guò)getWidth/Height()獲得View的最終寬/高
  3. draw決定了View的顯示,最終將View顯示出來(lái)
    MeasuredWidth/height 垮兑!= getWidth/Height()的場(chǎng)景:更改View的布局參數(shù)并進(jìn)行重新布局后冷尉,就會(huì)導(dǎo)致測(cè)量 != 實(shí)際值

4系枪、DecorView的作用

  1. DecorView是頂級(jí)View雀哨,本質(zhì)就是一個(gè)FrameLayout
  2. 包含了兩個(gè)部分,標(biāo)題欄和內(nèi)容欄
  3. 內(nèi)容欄id是content私爷,也就是activity中setContentView所設(shè)置的部分雾棺,最終將布局添加到id為content的FrameLayout中
  4. 獲取content:ViewGroup content = findViewById(R.android.id.content)
  5. 獲取設(shè)置的View:content.getChidlAt(0)

5、ViewRootIml如何和DecorView建立聯(lián)系

  1. Activity對(duì)象在ActivityThread中創(chuàng)建完畢后衬浑,會(huì)將DecorView添加到Window中
  2. 同時(shí)會(huì)創(chuàng)建ViewRootImpl捌浩,調(diào)用ViewRoot的setView方法將ViewRootImpl和DevorView建立關(guān)聯(lián)
root = new ViewRootImpl(view.getContext(), display)
root.setView(view, wparams, panelParentView)

6目溉、ViewRoot為什么要和DecorView建立關(guān)聯(lián)

  1. DecorView等View的三大流程需要通過(guò)ViewRoot完成

MeasureSpec

1偶摔、MeasureSpec是什么?

  1. MeasureSpec是一種“測(cè)量規(guī)則”或者“測(cè)量說(shuō)明書(shū)”沈堡,決定了View的測(cè)量過(guò)程
  2. View的MeasureSpec會(huì)根據(jù)自身的LayoutParamse和父容器的MeasureSpec生成助币。
  3. 最終根據(jù)View的MeasureSpec測(cè)量出View的寬/高(測(cè)量時(shí)數(shù)據(jù)并非最終寬高)

2浪听、MeasureSpec要點(diǎn)解析

  1. MeasureSpec代表一個(gè)32位int值,高2位是SpecMode奠支,低30位是SpecSize
  2. SpecMode是指測(cè)量模式
  3. SpecSize是指在某種測(cè)量模式下的大小
  4. 類MesaureSpec提供了用于SpecMode和SpecSize打包和解包的方法

3馋辈、測(cè)量模式SpecMode的類型

  • UNSPECIFIED:父容器不對(duì)View有任何限制,一般用于系統(tǒng)內(nèi)部
  • EXACTLY:精準(zhǔn)模式倍谜,View的最終大小就是SpecSize指定的值(對(duì)應(yīng)于LayoutParams的match_parent和具體的數(shù)值)
  • AT_MOST:最大值模式迈螟,大小不能大于父容器指定的值SpecSize(對(duì)應(yīng)于wrap_content)

4叉抡、MeasureSpec和LayoutParams的對(duì)應(yīng)關(guān)系

  1. View的MeasureSpec是需要通過(guò)自身的LayoutParams和父容器的MeasureSpec一起才能決定
  2. DecorView(頂級(jí)View)是例外,其本身MeasureSpec由窗口尺寸和自身LayoutParams共同決定
  3. MeasureSpec一旦確定答毫,onMeasure中就可以確定View的測(cè)量寬/高

5褥民、普通View的Measure的創(chuàng)建規(guī)則

  1. View本身布局參數(shù)為具體dp/px數(shù)值,模式:EXACTLY洗搂,尺寸:自身尺寸(不管父容器的MeasureSpec)
  2. View為match_parent消返, 模式:EXACTLY/AT_MOST由父容器MeasureSpec決定,尺寸:父容器目前可用大小
  3. View為wrap_content耘拇,模式:AT_MOST,尺寸:父容器可用尺寸(不能超過(guò)該尺寸)
  4. 當(dāng)父容器為UNSPECIFIED時(shí)撵颊,View為具體數(shù)值時(shí)規(guī)則不變;其余match_parent/wrap_content惫叛,模式均為:UNSPECIFIED倡勇,尺寸:0
  5. UNSPECIFIED一般用于系統(tǒng)內(nèi)部多次measure的情況,不需要關(guān)注該模式嘉涌。
WechatIMG126.jpeg

View的工作流程

  1. measure:測(cè)量——確定View的測(cè)量寬/高
  2. layout:布局——確定View的最終寬/高和四個(gè)頂點(diǎn)的位置
  3. draw:繪制——將View繪制到屏幕上

1妻熊、Measure 過(guò)程

1、View的measure過(guò)程及要點(diǎn)
  1. View的measure方法是final類型方法——表明該方法無(wú)法被重載
  2. View的measure方法會(huì)調(diào)用onMeasure方法仑最,onMeasure會(huì)調(diào)用setMeasuredDimension方法設(shè)置View寬/高的測(cè)量值
2扔役、View的onMeasure源碼要點(diǎn)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //1. setMeasuredDimension方法設(shè)置View寬/高的測(cè)量值
        setMeasuredDimension(
                //2. 第一個(gè)參數(shù)是獲得的測(cè)量寬/高(通過(guò)getDefaultSize獲取)
                getDefaultSize(getSuggestedMinimumWidth(),  //3. 獲取的建議最小的寬/高
                                    widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(),
                                    heightMeasureSpec));
}
  1. setMeasuredDimension方法設(shè)置View寬/高的測(cè)量值(測(cè)量值通過(guò)getDefaultSize獲取)
  2. getDefaultSize用于獲取View的測(cè)量寬/高
3警医、View的getDefaultSize源碼要點(diǎn)(決定了View寬高的測(cè)量值)
//1. 獲取View寬和高的測(cè)量值
  public static int getDefaultSize(int size, int measureSpec) {
      int result = size;
      int specMode = MeasureSpec.getMode(measureSpec);
      int specSize = MeasureSpec.getSize(measureSpec);

      switch (specMode) {
      //2. UNSPECIFIED模式時(shí)亿胸,寬/高為第一個(gè)參數(shù)也就是getSuggestedMinimumWidth()獲取的建議最小值
      case MeasureSpec.UNSPECIFIED:
          result = size;
          break;
      //3. AT_MOST(wrap_content)和EXACTLY(match_parent/具體值dp等)這兩個(gè)模式下,View寬高的測(cè)量值為當(dāng)前View的MeasureSpec(測(cè)量規(guī)格)中指定的尺寸specsize
      case MeasureSpec.AT_MOST:
      case MeasureSpec.EXACTLY:
          result = specSize;
          break;
      }
      return result;
  }
4预皇、View的getSuggestedMinimumWidth/Height()源碼要點(diǎn)
//獲取建議的最小寬度
protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
  1. 如果View沒(méi)有背景损敷,View的最小寬度就為android:minWidth這個(gè)參數(shù)指定的值(mMinWidth),沒(méi)有指定則默認(rèn)為0
  2. 如果View有背景,會(huì)從mMinWidth和背景的最小寬度中取最大值深啤。
  3. 背景的最小寬度(getMinimumWidth())本質(zhì)就是Drawable的原始寬度(ShapeDrawable無(wú)原始寬度,BitmapDrawable有原始寬度——圖片的尺寸)
5拗馒、View的wrap_content和match_parent效果一致的原因分析
  1. 根據(jù)View的onMeasure方法中的getDefaultSize方法,我們可以發(fā)現(xiàn)在兩種模式下溯街,View的測(cè)量值等于該View的測(cè)量規(guī)格MeasureSpec中的尺寸诱桂。
  2. View的MeasureSpec本質(zhì)是由自身的LayoutParams和父容器的MeasureSpec決定的。
  3. 當(dāng)View為wrap_content時(shí)呈昔,該View的模式為AT_MOST挥等,且尺寸specSize為父容器的剩余空間大小。
  4. 當(dāng)View為match_parent時(shí)堤尾,該View的模式跟隨父容器的模式(AT_MOST/EXACTLY), 且尺寸specSize為父容器的剩余空間大小肝劲。
  5. 因此getDefaultSize中無(wú)論View是哪種模式,最終測(cè)量寬/高均等于尺寸specSize,因此兩種屬性效果是完全一樣的(View的大小充滿了父容器的剩余空間)
  6. 除非給定View固定的寬/高辞槐,View的specSize才會(huì)等于該固定值掷漱。
6、自定義View需要重寫(xiě)onMeasure方法榄檬,并寫(xiě)明兩種模式的處理方法
//1. 重寫(xiě)onMeasure卜范,特殊處理wrap_content的情況
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);

        if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
            //2. 均為wrap_content時(shí), 將值設(shè)置為android:minWidth/Height屬性指定的值
            setMeasuredDimension(mWidth, mHeight);
        }else if(widthSpecMode == MeasureSpec.AT_MOST){
            //3. 哪個(gè)為wrap_content哪個(gè)就用android:minXXX屬性給定的最小值
            setMeasuredDimension(mWidth, heightSpecSize);
        }else if(heightSpecMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSpecSize, mHeight);
        }
    }
7、ViewGroup(抽象類)的measure流程
  1. ViewGroup沒(méi)有onMeasure方法鹿榜,只定義了measureChildren方法(onMeasure根據(jù)不同布局難以統(tǒng)一)
  2. measureChildren中遍歷所有子元素并調(diào)用measureChild方法
  3. measureChild方法中會(huì)獲取子View的MeasureSpec海雪,然后調(diào)用子元素View的measure方法進(jìn)行測(cè)量
8、getChildMeasureSpec獲取子元素MeasureSpec的要點(diǎn)
  1. 子View的MeasureSpec是根據(jù)自身的LayoutParams和父容器SpecMode生成
  2. 當(dāng)子View的布局參數(shù)為wrap_content舱殿,且父容器模式為AT_MOST時(shí)奥裸,效果與子元素布局為match_parent是一樣的。因此當(dāng)子View的布局參數(shù)為wrap_content時(shí)沪袭,需要指定默認(rèn)的寬/高
9刺彩、LinearLayout的onMeasure()分析
  1. ViewGroup因?yàn)椴季值牟煌瑹o(wú)法統(tǒng)一onMeasure方法枝恋,具體內(nèi)容根據(jù)布局的不同而不同,這里直接以LinearLayout進(jìn)行分析
  2. onMeasure會(huì)根據(jù)orientation選擇measureVertical或者measureHorizontal進(jìn)行測(cè)量
  3. measureVertical本質(zhì)是遍歷子元素嗡害,并執(zhí)行子元素的measure方法焚碌,并獲得子元素的總高度以及子元素在豎直方向上的margin等。
  4. 最終LinearLayout會(huì)測(cè)量自己的大小霸妹,在orientation的方向上十电,如果布局是match_parent或者具體數(shù)值,測(cè)量過(guò)程與View一致(高度為specSize)叹螟;如果布局是wrap_content鹃骂,高度是所有子元素高度總和,且不會(huì)超過(guò)父容器的剩余空間罢绽,最終高度需要考慮在豎直方向上的padding
10畏线、如何獲取View的測(cè)量寬/高
  1. 在measure完成后,可以通過(guò)getMeasuredWidth/Height()方法良价,就能獲得View的測(cè)量寬高
  2. 在一定極端情況下寝殴,系統(tǒng)需要多次measure,因此得到的值可能不準(zhǔn)確明垢,最好的辦法是在onLayout方法中獲得測(cè)量寬/高或者最終寬/高
11蚣常、如何在Activity啟動(dòng)時(shí)獲得View的寬/高
  1. Activity的生命周期與View的measure不是同步運(yùn)行,因此在onCreate/onStart/onResume均無(wú)法正確得到
  2. 若在View沒(méi)有測(cè)量好時(shí)痊银,去獲得寬高抵蚊,會(huì)導(dǎo)致最終結(jié)果為0
  3. 有四種辦法去正確獲得寬高
A. onWindowFocusChanged獲得View的寬/高
//1. View已經(jīng)初始化完畢,可以獲得寬高
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
//2. Activity得到焦點(diǎn)和失去焦點(diǎn)均會(huì)調(diào)用一次(頻繁onResume和onPause會(huì)導(dǎo)致頻繁調(diào)用)
        if(hasFocus){
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
        }
    }
B. view.post(runnable)獲得View的寬/高
//1. 通過(guò)post將一個(gè)runnable投遞到消息隊(duì)列尾部
        view.post(new Runnable() {
            @Override
//2. 等到Looper調(diào)用次runnable時(shí),View已經(jīng)完成初始化
            public void run() {
                int width = view.getMeasuredWidth();
                int height = view.getMeasuredHeight();
            }
        });
C. ViewTreeObserver獲得View的寬/高(Kotlin版)
val observer = imageView.viewTreeObserver
   //1. 使用ViewTreeObserver的接口贞绳,可以再View樹(shù)狀態(tài)改變或者View樹(shù)內(nèi)部View的可見(jiàn)性改變時(shí)谷醉,onGlobalLayout會(huì)被毀掉
   observer.addOnGlobalLayoutListener(object :ViewTreeObserver.OnGlobalLayoutListener {
           //2. 能正確獲取View寬/高
           override fun onGlobalLayout() {
           //3. 隨著View樹(shù)狀態(tài)改變,會(huì)多次調(diào)用熔酷。因此需要移除監(jiān)聽(tīng)器
               imageView.viewTreeObserver.removeGlobalOnLayoutListener(this)
               val width = imageView.measuredWidth
               val height = imageView.measuredHeight
           }
       })
D. view.measure()獲得View的寬/高(Kotlin)
  1. mathc_parent的情況下是不可以的孤紧,因?yàn)樾枰纏arent的size,這里無(wú)法獲取拒秘。
  2. 具體數(shù)值
//1. 具體數(shù)值時(shí)(dp/px),讓View重新測(cè)量
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
imageView.measure(widthMeasureSpec, heightMeasureSpec)
//2. 完成后就可以獲得寬/高
val width = imageView.width
val height = imageView.height

wrap_content

    //1. wrap_content,將specSize設(shè)置為30位二進(jìn)制的最大值 (1 << 30) - 1,讓View重新測(cè)量(在AT_MOST情況下是合理的)
    val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 shl 30) - 1, View.MeasureSpec.AT_MOST)
    val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 shl 30) - 1, View.MeasureSpec.AT_MOST)
    imageView.measure(widthMeasureSpec, heightMeasureSpec)
    //2. 完成后就可以獲得寬/高
    val width = imageView.width
    val height = imageView.height

Layout 過(guò)程

1号显、View的layout過(guò)程

  1. 使用layout方法確定View本身的位置
  2. layout中調(diào)用onLayout方法確定所有子View的位置

2、View的layout()源碼分析

  1. 調(diào)用setFrame()設(shè)置View四個(gè)定點(diǎn)位置(即初始化mLeft,mRight,mTop,mBottom的值)
  2. 之后調(diào)用onLayout確定子View位置躺酒,該方法類似于onMeasure押蚤,View和ViewGroup中均沒(méi)有實(shí)現(xiàn),具體實(shí)現(xiàn)與具體布局有關(guān)羹应。

3揽碘、LinearLayout的onLayout方法

  1. 根據(jù)orientation選擇調(diào)用layoutVertical或者layoutHorizontal
  2. layoutVertical中會(huì)遍歷所有子元素并調(diào)用setChildFrame(里面直接調(diào)用子元素的layout方法)
  3. 層層傳遞下去完成了整個(gè)View樹(shù)的layout過(guò)程
  4. setChildFrame中的寬/高實(shí)際就是子元素的測(cè)量寬/高(getMeasure…后直接傳入)

4、View的測(cè)量寬高和最終寬高有什么區(qū)別园匹?

  1. 等價(jià)于getMeasuredWidth和getWidth有什么區(qū)別
  2. getWidth = mRight - mLeft雳刺,結(jié)合源碼測(cè)量值和最終值是完全相等的。
  3. 區(qū)別在于:測(cè)量寬高形成于measure過(guò)程裸违,最終寬高形成于layout過(guò)程(賦值時(shí)機(jī)不同)
  4. 也有可能導(dǎo)致兩者不一致:強(qiáng)行重寫(xiě)View的layout方法掖桦,在傳參方面改變最終寬/高(雖然這樣毫無(wú)實(shí)際意義)
  5. 某些情況下,View需要多次measure才能確定自己的測(cè)量寬高供汛,在前幾次測(cè)量中等到的值可能有最終寬高不一致枪汪。但是最終結(jié)果上,測(cè)量寬高=最終寬高

Draw 過(guò)程

1怔昨、draw的步驟

  1. 繪制背景(drawBackground(canvas))
  2. 繪制自己(onDraw)
  3. 繪制children(dispatchDraw)-遍歷調(diào)用所有子View的draw方法
  4. 繪制裝飾(如onDrawScollBars)

2雀久、View特殊方法setWillNotDraw

  1. 若一個(gè)View不繪制任何內(nèi)容,需要將該標(biāo)志置為true趁舀,系統(tǒng)會(huì)進(jìn)行相應(yīng)優(yōu)化
  2. 默認(rèn)View不開(kāi)啟該標(biāo)志位
  3. 默認(rèn)ViewGroup開(kāi)啟該標(biāo)志位
  4. 如果我們自定義控件繼承自ViewGroup并且本身不進(jìn)行繪制時(shí)赖捌,就可以開(kāi)啟該標(biāo)志位
  5. 當(dāng)該ViewGroup明確通過(guò)onDraw繪制內(nèi)容時(shí),就需要顯式關(guān)閉WILL_NOT_DRAW標(biāo)志位矮烹。

參照大牛的文章寫(xiě)了個(gè)Android自定義View-漸變的溫度指示器巡蘸,融入自定義處理wrap_content,和padding 的情況,歡迎指正~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末擂送,一起剝皮案震驚了整個(gè)濱河市悦荒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘹吨,老刑警劉巖搬味,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡碰纬,警方通過(guò)查閱死者的電腦和手機(jī)萍聊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悦析,“玉大人寿桨,你說(shuō)我怎么就攤上這事∏看鳎” “怎么了亭螟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骑歹。 經(jīng)常有香客問(wèn)我预烙,道長(zhǎng),這世上最難降的妖魔是什么道媚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任扁掸,我火速辦了婚禮,結(jié)果婚禮上最域,老公的妹妹穿的比我還像新娘谴分。我一直安慰自己,他們只是感情好镀脂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布牺蹄。 她就那樣靜靜地躺著,像睡著了一般狗热。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上虑省,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天匿刮,我揣著相機(jī)與錄音,去河邊找鬼探颈。 笑死熟丸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伪节。 我是一名探鬼主播光羞,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怀大!你這毒婦竟也來(lái)了纱兑?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤化借,失蹤者是張志新(化名)和其女友劉穎潜慎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铐炫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年垒手,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倒信。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡科贬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鳖悠,到底是詐尸還是另有隱情榜掌,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布竞穷,位于F島的核電站唐责,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘾带。R本人自食惡果不足惜鼠哥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望看政。 院中可真熱鬧朴恳,春花似錦、人聲如沸允蚣。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嚷兔。三九已至森渐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冒晰,已是汗流浹背同衣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壶运,地道東北人耐齐。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蒋情,于是被迫代替她去往敵國(guó)和親埠况。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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