ConstraintLayout 详解

它的出现主要是为了解决布局嵌套过多的问题,以灵活的方式定位和调整小部件。从 Android Studio 2.3 起,官方的模板默认使用 ConstraintLayout,可见ConstraintLayout的重要性,约束布局非常有利于可视化编程,各种拖拽操作。但是我们实际开发中是不建议使用拖拽,这样写出来的代码维护成本更高。

RelativeLayout 也可以解决多层嵌套问题,但是ConstraintLayout更加灵活,性能更加出色。

适用场合

  1. 追求更高的性能。
    ConstraintLayout 可以有效减少布局的嵌套。绘制过程中的每个阶段都需要对视图树执行一次自顶向下的遍历操作。视图层次结构中嵌套的视图越多,设备绘制视图所需的时间和计算功耗也就越多。


    Android View 绘制过程
  2. 实现动画。
    使用ConstraintLayout可以更加简单实现复杂的动画。

属性分类

ConstraintLayout 目前有 57个属性(还在迭代),相比 LinearLayout 和 RelativeLayout 的学习成本是徒增的,在没有了解他们的属性前,看起来是非常的复杂。由于属性太多,这里把他们分类几类,这样理解起来就简单很多了。

  1. 位置约束 layout_constraintXX_toYYOf(13个)
  2. layout_constraintXX_creator(5个,无意义参数)
  3. layout_goneMarginXX(6个)
  4. 大小约束 layout_constraint[ Width | Height ]_**(10个)
  5. 宽高比例约束 layout_constraintDimensionRatio
  6. layout_constraintCircle**(3个)
  7. 绝对位置(2个)
  8. 参照物 Guideline 组件(3个)
  9. 屏障 Barrier 组件(2个)
  10. Group 组件(和Barrier共享1个)
  11. 占位符 Placeholder (1个)
  12. 其他属性
位置约束 layout_constraintXX_toYYOf(13个)

参数类型:reference|enum,这几个参数可以写@+id/xxx,也可以写parent,所以可以相对其他控件,也可以相对父控件。

这种属性是有规则的,每一个边缘都有2个,还有一个特殊的Baseline_toBaselineOf,是用于定位该控件相对其他控件的位置。如果仅仅使用这类属性布局,1个控件必须设置(左或右)和(上或下)2个属性,否则会提示异常。

  1. Left_toLeftOf
  2. Left_toRightOf
  3. Right_toRightOf
  4. Right_toLeftOf
  5. Top_toTopOf
  6. Top_toBottomOf
  7. Bottom_toBottomOf
  8. Bottom_toTopOf
  9. Start_toStartOf(适配right-to-left布局)
  10. Start_toEndOf(适配right-to-left布局)
  11. End_toEndOf(适配right-to-left布局)
  12. End_toStartOf(适配right-to-left布局)
  13. Baseline_toBaselineOf
<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="264dp"
        android:layout_marginTop="136dp"
        android:layout_marginEnd="256dp"
        android:text="button1"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Right_toLeftOf | Bottom_toTopOf"
        android:textAllCaps="false"
        app:layout_constraintBottom_toTopOf="@+id/button1"
        app:layout_constraintRight_toLeftOf="@+id/button1" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bottom_toTopOf | Left_toRightOf"
        android:textAllCaps="false"
        app:layout_constraintBottom_toTopOf="@+id/button1"
        app:layout_constraintLeft_toRightOf="@+id/button1" />
        ...
</androidx.constraintlayout.widget.ConstraintLayout>
layout_constraintXX_creator(5个,无意义参数)
  1. layout_constraintBaseline_creator
  2. layout_constraintLeft_creator
  3. layout_constraintRight_creator
  4. layout_constraintTop_creator
  5. layout_constraintBottom_creator

从源码可以看到,这几个参数是没有任何的处理,应该是可视化编辑器使用的,我们不用管这几个参数。

map.append(styleable.ConstraintLayout_Layout_layout_constraintLeft_creator, 39);
map.append(styleable.ConstraintLayout_Layout_layout_constraintTop_creator, 40);
map.append(styleable.ConstraintLayout_Layout_layout_constraintRight_creator, 41);
map.append(styleable.ConstraintLayout_Layout_layout_constraintBottom_creator, 42);
map.append(styleable.ConstraintLayout_Layout_layout_constraintBaseline_creator, 43);

...
int look = ConstraintLayout.LayoutParams.Table.map.get(attr);
int commaIndex;
switch(look) {
 case 0:
 case 39:
 case 40:
 case 41:
 case 42:
 case 43:
 default:
  break;
layout_goneMarginXX(6个)

当参照物为gone时候生效。

  1. layout_goneMarginBottom
  2. layout_goneMarginEnd
  3. layout_goneMarginLeft
  4. layout_goneMarginRight
  5. layout_goneMarginStart
  6. layout_goneMarginTop

下面的例子,两个布局方式的代码是一样的,都设置了app:layout_goneMarginLeft="100dp"app:layout_goneMarginTop="100dp",绿色的布局仅仅把button1隐藏,设置了两个属性就生效了,这几个属性和 ViewGroup layout_marginLeft的效果类似,不同的是参照物设置android:visibility="gone"时候才会生效。

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="@android:color/holo_red_dark">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button1"
            android:textAllCaps="false"
            android:visibility="visible"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="200dp"
            android:text="button2"
            android:textAllCaps="false"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Left_toRightOf | Top_toBottomOf"
            android:textAllCaps="false"
            app:layout_constraintLeft_toRightOf="@+id/button2"
            app:layout_constraintTop_toBottomOf="@+id/button1"
            app:layout_goneMarginLeft="100dp"
            app:layout_goneMarginTop="100dp" />
    </androidx.constraintlayout.widget.ConstraintLayout>
大小约束 layout_constraint[ Width | Height ]_**(10个)

在约束布局中宽高的维度 match_parent 被 0dp 代替,默认生成的大小占所有的可用空间。那么有以下几个属性可以使用:

  1. layout_constraintWidth_max(dimension|enum:wrap=-2)
  2. layout_constraintWidth_min(dimension|enum:wrap=-2)
  3. layout_constraintHeight_max(dimension|enum:wrap=-2)
  4. layout_constraintHeight_min(dimension|enum:wrap=-2)
  5. layout_constraintWidth_percent(float)
  6. layout_constraintHeight_percent(float)
  7. layout_constrainedHeight(boolean)
  8. layout_constrainedWidth(boolean)
  9. layout_constraintHeight_default(enum:spread, wrap, percent)
  10. layout_constraintWidth_default(enum:spread, wrap, percent)

XX_max 设置最大尺寸,XX_min 设置最小尺寸,XX_percent 置相对于父类的百分比。

layout_constraintHeight_default、layout_constraintWidth_default
这个属性我觉得有点多余,只有percent值有意义,但是也有其他代替方案,不建议使用。

  1. spread:从源代码中看到默认就是spread,实际效果分析,应该等价于android:layout_width="wrap_content"。
  2. wrap:等价 android:layout_width="wrap_content"(已被弃用)
  3. percent:等价 app:layout_constraintWidth_percent="1"

layout_constraintWidth_default="wrap" is deprecated.
Use layout_width="WRAP_CONTENT" and layout_constrainedWidth="true" instead.

layout_constrainedWidth、layout_constrainedHeight
上下两个布局的差别仅仅只是app:layout_constrainedWidth="false",下面的true,当width="wrap_content",如果实际宽度超过了约束的最大宽度,那么约束会失效(高同理),为了防止约束失效,增加了该属性。

layout_constraint[Horizontal | Vertical]_**(6个)
  1. layout_constraintHorizontal_bias(float)
  2. layout_constraintHorizontal_chainStyle(enum:spread, spread_inside, packed)
  3. layout_constraintHorizontal_weight(float)
  4. layout_constraintVertical_bias(float)
  5. layout_constraintVertical_chainStyle(enum:spread, spread_inside, packed)
  6. layout_constraintVertical_weight(float)

当一个控件左右都设置了约束,那么该控件距离左右的目标距离都是一样的,layout_constraintHorizontal_bias默认是0.5,当设置为0.8时候,左边的距离和右边的距离比例就变成了8:2。

<Button 
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        ...
        />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="10dp">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button1"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button2"
            app:layout_constraintHorizontal_bias="0.8"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/button1" />

    </androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
    android:paddingTop="10dp">
    <Button
        android:id="@+id/button1"
        android:layout_height="wrap_content"
        android:text="button1"
        android:layout_width="0dp"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/button2"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_height="wrap_content"
        android:text="button2"
        android:layout_width="0dp"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintLeft_toRightOf="@+id/button1"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
宽高比例约束 layout_constraintDimensionRatio(1个)

约束布局支持子控件设置宽高比,前提条件是至少需要将宽高中的一个设置为0dp。为了约束一个特定的边,基于另一个边的尺寸,可以预先附加W,或H以逗号隔开。

假设ImageView1是屏幕的宽度,希望ImageView1是以16:9的形式显示,但是在布局中无法写死Height,那么就可以给ImageView1设置app:layout_constraintDimensionRatio="H,16:9",神操作。设置宽度自适应比例也是同样的原理,app:layout_constraintDimensionRatio="W,16:9"

image.png
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/image1"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:background="@android:color/holo_red_dark"
            app:layout_constraintDimensionRatio="H,16:9"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <ImageView
            android:id="@+id/image2"
            android:layout_width="0dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_green_dark"
            app:layout_constraintDimensionRatio="W,16:9"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/image1" />
        <ImageView
            android:id="@+id/image3"
            android:layout_width="0dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_blue_dark"
            app:layout_constraintDimensionRatio="H,16:9"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/image2" />
    </androidx.constraintlayout.widget.ConstraintLayout>
layout_constraintCircle**(3个)
  1. layout_constraintCircle(reference)目标控件 ID
  2. layout_constraintCircleAngle(integer)和目标控件的角度
  3. layout_constraintCircleRadius(dimension)该控件中心 距离目标控件中心的距离。
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="100dp"
            android:layout_marginTop="100dp"
            android:text="Button"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:background="@android:color/darker_gray"
            android:gravity="center"
            android:text="0"
            app:layout_constraintCircle="@id/button1"
            app:layout_constraintCircleAngle="0"
            app:layout_constraintCircleRadius="100dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:background="@android:color/darker_gray"
            android:gravity="center"
            android:text="45"
            app:layout_constraintCircle="@id/button1"
            app:layout_constraintCircleAngle="45"
            app:layout_constraintCircleRadius="100dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
绝对位置(2个)

在布局中的绝对位置,很少会用到。

  1. layout_editor_absoluteX(dimension)
  2. layout_editor_absoluteY(dimension)
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1"
            app:layout_editor_absoluteX="50dp"
            app:layout_editor_absoluteY="50dp" />
    </androidx.constraintlayout.widget.ConstraintLayout>
参照物 Guideline 组件(3个)

Guideline 与 LinearLayout 类似可以设置水平或垂直方向,android:orientation="horizontal",android:orientation="vertical",水平方向高度为0,垂直方向宽度为0。我们可以创建一些横向的或者纵向的Guideline,在布局界面的时候可以充分利用这些辅助线,对齐我们的View,避免重复写一些marginXXX。

  1. layout_constraintGuide_begin(dimension)
  2. layout_constraintGuide_end(dimension)
  3. layout_constraintGuide_percent(float)
  4. android:orientation(vertical、horizontal)
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_begin="100dp" />
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_begin="50dp" />
        <Button
            android:text="Button"
            app:layout_constraintLeft_toLeftOf="@+id/guideline1"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </androidx.constraintlayout.widget.ConstraintLayout>
屏障 Barrier 组件(2个)

Barrier,直译为障碍、屏障。在约束布局中,可以使用属性constraint_referenced_ids属性来引用多个带约束的组件,从而将它们看作一个整体,Barrier 的介入可以完成很多其他布局不能完成的功能。

  1. constraint_referenced_ids
  2. barrierDirection(left、right、top、bottom、start、end)
<androidx.constraintlayout.widget.ConstraintLayout 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:padding="10dp">
    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="right"
        app:constraint_referenced_ids="text_view1,text_view2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/text_view1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="姓名:"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/text_view2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="联系方式:"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text_view1" />
    <EditText
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@+id/barrier"
        app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Group 组件(共享1个)

Group用于控制多个控件的可见性。

  1. constraint_referenced_ids(可以填写多个ID)
<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.Group
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="visible"
            app:constraint_referenced_ids="button1" />

        <androidx.constraintlayout.widget.Group
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            app:constraint_referenced_ids="button2,button3" />


        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button2"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toBottomOf="@id/button1" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button3"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toBottomOf="@id/button2" />
    </androidx.constraintlayout.widget.ConstraintLayout>
占位符 Placeholder

Placeholder中可设置另一个控件的id,使这个控件移动到占位符的位置。

  1. content(reference)
<androidx.constraintlayout.widget.ConstraintLayout 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:padding="10dp">

    <androidx.constraintlayout.widget.Placeholder
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="100dp"
        android:layout_marginTop="100dp"
        app:content="@+id/button1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
其他属性
  1. chainUseRtl(boolean)
  2. constraintSet(reference)
  3. emptyVisibility(gone, invisible)
  4. layout_optimizationLevel(none, standard, direct, barrier, chains, dimensions, groups)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容