AutoLayout

1.AutoLayout是什么耸别?

在Auto Layout之前,不論是在IB里拖放,還是在代碼中寫件舵,每個UIView都會有自己的frame屬性,來定義其在當(dāng)前視圖中的位置和尺寸脯厨。

UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 10, 10)];
[self.view addSubview:view];

使用AutoLayout的話铅祸,就變?yōu)榱耸褂眉s束條件來定義view的位置和尺寸。我們用"這個view距離底部10像素合武,距離頂部10像素临梗,距離左邊10像素,距離y右邊像素"或"label A右邊緣和button B左邊緣有20點的空白空間稼跳。"這樣來描述view盟庞。

這樣最大好處是可以解決了不同分辨率和屏幕尺寸下view的適配問題,另外也簡化了旋轉(zhuǎn)時view的位置的定義汤善,原來在底部之上10像素居中的view什猖,不論在旋轉(zhuǎn)屏幕或是更換設(shè)備,始終還在底部之上10像素居中的位置红淡,不會發(fā)生變化不狮。

使用AutoLayout另一個重要的好處就是本地化。比如各自語言中中的文本寬度不同適配起來是一件很麻煩的事在旱。AutoLayout能根據(jù)label需要顯示的內(nèi)容自動改變label的大小摇零。

2.AutoLayout和Autoresizing Mask的區(qū)別

如果你以前一直是代碼寫UI的話,你肯定寫過UIViewAutoresizingFlexibleWidth之類的枚舉桶蝎;如果你以前用IB比較多的話驻仅,一定注意到過每個view的size inspector中都有一個紅色線條的Autoresizing的指示器和相應(yīng)的動畫縮放的示意圖谅畅,這就是Autoresizing Mask。autosizing mask決定了當(dāng)一個視圖的父視圖大小改變時噪服,其自身需要做出什么改變铃彰。

autosizing mask下,你需要為每個view指定各自的寬高芯咧,并添加和父視圖的約束條件:

AutoLayout1.png
AutoLayout2.png

但AutoLayout則看起來簡單明了多了牙捉,視圖的大小和位置再也不重要了,只有約束要緊敬飒。當(dāng)然邪铲,當(dāng)你拖一個新建的button或label到畫布上時,它會有一定的大小无拗,并且你會將它拖到某一位置带到,但這是只一個用來告訴Interface Builder如何放置約束的設(shè)計工具。

AutoLayout3.png

3.開始AutoLayout

我會從一個我們常見的用戶注冊頁面的例子講起

AutoLayout4.PNG

我們希望它在橫屏模式下也可以較好地展示出來英染。

我們在storyBoard中拖拽控件揽惹,注意當(dāng)你拖拽的時候,藍(lán)色虛線將會出現(xiàn)四康。我們應(yīng)該用這些虛線來做向?qū)虏Mㄟ^preview(點擊show the Assistant Editor,并且切換到preview即可開啟)可以看出沒有AutoLayout的時候控件擺放非常糟糕。

AutoLayout4.png
AutoLayout5.png

首先對于左上方的imageView闪金,我們希望它不管屏幕大小如何哎垦,都保持同樣的大小墨闲,所以我們需要做的是將鼠標(biāo)放在改view上潘酗,按住control鍵,并垂直拖拽日裙。效果如下:

AutoLayout5.png

我們點擊Height,這樣就規(guī)定了它的高度固定不變。同樣的道理,我們點擊Weight,這次你需要水平拖拽收苏。

現(xiàn)在我們觀察preview秆乳,你會發(fā)現(xiàn)imageview跑到左上角去了葛闷。并且imageView會出現(xiàn)橙色的線忧陪。為什么呢?因為你的AutoLayout是不完整的阱飘,你只規(guī)定了高度和寬度,你沒有規(guī)定它距離它的父view邊緣的距離是多少缰儿。將鼠標(biāo)放在改view上预麸,按住control鍵,并拖拽至最外面的view上,放開:會看到下面的選項:

AutoLayout6.png

Top Space to Superview:是指該兩個view之間保存固定高度
Center Horizontal In Container:是指該兩個view之間垂直居中
Equal Widths:保持相同寬度
Equal Heights:保持相同高度
Aspect Ratio:保存固定比例關(guān)系

很明顯我們需要點擊第一個選項和第二個選項丐巫。第二個選項和imageView自身的width相當(dāng)于規(guī)定了imageView到父view的左右邊緣長度不變。第一個選項和imageView自身的Height相當(dāng)于規(guī)定了imageView到父view的上下高度不變。因此,該imageView的約束條件就完整了。

對于下面的UITextField,我們希望它距離上面的imageView高度固定捂蕴,并且左右邊緣的距離固定昂儒。

我們將UITextField拖拽至imageView,放手如下:

AutoLayout7.png

Vertical Spacing:是指兩個view之間的垂直距離固定
Left:是指兩個view左邊對齊
Center X:是指兩個view左邊對齊
Right:是指兩個viewX軸中心對齊

我們需要點擊第一個選項來固定自身和上方imageView之間的距離蒿囤,然后我們需要固定自身和父view邊緣的距離脸侥,所以我們拖拽至父view左右邊緣,如下圖:

AutoLayout8.png
AutoLayout9.png

Leading Space to Superview:view至父view左邊緣長度(前置距離)固定
Trailing Space to Superview:view至父view右邊緣長度(尾隨距離)固定

我們對第二個UITextField以及下面的UIButton進(jìn)行同樣的操作诡渴。

當(dāng)你對下面的UIButton進(jìn)行同樣的操作后你會發(fā)現(xiàn)仍然出現(xiàn)了表示警告的橙色線恩袱,為什么呢?如果你不知道為什么谅辣,你可以看到Document Outline那里有一個黃色箭頭,點擊它萎河,你會來到下圖所示:

AutoLayout11.png

它說:你期望的view高度是30沾鳄,但現(xiàn)在它確實52吞歼,你需要修復(fù)它

你可能懷疑為什么button沒有Width約束,自動布局是為何知道button有多寬(30)的?

事情是這樣的:button自己是知道自己有多寬。它根據(jù)自己的title加上一些padding就行了惩淳。如果你為button的title設(shè)置更大的字號,它會自動調(diào)整它的寬度频敛。

這正是我們熟悉的intrinsic content size任洞。并不是所有的控制器都有這個挪鹏,但大部分是(UILabel是一個例子)。如果一個視圖可以計算自己理想的大小齿梁,那么你就不需要為它特別指定Width或Height約束了催植。但在我們的例子中肮蛹,我希望這個button更高啊,那怎么辦创南?

點擊那個黃色的三角形你會看到:

AutoLayout12.png

Update Frame?不伦忠,我們不想它的高度變小。Update Constrains?如果你點擊這個選項的話,你會發(fā)現(xiàn)什么變化都沒有昌渤,因為在它需要你沒有在Height上設(shè)置一個約束條件物咳,也就談不上更新。那我們點擊第三個選項試試赋咽。

可以發(fā)現(xiàn)警告消失了,那我們點擊這個選項之后吨娜,XCode為我們做了什么脓匿?

AutoLayout13.png

看這里我們可以發(fā)現(xiàn),UIButton自身增加了一個高度不變的約束條件宦赠,所以警告消失了陪毡。

我們運(yùn)行看看效果如何

豎屏:

AutoLayout15.PNG

橫屏:

AutoLayout14.PNG

嗯,豎屏看起來還不錯勾扭,橫屏看起來不是太好毡琉,UIButton看不見了。這很好理解因為我們固定了控件和父view頂部的距離妙色,但橫屏下高度變小所以UIButton被擠到下面去了桅滋。那怎么辦?如果我們固定了控件和父view底部的距離身辨,很有可能會造成image在橫屏模式下被擠到上面去丐谋,所以有沒有更好的解決辦法呢。

其實上面講到的這些約束條件也是對象栅表,它們是NSLayoutConstraint對象笋鄙,所以我們可以在程序運(yùn)行是動態(tài)改變其中的約束條件,如下圖怪瓶,我們將imageView和父view的垂直距離約束條件拖動到代碼中:

AutoLayout16.png

在ViewController.m中寫下以下代碼:

-(void)viewWillLayoutSubviews{
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){
        self.imageViewToViewSpace.constant = 30;
    }
    else{
        self.imageViewToViewSpace.constant = 82;
    }
}

效果看上去還不錯:

AutoLayout17.PNG

4.稍微復(fù)雜點的AutoLayout:

我們再將上面那個例子變得稍微復(fù)雜一點萧落,把下面的Button變?yōu)?個button,每個等寬洗贰。

我們首先為button1增加上左右3個距離寬度約束條件:

為button2增加與button1等y軸找岖,與button3距離約束,將button1與button2的距離和button2和button3的距離都設(shè)置為8:

為button3增加與button2等y軸敛滋,與父view的Trailing space:

屏幕快照 2015-03-11 下午5.19.06.png

看起來好多警告许布?恩下面是重點,我們把button1绎晃,button2蜜唾,button3杂曲,設(shè)置為同樣高度同樣寬度,警告就消失了袁余。

現(xiàn)在運(yùn)行效果如下:

5.SizeClass

我們上面使用了NSLayoutConstraint的IBOutlet對象擎勘,所以我們可以在程序運(yùn)行是動態(tài)改變其中的約束條件,不過有另外一種更優(yōu)雅的方式來實現(xiàn)上面的效果:使用SizeClass颖榜。

隨著iPhone6/iPhone6 Plus的發(fā)布棚饵,現(xiàn)在蘋果生態(tài)圈中的設(shè)備尺寸也已經(jīng)變得種類繁多了。想必蘋果也意識到這一點掩完。都知道蘋果是以化繁為簡的設(shè)計哲學(xué)深入人心的噪漾,這次再一次證明了。SizeClass是對設(shè)備尺寸的一個抽象概念且蓬,現(xiàn)在任何設(shè)備的 長欣硼、寬 被簡潔地分為三種情況:普通 (Regular) 、緊密 (Compact)和任意(Any) 缅疟,這樣分别,根據(jù)長和寬不同的搭配就能產(chǎn)生 3*3=9 種不同尺寸。下圖展示個每種情況對應(yīng)的設(shè)備存淫。

1411722627166330.png

我們可以在不同的屏幕尺寸下使用不同的SizeClass,在正常情況下:

點擊 wAny,hAny可以更改需要布局的尺寸沼填,顯然橫屏的時候桅咆,高度處于壓縮的狀態(tài),(height: compact)坞笙,我們需要先對正常的布局之外岩饼,還要添加一種(wAny, hCompact)

然后我們在這個狀態(tài)下重新設(shè)置我們的布局方式,把上面的imageView的topSpace 修改為10:

你需要知道的是在這個狀態(tài)下的布局方式不會影響其它size下的布局方式薛夜,預(yù)覽效果如下:

你有沒有注意到imageView的圖片不同了呢籍茧,你是不是以為我使用了不同的image?其實是同一張圖片梯澜,只不過我們可以在Images.xcassets上對不同size下使用不同的圖片:

1.AutoLayout與UITableView

你見識到了AutoLayout的強(qiáng)大之處了吧寞冯,下面的例子讓我們把AutoLayout應(yīng)用到UITableView中,嘗試來構(gòu)建更復(fù)雜的應(yīng)用晚伙。例如下面圖片吮龄,當(dāng)UITableView中內(nèi)容不同時,使用AutoLayout來動態(tài)調(diào)整UITableCell的高度咆疗。

IMG_0920.PNG

我們新建一個UITableViewController的子類漓帚,在我們的storyBoard中添加一個TableViewController,并將它的自定義類設(shè)置為DynamicCellHeightViewController。

AutoLayout1.png

在我們的cell上添加如下imageView和Label兩個控件:

AutoLayout4.png

新建自定義的cell類CustomTableViewCell并將storyBoard中的cell關(guān)聯(lián)至該類午磁。

AutoLayout7.png

并將UILabel的屬性Lines設(shè)為了0以表示顯示多行尝抖。將cell的Identifier設(shè)置為"cell"毡们。

讓我們給這些view一點約束。在上一篇文章你已經(jīng)知道了通過按住ctrl在兩個view之間拖拽增加約束的方式昧辽,此外漏隐,我們還有其他兩種方式:用Editor\Pin和Align菜單:

AutoLayout2.png

還有在Interface Builder窗口的底部有一行這樣的按鈕:

AutoLayout3.png

從左到右分別是:對齊(Align),固定(Pin)奴迅,解決自動布局問題(Resolve Auto Layout Issues)和重定義尺寸(Resizing Behavior)青责。前三個按鈕魚Editor菜單中的對應(yīng)項有一致的功能。Resizing Behavior按鈕允許你在重新設(shè)置view的尺寸的時候取具,改變已經(jīng)添加的約束脖隶。

頂部的Spacing to nearest neighbor可以添加上下左右四個約束條件,點擊者4個T字架暇检,它們就會變成實體的紅色:

AutoLayout5.png

如上圖所示产阱,我們?yōu)閕mageView增加4個約束條件。同理我們?yōu)閘abel增加4個約束條件块仆。

AutoLayout6.png

好了构蹬,我們已經(jīng)完成了AutoLayout的布局,下面我們需要實現(xiàn)UITableView的協(xié)議悔据。

先聲明了一個NSArray變量來存放數(shù)據(jù)庄敛。

@interface DynamicCellHeightViewController ()
@property (nonatomic, strong) NSArray *tableData;
@end

@implementation DynamicCellHeightViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableData = @[@"1\n2\n3\n4\n5\n6", @"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"1"];
}

現(xiàn)在實現(xiàn)UITableViewDataSource的protocol:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableData.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    cell.label.text = self.tableData[indexPath.row];
    return cell;
}

從self.tableData中的數(shù)據(jù)我們可以看到,每一個Cell顯示的數(shù)據(jù)高度是不一樣的科汗,那么我們需要動態(tài)計算Cell的高度藻烤。由于是自動布局,所以我們需要用到一個systemLayoutSizeFittingSize:來計算UITableViewCell所占空間高度头滔。

這里有一個需要注意的問題怖亭,UITableView是一次性計算完所有Cell的高度,如果有1W個Cell坤检,那么heightForRowAtIndexPath就會觸發(fā)1W次兴猩,然后才顯示內(nèi)容。不過在iOS7以后早歇,提供了一個新方法可以避免這1W次調(diào)用倾芝,它就是estimatedHeightForRowAtIndexPath。要求返回一個Cell的估計值缺前,實現(xiàn)了這個方法蛀醉,那只有顯示的Cell才會觸發(fā)計算高度的protocol. 由于systemLayoutSizeFittingSize需要cell的一個實例才能計算,所以這兒用一個成員變量存一個Cell的實列衅码,這樣就不需要每次計算Cell高度的時候去動態(tài)生成一個Cell實例拯刁,這樣即方便也高效也少用內(nèi)存,可謂一舉三得逝段。

我們聲明一個存計算Cell高度的實例變量:

@property (nonatomic, strong) UITableViewCell *prototypeCell;

然后在viewDidLoad中初始化它:

self.prototypeCell  = [self.tableView dequeueReusableCellWithIdentifier:@"cell"];

計算Cell高度的實現(xiàn):

#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomTableViewCell *cell = (CustomTableViewCell *)self.prototypeCell;
    cell.label.text = [self.tableData objectAtIndex:indexPath.row];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    NSLog(@"h=%f", size.height + 1);
    return 1  + size.height;//加1是因為分隔線的高度
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 66;
}

運(yùn)行效果如下:

AutoLayout8.PNG

恩垛玻,好像哪里不對割捅,計算cell高度時應(yīng)該考慮頭像的高度。

如下圖帚桩,我們?yōu)轭^像和cell之間添加一個約束條件亿驾,并在右面板中將Constant設(shè)置為>=10,這樣cell的最小高度也是頭像高度位置加上10了。

AutoLayout9.png

運(yùn)行效果如下:

AutoLayout10.PNG

如果不用systemLayoutSizeFittingSize账嚎,我們也可以手動計算cell的高度莫瞬,只要計算cell中l(wèi)abel的文字高度即可,下面是該方法:

#import "NSString+addition.h"

@implementation NSString (addition)
- (CGSize)calculateSize:(CGSize)size font:(UIFont *)font {
    CGSize expectedLabelSize = CGSizeZero;
    
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
        NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle.copy};
        
        expectedLabelSize = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
    }
    else {
        expectedLabelSize = [self sizeWithFont:font
                                       constrainedToSize:size
                                           lineBreakMode:NSLineBreakByWordWrapping];
    }

    return CGSizeMake(ceil(expectedLabelSize.width), ceil(expectedLabelSize.height));
}
@end

像label這種控件會根據(jù)label中text的內(nèi)容自動調(diào)整其高度郭蕉,那如果是UITextView呢疼邀,我們需要下面的方法來返回其大小。

CGSize textViewSize = [cell.label sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];

2.Self Sizing

在iOS8中引入了一個強(qiáng)大的新特性召锈,Self Sizing.只要在viewDidLoad中加入以下這兩行代碼旁振,然后加入上面的自動布局,我們就可以把計算高度的代碼刪掉了涨岁。

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 60.0;
    self.tableView.rowHeight = UITableViewAutomaticDimension;    
}

我自己在項目中也嘗試用過Self Sizing這個特性拐袜,不過當(dāng)tableView加載特別多內(nèi)容時會有明顯的卡頓效果并且tableView有時還會上下跳動!所以我對它的使用保留謹(jǐn)慎態(tài)度梢薪。不過蹬铺,在構(gòu)建簡單的tableView時,這是一個非常好用的特性沮尿。

AutoLayout與ScrollView

ScrollView在AutoLayout上的表現(xiàn)稍微有點特殊丛塌,我們來講講。首先我們拖動一個
ScrollView到視圖中畜疾,并設(shè)置它的約束條件:x , y , width , height.

UIScrollView特殊在于:需要設(shè)置其ContentView!,所以你需要另外拖一個UIView上作為它的內(nèi)容視圖印衔。

并且設(shè)置ContentView對應(yīng)于UIScrollView的Leading Space啡捶、Trailing Space、Top Space奸焙、Bottom Space以及其width瞎暑、height.我設(shè)置Leading Space、Trailing Space与帆、Top Space了赌、Bottom Space都為 0。

在這個例子里玄糟,我們需要內(nèi)容視圖在ScrollView中滑起來勿她,而且只能垂直滑動而不能水平滑動,所以我們需要把ContentView的寬設(shè)置成和ScrollView一樣阵翎,但是高一定要大于ScrollView的高:

你可以在這里下載完整的代碼逢并。如果你覺得對你有幫助之剧,希望你不吝嗇你的star:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市砍聊,隨后出現(xiàn)的幾起案子背稼,更是在濱河造成了極大的恐慌,老刑警劉巖玻蝌,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蟹肘,死亡現(xiàn)場離奇詭異,居然都是意外死亡俯树,警方通過查閱死者的電腦和手機(jī)帘腹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聘萨,“玉大人竹椒,你說我怎么就攤上這事∶追” “怎么了胸完?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翘贮。 經(jīng)常有香客問我赊窥,道長,這世上最難降的妖魔是什么狸页? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任锨能,我火速辦了婚禮,結(jié)果婚禮上芍耘,老公的妹妹穿的比我還像新娘址遇。我一直安慰自己,他們只是感情好斋竞,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布倔约。 她就那樣靜靜地躺著,像睡著了一般坝初。 火紅的嫁衣襯著肌膚如雪浸剩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天鳄袍,我揣著相機(jī)與錄音绢要,去河邊找鬼。 笑死拗小,一個胖子當(dāng)著我的面吹牛重罪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蛆封,長吁一口氣:“原來是場噩夢啊……” “哼唇礁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惨篱,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盏筐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砸讳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琢融,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年簿寂,在試婚紗的時候發(fā)現(xiàn)自己被綠了漾抬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡常遂,死狀恐怖纳令,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情克胳,我是刑警寧澤平绩,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站漠另,受9級特大地震影響捏雌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笆搓,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一性湿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧满败,春花似錦肤频、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至米同,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摔竿,已是汗流浹背面粮。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留继低,地道東北人熬苍。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親柴底。 傳聞我的和親對象是個殘疾皇子婿脸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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