iOS使用代码进行AutoLayout自动布局

1.简介

  • 1.在以前的iOS代码中是如何设置布局UI界面的?
    经常编写大量的坐标计算代码,为了保证在3.5 inch和4.0 inch屏幕上都能有完美的UI界面效果,有时还需要分别为2种屏幕编写不同的坐标计算代码(即传说中的“屏幕适配”)。
  • 2.什么是AutoLayout?
    AutoLayout是一种自动布局技术,专门用来布局UI界面。AutoLayout自iOS6开始引入,由于xcode4的不给力,当时并没有得到很大的推广。自iOS7开始,AutoLayout的开发效率得到很大的提升,苹果官方也推荐开发者尽量使用AutoLayout来进行UI布局。AutoLayout能够很轻松的解决屏幕适配的问题。
  • 3.Autoresizing
    在AutoLayout之前,有Autoresizing可以做屏幕适配,但是它局限性较大,很多工作无法完成,相比之下,AutoLayout的功能比Autoresizing强大得多。

2.代码实现AutoLayout

代码实现AutoLayout要注意的点:
1.要先禁止视图的autoresizing功能,视图的下列属性设置为NO:
view.translatesAutoresizingMaskIntoConstraints = NO;
2.添加约束之前,一定保证相关控件都已经添加到各自的父视图上。
3.不再需要为视图设置frame。

代码实现AutoLayout的步骤如下:
1.创建一个NSLayoutConstraint类的实例对象作为具体的约束对象。
1.将这个具体的约束对象添加到对应的视图上去。

1.创建一个NSLayoutConstraint类的实例对象作为具体的约束对象

NSLayoutConstraint类创建具体的约束对象有两种方法:

+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *,id> *)views;

我们先来看第一种方法,第二种方法我们在后面再讲。

+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

这个方法创建了一个约束对象,这个约束对象定义了View1的attribute1属性和View2的attribute2属性之间的关系。他们之间有这样的一个线性等式的关系:
item1.attribute1 = multiplier × item2.attribute2 + constant

  • view1
    就是约束左边的视图,也就是上面核心等式中的item1
  • attr1
    上面核心等式左边的视图的属性,它是NSLayoutAttribute的枚举类型。
    NSLayoutAttribute:
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
    NSLayoutAttributeLeft = 1,
    NSLayoutAttributeRight,
    NSLayoutAttributeTop,
    NSLayoutAttributeBottom,
    NSLayoutAttributeLeading,
    NSLayoutAttributeTrailing,
    NSLayoutAttributeWidth,
    NSLayoutAttributeHeight,
    NSLayoutAttributeCenterX,
    NSLayoutAttributeCenterY,
    NSLayoutAttributeLastBaseline,
    NSLayoutAttributeBaseline NS_SWIFT_UNAVAILABLE("Use 'lastBaseline' instead") = NSLayoutAttributeLastBaseline,
    NSLayoutAttributeFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0),
    
    
    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeNotAnAttribute = 0
};
  • relation
    relation指的是左边的约束和右边的约束之间的关系,左边和右边的云总共有三种关系,即=,>=,<=。所以relation也是一个枚举值:
typedef NS_ENUM(NSInteger, NSLayoutRelation) {
    NSLayoutRelationLessThanOrEqual = -1,//<=
    NSLayoutRelationEqual = 0,//=
    NSLayoutRelationGreaterThanOrEqual = 1,//>=
};
  • view2
    约束右边的视图
  • attr2
    约束右边的视图的属性,和attr1一样是枚举值。
  • multiplier
    这个就是上面的核心等式中的multiplier,就是乘的倍数。
  • c
    就是乘的倍数后面加上的一个常量

2.将这个具体的约束对象添加到对应的视图上去

在添加约束后,要将它作用到对应的view上。
在添加到view上时要遵循以下规则:

  • 1.对于两个同层级View之间的约束关系,添加到它们的父视图上。


    相同层级.png
  • 2.对于两个不同层级View之间的约束关系,添加到它们最近的共同父View上。


    有层级关系.png
  • 3.对于有层次关系的两个View之间的约束关系,添加到层次较高的父View上。


    有层级关系.png

3.示例Demo

  • 1.创建一个红色的视图和一个蓝色的视图
    红色视图和蓝色视图等宽,为100
    红色视图和蓝色视图等高,为50
    红色视图和蓝色视图在同一水平线上,红色视图在前,红色视图距离左边界为50,蓝色视图距离右边界为50
    红色视图和蓝色视图在垂直方向上距离边界的距离都是50。
    代码:
self.redview = [[UIView alloc] init];
    _redview.backgroundColor = [UIColor redColor];
    _redview.translatesAutoresizingMaskIntoConstraints = NO;
    
    self.blueview = [[UIView alloc] init];
    _blueview.backgroundColor = [UIColor blueColor];
    _blueview.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addSubview:_redview];
    [self.view addSubview:_blueview];
    
    //redview在垂直方向上距离边界为50
    NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:50];
    
    //设置redview的宽
    NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:100];
    
    //设置reaview的高
    NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:50];
    
    //设置blueview在垂直高度上和redview等高
    NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
    
    //设置blueview和redview等宽
    NSLayoutConstraint *constraint5 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
    
    //设置blueview和redview等高
    NSLayoutConstraint *constraint6 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
    
    //redview距离左边界为50
    NSLayoutConstraint *constraint7 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:50];
    
    //blueview距离右边界为50
    NSLayoutConstraint *constraint8 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:-50];
    
    [self.view addConstraint:constraint1];
    [self.view addConstraint:constraint2];
    [self.view addConstraint:constraint3];
    [self.view addConstraint:constraint4];
    [self.view addConstraint:constraint5];
    [self.view addConstraint:constraint6];
    [self.view addConstraint:constraint7];
    [self.view addConstraint:constraint8];

这段代码看起来比较复杂,当然我们这里也是为了用AutoLayout而用,后面还有更加简便的方法。

运行结果.png
  • 2.创建一个红色视图和一个蓝色视图
    红色视图和蓝色视图的右边界对齐
    蓝色视图的宽度是红色视图的宽度的一半
    红色视图居中对齐
    红色视图在上,蓝色视图在下
    代码:
self.redview = [[UIView alloc] init];
    _redview.backgroundColor = [UIColor redColor];
    _redview.translatesAutoresizingMaskIntoConstraints = NO;
    
    self.blueview = [[UIView alloc] init];
    _blueview.backgroundColor = [UIColor blueColor];
    _blueview.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addSubview:_redview];
    [self.view addSubview:_blueview];
    
    //redview在垂直方向上距离边界为50
    NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:50];
    
    //设置redview的宽
    NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:200];
    
    //设置reaview的高
    NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:50];
    
    //设置readview居中
    NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
    
    //设置blueview宽度是redview的0.5倍
    NSLayoutConstraint *constraint5 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0];
    
    //设置blueview和redview等高
    NSLayoutConstraint *constraint6 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
    
    //redview和blueview的右边界对齐
    NSLayoutConstraint *constraint7 = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:_blueview attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
    
    //blueview顶部距离redview为50
    NSLayoutConstraint *constraint8 = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeBottom multiplier:1 constant:50];
    
    [self.view addConstraint:constraint1];
    [self.view addConstraint:constraint2];
    [self.view addConstraint:constraint3];
    [self.view addConstraint:constraint4];
    [self.view addConstraint:constraint5];
    [self.view addConstraint:constraint6];
    [self.view addConstraint:constraint7];
    [self.view addConstraint:constraint8];

运行结果:


结果.png

4.VFL语言

VFL全称是Visual Format Language,翻译过来是“可视化格式语言”
VFL是苹果公司为了简化Autolayout的编码而推出的抽象语言
VFL语法:

  • H
    水平方向的约束
  • V:
    垂直方向的约束
  • |
    边界
  • []
    方括号里面是视图
  • ()
    圆括号里面是数值
  • == , >=,<=
    表示数值的大小关系

实例:

  1. H:|-50-[button]-50-|
    表达的就是button这个控件距离左边界的距离是50,距离右边界的距离是50。
    2.H:|-20-[button(50)]
    表示button这个控件距离左边界的距离是20且button宽度是50。
    3.V:[button(40)]-20-|
    表示button这个控件的高度是40,且其距离下边界的距离是20
    4.V:[redview]-[yellowview(==redview)]
    在垂直方向上,首先有一个视图redview,然后在其下方,紧挨着有一个视图yellowview,并且redview和yellowview的高度一致

使用VFL来创建约束数组

在第二部分代码实现AutoLayout中提到过NSLayoutConstraint类创建具体的约束对象有两种方法,在那部分我们只讲了第一种方法,还有第二种方法我们没有讲。
第二种方法就是:

+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *,id> *)views;

这种方法就是使用VFL语法来创建一组约束对象。这个方法返回的是一个数组,这个数组中的对象都是NSLayoutConstraint类的实例对象。

  • format
    VFL描述语句
  • opts
    它是NSLayoutFormatOptions的枚举值
typedef NS_OPTIONS(NSUInteger, NSLayoutFormatOptions) {
    NSLayoutFormatAlignAllLeft = (1 << NSLayoutAttributeLeft),
    NSLayoutFormatAlignAllRight = (1 << NSLayoutAttributeRight),
    NSLayoutFormatAlignAllTop = (1 << NSLayoutAttributeTop),
    NSLayoutFormatAlignAllBottom = (1 << NSLayoutAttributeBottom),
    NSLayoutFormatAlignAllLeading = (1 << NSLayoutAttributeLeading),
    NSLayoutFormatAlignAllTrailing = (1 << NSLayoutAttributeTrailing),
    NSLayoutFormatAlignAllCenterX = (1 << NSLayoutAttributeCenterX),
    NSLayoutFormatAlignAllCenterY = (1 << NSLayoutAttributeCenterY),
    NSLayoutFormatAlignAllLastBaseline = (1 << NSLayoutAttributeLastBaseline),
    NSLayoutFormatAlignAllBaseline NS_SWIFT_UNAVAILABLE("Use 'alignAllLastBaseline' instead") = NSLayoutFormatAlignAllLastBaseline,
    NSLayoutFormatAlignAllFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0) = (1 << NSLayoutAttributeFirstBaseline),
    
    NSLayoutFormatAlignmentMask = 0xFFFF,
    
    /* choose only one of these three
     */
    NSLayoutFormatDirectionLeadingToTrailing = 0 << 16, // default
    NSLayoutFormatDirectionLeftToRight = 1 << 16,
    NSLayoutFormatDirectionRightToLeft = 2 << 16,  
    
    NSLayoutFormatDirectionMask = 0x3 << 16,  
    
    /* choose only one spacing format
     */
    NSLayoutFormatSpacingEdgeToEdge API_AVAILABLE(ios(11.0),tvos(11.0)) = 0 << 19, // default
    
    
    NSLayoutFormatSpacingBaselineToBaseline API_AVAILABLE(ios(11.0),tvos(11.0)) = 1 << 19,
    
    NSLayoutFormatSpacingMask API_AVAILABLE(ios(11.0),tvos(11.0)) = 0x1 << 19,
};

比如说现在的VFL语句是@"H:|-50-[redview]-20-[blueview(==redview)]-50-|",而NSLayoutFormatOptions枚举类型是NSLayoutFormatAlignAllCenterY,那么表达的意思就是在水平方向上redview距离左边界是50,blueview距离右边界是50,redview和blueview之间的水平距离是20,并且,redview和blueview的垂直高度一致opts在这里的作用就是添加一个约束

  • metrics
    这是一个字典类型的参数,这个字典的键必须是出现在VFL语句中的常量字符串,而值则是我们想要这个常量字符串想要代表的值。
  • views
    这是一个字典类型,表示VFL语句中用到的控件。比如说我们在VFL语句中为了简便起见,使用rv代表_redview,使用bv代表_blueview,那么views可以这样写:@{@"rv":_redview,@"bv":_blueview}

使用Demo

  • 1.创建一个红色的视图和一个蓝色的视图
    红色视图和蓝色视图等宽等高
    红色视图和蓝色视图在垂直高度上相等
    红色视图和蓝色视图之间的水平距离为20
    红色视图距离左边界的距离为50,蓝色视图距离右边界的距离为50
    代码:
self.redview = [[UIView alloc] init];
    _redview.backgroundColor = [UIColor redColor];
    _redview.translatesAutoresizingMaskIntoConstraints = NO;
    
    self.blueview = [[UIView alloc] init];
    _blueview.backgroundColor = [UIColor blueColor];
    _blueview.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addSubview:_redview];
    [self.view addSubview:_blueview];
    
    //设置redview距离左边界为50,blueview距离右边界为50,redview和blueview之间的水平距离为20,且redview和blueview等宽,并且redview和blueview在垂直高度上等高,怎么样?是不是一次性约束了很多条件?
    NSArray *consts1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[redview]-20-[blueview(==redview)]-50-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:@{@"redview":_redview,@"blueview":_blueview}];
    
    //垂直方向上,redView距离上边界为100,且redview的高度是80
    NSArray *consts2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[redview(80)]" options:0 metrics:nil views:@{@"redview":_redview}];
    
    //设置redview和blueview的头部在同一高度
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_redview attribute:NSLayoutAttributeTop relatedBy:0 toItem:_blueview attribute:NSLayoutAttributeTop multiplier:1 constant:0];
    [self.view addConstraints:consts1];
    [self.view addConstraints:consts2];
    [self.view addConstraint:constraint];

运行效果:


结果1.png
  • 2.创建一个红色的视图和一个蓝色的视图
    红色视图和蓝色视图的右边界对齐
    红色视图的宽度是蓝色视图的两倍
    红色视图在水平方向上居中
    红色视图在蓝色视图的上面,红色视图和蓝色视图紧挨着
    代码:
   self.redview = [[UIView alloc] init];
    _redview.backgroundColor = [UIColor redColor];
    _redview.translatesAutoresizingMaskIntoConstraints = NO;
    
    self.blueview = [[UIView alloc] init];
    _blueview.backgroundColor = [UIColor blueColor];
    _blueview.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addSubview:_redview];
    [self.view addSubview:_blueview];
    
    //水平方向上,设置redview距离右边界为50,距离左边界为50
    NSArray *consts1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[redview]-50-|" options:0 metrics:nil views:@{@"redview":_redview}];
    
    //垂直方向上,redView距离上边界为100,且redview的高度是80,下面紧挨着blueview,且redview和blueview右边界对齐
    NSArray *consts2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[redview(80)][blueview(==redview)]" options:NSLayoutFormatAlignAllRight metrics:nil views:@{@"redview":_redview, @"blueview":_blueview}];
    
    //设置blueview的宽是redview的一半
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_blueview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_redview attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0];
    [self.view addConstraints:consts1];
    [self.view addConstraints:consts2];
    [self.view addConstraint:constraint];

运行效果:

结果2.png

通过代码量我们能够清晰的看到,使用VFL来进行约束会轻松很多。

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

推荐阅读更多精彩内容