翻譯:iOS 7中的自動布局教程第1部分:入門

本文內(nèi)容:參考外文學(xué)習(xí)并使用Auto Layout骤视,順便翻譯記錄鹦付。

原文


iOS 9, Xcode 7, Swift 2 環(huán)境下可以參考:

iOS 7中的自動布局教程第1部分:入門

來自Ray的注釋:教程團(tuán)隊成員 Matthijs Hollemans(iOS Apprentice系列作者)已將此教程移植到iOS 7作為 iOS 7系列 的一部分梗醇。我們希望你會喜歡知允!

設(shè)想這樣一個場景,如果你想讓你的應(yīng)用程序能夠在手機(jī)豎屏和橫屏狀態(tài)下都能正常顯示叙谨,但是調(diào)試起來卻是一件足夠令人崩潰的事情温鸽。另外,想要約束屏幕布局讓APP同時支持iPhone和iPad,是否是一件足以把你逼到絕望邊緣的事情涤垫? 別灰心姑尺,這篇文章會給你帶來好消息!

為屏幕設(shè)計一個總是能保證大小相同的用戶界面并不困難蝠猬,但如果屏幕的frame是可以改變的切蟋,UI元素的位置和大小也必須適應(yīng)這些新的尺寸變化。

到目前為止榆芦,如果你的設(shè)計是相當(dāng)復(fù)雜的柄粹,你就必須編寫大量的代碼來支持這種自適應(yīng)布局。 你會很高興聽到這再也不是個麻煩了——iOS 6給iPhone和iPad帶來了一個非常棒的新功能:自動布局(Auto Layout)匆绣。 Xcode 5和iOS 7讓它實現(xiàn)得更好驻右!如果你嘗試在Xcode 4中實現(xiàn)自動布局并想放棄時,那么你真的應(yīng)該給Xcode 5一個機(jī)會了崎淳。

Auto Layout不僅可以輕松地在應(yīng)用程序中支持不同的屏幕的尺寸堪夭,而且還可以使國際化實現(xiàn)變得非常方便。你不再需要為希望支持的每種語言創(chuàng)建新的nib文件或storyboard文件凯力,這包括從右到左的語言茵瘾,如希伯來語(Hebrew)或阿拉伯語(Arabic)。

此自動布局教程將向您介紹如何在Interface Builder中開始使用自動布局咐鹤。 在iOS 6 by Tutorials Third Edition教程中拗秘,我們將本教程向深層次推進(jìn),然后會有一個新的章節(jié)祈惶,基于這些知識雕旨,并展示如何通過代碼實現(xiàn)Auto Layout的全部功能。

提示:我們正在將基于iOS 6上的所有教程到更新到iOS 7 上——這是一個預(yù)覽版本捧请! 當(dāng)我們完成所有的更新后凡涩,更新將免費(fèi)下載到所有iOS 6的Tutorials PDF客戶手中。

所以吃著點心和你最喜歡的咖啡飲料疹蛉,準(zhǔn)備好成為一個自動布局(Auto Layout)大師吧活箕!

彈簧和支柱(Autosizing)的問題

毫無疑問你一定對autosizing masks非常熟悉 - 它也常被稱為“彈簧和支柱”模型。 autosizing masks確定了當(dāng)父視圖更改大小時可款,相應(yīng)子視圖發(fā)生的改變育韩。 它是否有靈活或固定的邊距(margins)(支柱),以及它的寬度和高度(彈簧)發(fā)生的變化闺鲸?

例如,如果子視圖使用靈活可變的寬度壁袄,當(dāng)父視圖變得更寬時,則子視圖將成比例地變寬行嗤。 如果使用固定的右邊距蛀骇,子視圖的右邊緣將始終貼著父視圖(superview)的右邊緣。

Autosizing 系統(tǒng)適用于簡單的情況屠列,但是當(dāng)你的布局變得更復(fù)雜時啦逆,它很快就會失效。 讓我們來看一個彈簧和支柱完全失效的例子笛洛。

打開Xcode 5并創(chuàng)建一個新的基于 Single View Application 模板的iPhone項目夏志。 設(shè)置應(yīng)用程序名為:StrutsProblem

1

點擊 Main.storyboard 以打開Interface Builder(界面生成器)界面。在做任何操作之前苛让,先禁用該storyboard的Auto Layout功能沟蔑。你可以在右側(cè)工具欄的六個標(biāo)簽中的第一個 File Inspector (文件檢視器)中執(zhí)行該操作。

2

取消勾選Use Autolayout狱杰。 現(xiàn)在storyboard就會使用舊的支柱和彈簧(struts-and-springs)模型.

譯者注:我在Xcode 8環(huán)境下取消勾選的對話框界面如下:

取消勾選Use Auto Layout后瘦材,會彈出如下對話框:

Trait Variations:用來聲明APP在不同設(shè)備上的不同特征。使用特征變量(Trait Variations)需要 Autolayout 支持仿畸,因此如果取消勾選Use Autolayout食棕,那么特征變量(Trait Variations)也會不可用。

禁用特征變量(Trait Variations)將文檔限制為存儲單個設(shè)備的數(shù)據(jù)错沽。用于表示目標(biāo)設(shè)備系列的性狀集合的數(shù)據(jù)將被保留簿晓,并且所有其他數(shù)據(jù)將被刪除。此外千埃,segues 將被轉(zhuǎn)換為它們的非適應(yīng)性等效憔儿。

這里我們點擊 Disable Trait Variations

注意:使用Xcode 4.5或更高版本創(chuàng)建的任何新的nib或storyboard文件將默認(rèn)開啟Auto Layout镰禾。 因為Auto Layout是iOS 6及以上系統(tǒng)的新特性皿曲,如果你想使用最新的Xcode來開發(fā)與iOS 5兼容的應(yīng)用程序,你需要通過取消選中“Use Autolayout“復(fù)選框,在任何新創(chuàng)建的nib或storyboard上禁用Auto layout吴侦。

拖動三個新視圖UIView到主視圖上屋休,并按照這樣的方式排列:

為了便于清晰理解,給每一個新視圖設(shè)置它們自己的顏色以便于區(qū)分是哪個备韧。

每個視圖距離窗口的邊框20pt; 視圖之間的距離也是20pt劫樟。 底部視圖是280pt寬,頂部的兩個視圖都是130 pt寬织堂。 所有的視圖都是254pt高叠艳。

運(yùn)行APP在 iPhone Retina 4-inch 模擬器(沒有的話也可以用iPhone SE代替)上,旋轉(zhuǎn)模擬器至橫屏狀態(tài)易阳。這時APP看起來是這樣子的附较,并不是我所期待的樣子:

注意:你可以使用菜單欄中的 Hardware\Rotate Left 和 **Rotate Right ** 選項來旋轉(zhuǎn)模擬器,或者通過按住鍵盤 ? 同時按向左或者向右的方向鍵來實現(xiàn)屏幕旋轉(zhuǎn)潦俺。

相反拒课,你想要APP在橫屏狀態(tài)下應(yīng)該是這樣的:

顯然徐勃,autosizing masks為所有三個視圖留了一些需要設(shè)置的東西。 將左上角視圖的 autosizing設(shè)置更改為:

該操作會使視圖貼著頂部和左邊緣(但不是底部和右邊緣)早像,并且當(dāng)父視圖更改其大小時會調(diào)整子視圖的寬和高僻肖。同樣,將右上角視圖的autosizing設(shè)置為:

底部視圖設(shè)置:

再次運(yùn)行APP并且旋轉(zhuǎn)至橫屏狀態(tài)卢鹦,它應(yīng)該看起來是這樣的:

已經(jīng)很接近我們想要的樣式了,但還不完全匹配。視圖之間的距離不正確荐糜〈鹩妫或者用另一種說法:視圖的大小比例并不是100%正確的务豺。問題就在于 autosizing masks 告訴子視圖當(dāng)父視圖調(diào)整大小時蚪燕,子視圖大小隨之改變汹桦,但是它無法告訴子視圖以何種方式調(diào)整大小。

你或許可以這樣設(shè)置 autosizing masks - 例如赂蠢,調(diào)整可變的寬度和高度設(shè)置(彈簧) - 但是你不會得到三個視圖之間的距離正好完全是20pt的結(jié)果第岖。

這是為什么呢

要用彈簧和支柱(springs and struts)的方法解決這個布局問題键袱,不幸的是褐健,你將不得不寫一點代碼澜汤。

在旋轉(zhuǎn)UI界面之前,之中和之后俊抵,UIKit會向您的視圖控制器發(fā)送幾個消息拍谐。 您可以截取這些消息以更改UI的布局亡蓉。 通常喷舀,你需要覆寫 viewWillLayoutSubviews 方法以更改需要重新排列的任何視圖的大小砍濒。

在這樣做之前淋肾,你首先必須聲明插座屬性來引用需要調(diào)整的視圖。

切換到輔助編輯器模式( Assistant Editor mode)(Xcode工具欄上的編輯器工具集上的中間按鈕)爸邢,然后鼠標(biāo)右擊拖動三個視圖的每個視圖到 ViewController.m 中:

分別連接每個視圖到這三個屬性:

@property (weak, nonatomic) IBOutlet UIView *topLeftView;    
@property (weak, nonatomic) IBOutlet UIView *topRightView;      
@property (weak, nonatomic) IBOutlet UIView *bottomView;     

添加以下代碼到ViewController.m 中:

- (void)viewWillLayoutSubviews
{   
// 譯者注:原文中if的判斷方法在我最新的Xcode 8中嘗試時發(fā)現(xiàn)被棄用了樊卓。
~~if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))~~
// 換用下面這個
if(UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
{    
    // 判斷設(shè)備方向:如果是橫屏模式
    CGRect rect = self.topLeftView.frame;
    rect.size.width = 254;
    rect.size.height = 130;
    self.topLeftView.frame = rect;

    rect = self.topRightView.frame;
    rect.origin.x = 294;
    rect.size.width = 254;
    rect.size.height = 130;
    self.topRightView.frame = rect;

    rect = self.bottomView.frame;
    rect.origin.y = 170;
    rect.size.width = 528;
    rect.size.height = 130;
    self.bottomView.frame = rect;
}
else
{
    CGRect rect = self.topLeftView.frame;
    rect.size.width = 130;
    rect.size.height = 254;
    self.topLeftView.frame = rect;

    rect = self.topRightView.frame;
    rect.origin.x = 170;
    rect.size.width = 130;
    rect.size.height = 254;
    self.topRightView.frame = rect;

    rect = self.bottomView.frame;
    rect.origin.y = 295;
    rect.size.width = 280;
    rect.size.height = 254;
    self.bottomView.frame = rect;
}
}

當(dāng)視圖控制器旋轉(zhuǎn)到新方向時,就會回調(diào)這段方法杠河。 它先判斷視圖控制器旋轉(zhuǎn)到的方向碌尔,并適當(dāng)調(diào)整視圖大小——在這種情況下,使用基于iPhone的已知屏幕尺寸的硬編碼偏移(將可變變量用一個固定值來代替的方法叫做hard-code)券敌。 此回調(diào)發(fā)生在動畫塊中唾戚,因此會以動畫的方式調(diào)整視圖大小。

先別運(yùn)行APP,首先你需要恢復(fù)剛才所作的所有三個視圖的 autosizing masks 設(shè)置待诅,否則自動調(diào)整機(jī)制將與您在viewWillLayoutSubviews中的設(shè)置的視圖位置和大小相沖突:

三個都還原后就可以了叹坦。 運(yùn)行APP,旋轉(zhuǎn)到橫屏狀態(tài)卑雁。 現(xiàn)在的視圖排列得很好募书。 旋轉(zhuǎn)回豎屏狀態(tài),驗證一切看起來也很好序厉。

這奏效了锐膜。代價就是,你必須為一個看起來很簡單的布局寫很多的代碼弛房。 想象一下調(diào)整一個真正復(fù)雜的布局需要花費(fèi)的工夫道盏,尤其是單個視圖以動態(tài)的方式更改大小,或者子視圖的數(shù)量是不確定的情況下文捶。

現(xiàn)在試著在3.5寸的模擬器上運(yùn)行程序荷逞。糟糕。視圖的位置和大小又錯了粹排,因為viewWillLayoutSubviews的硬編碼坐標(biāo)是基于4英寸大小的手機(jī)(320x568取代320x480)种远。你可以增加另一個if語句判斷屏幕大小,并使用不同的坐標(biāo)集顽耳,但是你可以看到這個方法很快變得不切實際坠敷。

注意:您可以采取的另一種方法是為豎屏和橫屏設(shè)置單獨的nib文件。 當(dāng)設(shè)備旋轉(zhuǎn)時射富,您從另一個nib加載視圖膝迎,并替換出現(xiàn)有的nib。 但這仍然需要非常大的工作量胰耗,它也增加了許多麻煩限次,必須設(shè)置兩個nib文件,而不是一個。 當(dāng)你使用storyboards而不是nibs時卖漫,這種方法是不切實際的费尽。

Auto Layout (自動布局)拯救猿!

現(xiàn)在羊始,你將看到如何使用自動布局實現(xiàn)相同的效果旱幼。 首先,從ViewController.m中刪除viewWillLayoutSubviews方法突委,因為該方法不用寫任何代碼速警。

選擇Main.storyboard,并在File inspector中勾選Use Autolayout為該storyboard文件開啟自動布局:

注意:自動布局始終作用于整個nib或storyboard文件鸯两。 如果選中該框,那么所有插入nib或storyboard中的視圖都將使用自動布局长豁。

運(yùn)行APP并且旋轉(zhuǎn)為橫屏狀態(tài)钧唐,它現(xiàn)在看起來是這樣的:

讓我們把Auto Layout放到Action中。 按住?鍵的同時單擊頂部的兩個視圖(綠色和黃色視圖)匠襟,以便同時選中這兩個視圖钝侠。 從Xcode的編輯器菜單中,選擇 Pin \ Widths Equal(相等寬度):

還是譯者提示:這一步操作在 Xcode 5 環(huán)境下應(yīng)該入下圖所示酸舍,但我在 Xcode 8 的環(huán)境下操作發(fā)現(xiàn)情況已經(jīng)不一樣了帅韧,菜單界面都發(fā)生了變化,Editor 里 沒有 Pin 選項了啃勉。

所以選中兩個View之后不妨可以在畫板右下角設(shè)置忽舟,之后的很多操作步驟在新Xcode環(huán)境下找不到的話你也可以在這里試試:

再次選中相同的兩個視圖,然后選擇 Editor\Pin\Horizontal Spacing(水平距離)淮阐。(即使在執(zhí)行第一次Pin操作后兩個視圖看起來是仍然選中叮阅,請注意這只是它們處于特殊的布局關(guān)系的一種顯示模式,因此你必須重新選中這兩個視圖泣特。)

現(xiàn)在storyboard看起來是這樣的:

橙色的“T條”形狀的東西代表視圖之間的約束浩姥。 到目前為止,你添加了兩個約束:兩個視圖的 Equal Widths (相同寬度)約束(由帶有等號"="的T條表示)和位于兩個視圖之間的 Horizontal Space(水平距離)約束状您。約束(Constraints )代表了視圖之間的關(guān)系勒叠,它們是使用Auto Layout設(shè)置布局的主要工具。它可能看起來有點可怕膏孟,但它實際上是很直接的描述眯分,一旦你知道這一切意味著什么時。

要繼續(xù)構(gòu)建此屏幕的布局骆莹,請執(zhí)行以下步驟颗搂。 每個步驟都會添加更多的橙色T條。

對于左邊的視圖幕垦,從 Editor\Pin 菜單選擇:

  • Top Space to Superview ——上邊界到父視圖的距離
  • Leading Space to Superview ——左邊界到父視圖的距離

對于右邊的視圖丢氢,選擇:

  • Top Space to Superview ——上邊界到父視圖的距離
  • Trailing Space to Superview ——右邊界到父視圖的距離

對于底部那張大視圖:

  • Leading Space to Superview ——左邊界到父視圖的距離
  • Trailing Space to Superview ——右邊界到父視圖的距離
  • Bottom Space to Superview ——下邊界到父視圖的距離

現(xiàn)在你應(yīng)該有了如下的約束:

請注意傅联,T形條仍然是 橙色 的。這就意味著你的布局是不完整的;也就是說自動布局沒有足夠的約束來計算視圖的位置和大小疚察。解決方案是添加更多的約束蒸走,直到它們變成 藍(lán)色

按住?并選中所有三個視圖貌嫡。從 Editor 菜單中比驻,選擇 Pin\Heights Equally(相等高度)

現(xiàn)在選中左上角視圖和底部視圖(像先前一樣使用?),并選擇 Editor\Pin\Vertical Spacing(垂直距離)岛抄。

Interface Builder 應(yīng)該看起來是這樣的:

現(xiàn)在T條已經(jīng)變?yōu)?strong>藍(lán)色了别惦。自動布局現(xiàn)在有足夠的信息來計算有效的布局了。 它看起來有點凌亂夫椭,不過這是因為Equal WidthsEqual Heights約束占據(jù)了很大空間的緣故掸掸。

運(yùn)行APP并且...哇噢,不需要寫一行代碼便運(yùn)行的很好了蹭秋。不管你在哪個模擬器上運(yùn)行它扰付;在3.5英寸和4英寸設(shè)備上,布局效果都運(yùn)行良好仁讨。

真酷羽莺,但是實際上你到底做了什么你?Auto Layout 允許你表達(dá):布局中的視圖如何相互關(guān)聯(lián)洞豁,而不是要求你對視圖的大小和位置進(jìn)行硬編碼設(shè)置盐固。

你已經(jīng)把以下關(guān)系——也就是所謂的約束——放入了布局中:

  • 左上角和右上角的視圖總是保持相同的寬度(也就是pin中第一個widths equally命令)
  • 左上角和右上角視圖的水平距離是20pt(也就是pin中的horizontal spacing命令)
  • 所有的視圖總是有相同的高度(pin中heights equally命令)
  • 頂部兩個視圖和底部視圖的垂直距離是20pt(pin中的vertical spacing命令)
  • 視圖和屏幕邊緣的距離是20pt (上邊界、下邊界丈挟、左邊界和右邊界到父視圖的距離)

這些就足以表達(dá)出讓 Auto Layout 怎么放置視圖闰挡,以及當(dāng)屏幕大小改變時該如何處理了。

你可以在左側(cè)的 Document Outline 中查看所有的約束(constraints)礁哄。 當(dāng)你為storyboard開啟Auto Layout時长酗,就添加了名為Constraints的部分。 (如果沒有看到大綱窗格桐绒,請單擊Interface Builder窗口底部的箭頭按鈕夺脾。)

如果你選中了Document Outline中的一個約束(constraints),Interface Builder界面就會通過在約束周圍畫白色輪廓的方式茉继,高亮顯示約束在視圖上的位置咧叭,并且還會為其添加陰影以使其突出顯示。

約束是真實的對象(NSLayoutConstraint 類)烁竭,它們也有屬性菲茬。例如,選擇在兩個頂部視圖之間創(chuàng)建填充的約束(名“為Horizontal Space(20)”,請務(wù)必選擇正確)婉弹,然后切換到Attributes inspector睬魂。 你就可以通過編輯Constant字段來更改邊距的大小。

把值設(shè)置為100镀赌,然后再次運(yùn)行APP氯哮,現(xiàn)在邊距變得更寬了:

當(dāng)你在應(yīng)用程序中描述視圖時,Auto Layoutsprings and struts 更具表達(dá)力商佛。 在本教程的其余部分中喉钢,您將了解所有約束以及如何在Interface Builder中應(yīng)用它們以創(chuàng)建不同類型的布局矩屁。

Auto Layout 是如何工作的

正如你在上面的測試中所看到的撩轰,Auto Layout中的基本工具是約束(constraint)员淫。 約束描述了兩個視圖之間的幾何關(guān)系响迂。 例如,您可能有一個約束:
“l(fā)abel A右邊緣和button B左邊緣有20點的空白空間”

自動布局采用所有這些約束道宅,并進(jìn)行一些數(shù)學(xué)計算湃交,計算出所有視圖的理想位置和大小镀首。 您不再需要自己設(shè)置視圖的frame——自動布局會幫你實現(xiàn)它豹缀,完全基于你在這些視圖上設(shè)置的約束。

自動布局以前慨代,你總是需要為視圖的frames設(shè)置硬編碼邢笙,要么在Interface Builder中將他們放置在特定的坐標(biāo)中,或通過傳遞一個rectangle到initWithFrame:侍匙,或者設(shè)置視圖的frame氮惯,bounds或者center屬性。

對于你剛剛設(shè)置的APP來說想暗,你尤其需要像這樣設(shè)置frames:

還需要為這些視圖設(shè)置自動調(diào)整大小的masks:

這再也不是你需要為屏幕設(shè)計所考慮的東西了妇汗。有了Auto Layout(自動布局),你需要做的是這些:

視圖的大小和位置不再重要了; 只有約束才是最重要的说莫。當(dāng)然杨箭,當(dāng)你拖動一個新的button或label到畫布上時,它將有一定的大小储狭,并且你會把它放在一個特定的位置互婿,但這只是一個設(shè)計幫助,用來告訴Interface Builder在哪里放置約束 辽狈。

想你所想慈参,如你所愿

使用約束的最大優(yōu)點是,你不再需要調(diào)整坐標(biāo)以使你的視圖顯示在正確的位置刮萌。 相反驮配,你可以向自動布局描述視圖如何相互關(guān)聯(lián),自動布局將為您做所有的辛苦工作。 這就是所謂的根據(jù)目的設(shè)計(designing by intent)壮锻。

當(dāng)你根據(jù)目的設(shè)計時琐旁,你表達(dá)的是你想要實現(xiàn)什么,而不是是如何實現(xiàn)躯保。你不應(yīng)該說:“該按鈕的左上角坐標(biāo)是(20,230)”旋膳,你應(yīng)該說:

按鈕在其父視圖中垂直居中,并且放置在距離父視圖的左邊緣固定的距離處途事。

使用此描述验懊,自動布局可以自動計算按鈕應(yīng)顯示的位置,不用管父視圖的大小。

其他根據(jù)目的設(shè)計的示例(自動布局可以處理所有這些指令):

  • 這兩個textField應(yīng)該總是保持相同大小;
  • 這兩個button應(yīng)該總是同時移動;
  • 這四個label應(yīng)該總是保持右對齊;

這使得你的用戶界面的設(shè)計更具描述性。你只需定義約束,系統(tǒng)就會自動計算其frame肺然。

在第一部分你看到拾碌,即使為幾個視圖在橫豎方向上正確的布局都需要做大量的工作灾前。有了自動布局,你可以繞過這些麻煩。如果你正確的設(shè)置了約束衔憨,那么在橫豎屏方向上,布局將不需要做任何改變平项。

使用自動布局另一個重要的好處就是國際化悍及。比如德語中的文本,出了名的比老奶奶的裹腳布還要長扣讼,適配起來是一件很麻煩的事。再次缨叫,自動布局釋放了程序員的雙手耻姥,因為它能根據(jù)label需要顯示的內(nèi)容自動改變label的大小。

添加對德語渣叛,法語或任何其他語言的支持現(xiàn)在只是一個設(shè)置約束的問題淳衙,翻譯文本...然后就完了!

學(xué)習(xí)自動布局最好的方法就是使用它饺著,所以這正是剩下教程中你會學(xué)到的東西箫攀。

注意:自動布局不僅對旋轉(zhuǎn)有作用;它還能輕易的縮放你UI的大小從而適應(yīng)不同尺寸的屏幕瓶籽。這并不是巧合匠童,當(dāng)iPhone5擁有更高屏幕的同時,這個技術(shù)也同時加到了iOS中塑顺!自動布局能輕易的拉伸你程序的用戶界面汤求,從而充滿iPhone5垂直方向上多出來的空間。隨著iOS7中的動態(tài)類型的出現(xiàn)严拒,自動布局變得更加重要了扬绪。用戶現(xiàn)在可以改變?nèi)肿煮w大小設(shè)置--有了自動布局,這將變得非常簡單裤唠。

擁抱約束(courting constraints)

關(guān)閉你當(dāng)前的項目并用 Single View Application 模板創(chuàng)建一個新的iPhone項目挤牛。叫做"Constraints"。任何用Xcode5創(chuàng)建出來的項目都會自動假定你會使用自動布局种蘸,所以你并不需要額外做任何事情墓赴。

點擊Main.storyboard打開Interface Builder。 將一個新按鈕拖動到畫布上航瞭。 請注意诫硕,當(dāng)您拖動時,會出現(xiàn)藍(lán)色虛線刊侯。 這些線用來做向?qū)В?/p>

將控件拖動到在屏幕邊緣以及中心的時候章办,都會有向?qū)Ь€出現(xiàn):

如果之前你已經(jīng)使用過Interface Builder,那么你肯定看到過這些向?qū)Ь€滨彻。這些對我們對齊控件有很大的幫助藕届。

在啟用自動布局的Xcode 4中,指南有不同的用途亭饵。你仍然使用它們來對齊休偶,但他們也告訴你新的約束會在哪里。如果你將button沿著向?qū)Ь€反方向拖拽到左上角時辜羊,Xcode 4中的storyboard會是這樣的:

有兩個藍(lán)色的東西附屬在button上面椅贱。這些T-bar形狀的對象便是約束了懂算。在Xcode 4的Interface Builder中不管你將UI控制器放在哪兒,它總是會給出有效的約束庇麦。理論上這聽起來是個好主意计技,但是實際上,在Interface Builder中使用自動布局卻非常困難山橄。

幸運(yùn)的是垮媒,在Xcode 5中使用的情況變好了。當(dāng)你將按鈕放到畫布上后航棱,沒有任何T形條可見了:

注意到Document Outline窗格中也沒有“約束”部分睡雇。結(jié)論就是:這個按鈕沒有設(shè)置任何約束。

但是這又是如何奏效的呢饮醇?你剛剛也有了解到它抱,Auto Layout總是需要足夠的約束來確定所有視圖的大小和位置,但在這里你根本沒有設(shè)置任何約束朴艰。很明顯這難道不是一個不完整的布局嗎观蓄?

這就是Xcode 5比Xcode 4有所提升的地方:它不再強(qiáng)迫你總是去設(shè)置一個有效的布局。

注意:

  • 運(yùn)行帶有無效布局的應(yīng)用程序是一個壞主意祠墅,因為自動布局無法正確計算視圖應(yīng)該在哪里侮穿。 要么視圖的位置將是不可預(yù)測的(如果沒有足夠的約束)或是應(yīng)用程序?qū)罎ⅲㄈ绻刑嗟募s束)。
  • Xcode 4試圖通過確被汆拢總是有足夠的約束來創(chuàng)建有效的布局來防止這種情況的發(fā)生。 不幸的是狗准,它通常通過刪除你自己的約束并用你實際上不想要的約束來替換它們。 這是非常令人沮喪的腔长,這也是許多開發(fā)人員放棄使用Auto Layout的原因袭祟。
    Xcode5中,當(dāng)你編輯Storyboard時它允許你有不完整的布局饼酿,但它也會指出哪些地方你還需要修改榕酒。使用Interface Builder創(chuàng)建的自動布局驅(qū)動用戶界面變得更有趣了胚膊,使用Xcode5也消耗更少的時間故俐。
  • 如果你根本不提供任何約束,Xcode自動分配一套默認(rèn)的約束紊婉,正是我們所知的automatic constraints(自動約束)药版。它會在程序built的編譯時間中去完成這些事,而不是設(shè)計時間喻犁。當(dāng)你設(shè)計你的用戶界面時槽片,Xcode5中的自動布局為了不參與你的設(shè)計方法而努力工作何缓,這這是我們喜歡它的原因。

自動約束為你的視圖提供一個固定尺寸和位置还栓。換句話說碌廓,視圖總是擁有跟你在storyboard中看到的一樣的坐標(biāo)。這是非常方便的剩盒,因為這就意味著你可以大量的忽視自動布局谷婆。你可以為那些擁有充分約束的控件不增加約束,只為那些需要特殊規(guī)則的視圖創(chuàng)建約束辽聊。

好吧纪挎,讓我們來使用一下約束,看看他們能做些什么「遥現(xiàn)在异袄,按鈕位于左上角并且沒有約束。請確保按鈕是與兩個角導(dǎo)軌對齊的玛臂。

使用Editor\Pin菜單為按鈕增加兩個新的約束烤蜕,看起來像這樣:

如果你還沒有猜到,這就是Leading Space to SuperviewTop Space to Superview 選項垢揩。

所有的約束也列在Interface Builder窗口左側(cè)的Document Outline窗格中:

目前有兩個約束玖绿,即按鈕和主視圖的左邊緣之間的水平距離,以及按鈕和主視圖的頂部邊緣之間的垂直距離叁巨。 描述這些約束表達(dá)的關(guān)系就是:

該按鈕始終位于其父視圖中左上角的20點位置斑匪。

注意:這些實際上并不是非常有用的約束,因為它們與自動約束所做的事相同锋勺。 如果你總是希望你的按鈕位于它父視圖的左上角蚀瘸,那么你可能不需要提供任何約束,你可以讓Xcode幫你完成庶橱。

現(xiàn)在拖動button并將它放到屏幕的右上角贮勃,再次和藍(lán)色向?qū)Ь€對齊:

哇,這里發(fā)生了什么苏章?在Xcode 4中寂嘉,這將破壞舊的約束并基于藍(lán)色引導(dǎo)線分配新的約束,但在Xcode 5中枫绅,按鈕保留現(xiàn)有的約束泉孩。這里的問題是,【Interface Builder中按鈕的大小和位置】與【Auto Layout中基于約束所設(shè)置的大小和位置】不一致并淋。我們稱之為 misplaced view(錯位視圖)寓搬。

運(yùn)行APP。該按鈕仍將顯示在屏幕的左上角:

對于Auto Layout來說县耽,橙色代表著問題所在句喷。 Interface Builder繪制了兩個橙色框:一個帶有虛線的邊框镣典,一個帶有實線的邊框。 虛線框展示的是根據(jù)Auto Layout約束顯示的視圖邊框唾琼。 實心橙色框是根據(jù)你對視圖的拖動顯示在屏幕中的邊框兄春。 這兩個邊框應(yīng)該是匹配一致的,但在這里他們并不匹配锡溯。

如何解決這個問題取決于你想實現(xiàn)什么:

  • 如果你想要將按鈕放在屏幕的左邊神郊,而左邊邊緣距離拖放的視圖234點位置, 在這種情況下趾唱,你已經(jīng)使現(xiàn)有視圖的水平空間約束增加了234pt涌乳。 這就是橙色線條用“+234”的意思。
  • 如果你要將按鈕放在屏幕的右邊甜癞,那么夕晓,你需要刪除現(xiàn)有的約束并創(chuàng)建一個新的約束。

刪除水平空間約束悠咱。首先在畫布或 Document Outline 中選擇它蒸辆,然后按鍵盤上的Delete鍵。

請注意析既,這步操作會將垂直空間約束變?yōu)槌壬保鴦偛潘撬{(lán)色的。這個特定的約束并沒有錯誤;它只是意味著沒有足夠的約束來確定按鈕的完整位置眼坏。你仍然需要為X位置添加約束拂玻。

注意:你可能想知道為什么Xcode不為X位置添加一個自動約束。 規(guī)則是:只有當(dāng)你沒有人為設(shè)置任何約束時宰译,Xcode才會創(chuàng)建自動約束檐蚜。而一旦只要你添加了一個約束,這就意味著你告訴Xcode沿侈,這個視圖的約束由你管理闯第,不需要Xcode插手來自動添加。因此缀拭,Xcode將不再進(jìn)行任何自動約束咳短,并希望你添加此視圖所需要的任何其他約束。

選中按鈕蛛淋,選擇 Editor\Pin\Trailing Space to Superview咙好。 這個步驟會在按鈕的右邊緣和屏幕的右邊緣之間產(chǎn)生新的約束。 該約束表達(dá)的關(guān)系是:
“這個按鈕總是位于它的superview的右上角20px铣鹏》笊ǎ”
運(yùn)行APP并旋轉(zhuǎn)模擬器到橫屏狀態(tài)哀蘑。 請注意查看按鈕與右邊屏幕邊緣的距離是否始終相同:

當(dāng)你將按鈕(或任何其他視圖)參照引導(dǎo)并設(shè)置約束時诚卸,你將獲得一個由Apple的iOS人機(jī)交互指南 (即HIG)定義的標(biāo)準(zhǔn)尺寸的間距約束葵第。 對于邊框周圍的邊緣距離,標(biāo)準(zhǔn)大小為20px的空間合溺。

現(xiàn)在卒密,將按鈕向左拖動一點:

同樣你又得到了一個橙色的虛線框,因為視圖產(chǎn)生了misplaced view(錯位視圖)棠赛。如果說這個新的按鈕位置確實是你想要的哮奇。這是常見的約束設(shè)置序调,只要微調(diào)視圖的幾個像素浪规,橙色框就會出現(xiàn)。解決該問題的一種方法是刪除舊約束并創(chuàng)建一個新的約束纲酗,但有一個更簡單的解決方案辩涝。

Editor菜單有一個Resolve Auto Layout Issues子菜單贸伐。 從該菜單中,選擇Update Constraints更新約束怔揩。在我的這種情況下捉邢,這就告訴了Interface Builder,它的約束需要增大64px商膊,如下所示:

太棒了伏伐,T條又變成藍(lán)色并且布局也是有效的。在Document Outline(文檔大綱)中晕拆,你可以看到水平空間約束不再有標(biāo)準(zhǔn)空間的那個約束了:

到目前為止藐翎,你已經(jīng)嘗試使用了水平空間和垂直空間約束。 還有一個“中心”約束实幕。將一個新的Button對象拖動到畫布的底部中心阱高,以便它與指引位置相同:

為了使按鈕始終相對于父視圖居中對齊,在水平軸上茬缩,你需要添加 Center X Alignment(中心對齊)約束赤惊。 從Editor菜單中選擇Align\Horizontal Center in Container。 這個步驟會增加了一條長的橙色線條:

該線是橙色的凰锡,因為你只指定了按鈕的X坐標(biāo)未舟,而沒有指明其Y坐標(biāo)發(fā)生了什么。 使用Editor \ Pin菜單在視圖的按鈕和底部之間添加垂直空間約束掂为。 它應(yīng)該看起來像這樣:

如果你不知道如何操作裕膀,它是Bottom Space to Superview選項。 垂直空間約束使按鈕遠(yuǎn)離視圖的底部(再次使用標(biāo)準(zhǔn)邊距20px)勇哗。

運(yùn)行APP并將其旋轉(zhuǎn)到橫屏狀態(tài)昼扛。 即使在橫屏模式下,按鈕仍停留在屏幕的底部中心:


這就是你所表達(dá)的意圖:“這個按鈕應(yīng)該始終在底部中心〕常”注意渺鹦,你并沒有告訴Interface Builder該按鈕的坐標(biāo)是什么,你只是希望它被錨定在視圖底部中心蛹含。

有了 Auto Layout毅厚,你不再需要關(guān)心在畫布上放置視圖的位置的確切坐標(biāo)或它們的大小。相反浦箱,Auto Layout 會根據(jù)你設(shè)置的約束中導(dǎo)出這兩個東西吸耿。

您可以在按鈕的Size inspector(大小檢視器)中看到這種模式轉(zhuǎn)換,現(xiàn)在已經(jīng)非常不同了:

禁用自動布局后酷窥,輸入X咽安,Y,寬度或高度字段將更改所選視圖的位置和大小蓬推。 啟用自動布局后板乙,您仍然可以在這些字段中鍵入新值,但是如果您已經(jīng)在視圖上設(shè)置了約束拳氢,它現(xiàn)在可能會放錯位置募逞。 您還必須更新約束以使其與新值匹配。

例如馋评,將按鈕的寬度值更改為100.畫布變成這樣:

Xcode 4 會用水平空間的新約束替換掉中心X對齊約束放接,強(qiáng)制它具有100點的寬度。然而留特,Xcode 5簡單地說纠脾,“如果你想要的寬度是100點,對我來說無所謂蜕青,但是你要知道約束并不是這么說的苟蹈。

在這種情況下,你希望按鈕是100點寬右核。 對此有一種特殊類型的約束:the Fixed Width constraint(固定寬度約束)慧脱。 首先按撤消,使按鈕再次居中贺喝,T條全部為藍(lán)色菱鸥。 選擇按鈕并選擇Editor \ Pin \ Width。 這會在按鈕下方放置一個新的T形條:

選擇該T條躏鱼,并在Attributes inspector(屬性檢視器)中將常數(shù)更改為100.這將強(qiáng)制按鈕總是100點寬氮采,無論它的標(biāo)題多大或小。 要看到這一點染苛,你可以給按鈕一個背景顏色:

您還可以在左側(cè)的Document Outline中看到此新寬度約束:

與按鈕及其父視圖之間的其他約束不同鹊漠,寬度約束僅適用于按鈕本身。 你可以認(rèn)為這是按鈕和...按鈕之間的約束。

你可能想知道為什么按鈕之前沒有寬度約束躯概。 Auto Layout如何知道按鈕有多寬登钥?

這里有一條就是:按鈕本身是知道它自己必須有多寬的。 它是基于其標(biāo)題文本和一些填充來計算的楞陷。 如果你在按鈕上設(shè)置了一個背景圖片,它也會考慮到這一點茉唉。

這稱之為intrinsic content size(固有內(nèi)容大泄潭辍)。 不是所有的控件都有這個度陆,但很多(UILabel是另一個例子)艾凯。 如果視圖可以計算自己的應(yīng)有大小,那么您不需要在為其設(shè)置特定的寬度或高度約束懂傀。 以后你會看到更多的趾诗。

要將按鈕恢復(fù)到最佳大小,請先刪除寬度約束蹬蚁。 然后選擇按鈕恃泪,從編輯器菜單中選擇Size to Fit Content(大小適應(yīng)內(nèi)容)。這將恢復(fù)按鈕的固有內(nèi)容大小犀斋。

孤掌難鳴

引導(dǎo)線不僅僅呈現(xiàn)視圖及其父視圖之間的關(guān)系贝乎,而且也呈現(xiàn)視圖層次結(jié)構(gòu)的同一級別的視圖之間。 為了演示這一點叽粹,將一個新按鈕拖到畫布上览效。 如果將此按鈕拖動到其他按鈕附近,則它們的引導(dǎo)線也會開始交互虫几。

將新按鈕放在現(xiàn)有按鈕旁邊锤灿,使其卡入到位:

這里有很多虛線的引導(dǎo)線。 Interface Builder認(rèn)為這兩個按鈕可以以不同的方式排列 - 在它們的頂部辆脸,中心和基線但校。
Xcode 4將把這些貼緊引導(dǎo)下中的一個轉(zhuǎn)換成新的約束。 但是使用Xcode 5啡氢,如果你想在這兩個按鈕之間有一個約束始腾,你必須自己做。 您已經(jīng)看到空执,您可以使用Editor \ Pin菜單在兩個視圖之間創(chuàng)建約束浪箭,但也有一種更簡單的方法。
選擇新的按鈕辨绊,然后Ctrl-drag到另一個按鈕奶栖,像這樣:

當(dāng)您松開鼠標(biāo)按鈕時,會出現(xiàn)一個彈出窗口。 選擇第一個選項宣鄙,Horizontal Spacing(水平間距)袍镀。

它會創(chuàng)建一個像這樣的新約束:

它是橙色的,意味著此按鈕需要至少一個其他約束冻晤。 按鈕的大小是已知的 - 它使用固有內(nèi)容大小確定 - 并且按鈕的X位置已經(jīng)有一個約束了苇羡。 只留下Y位置沒有約束。

這里缺少的約束很容易確定鼻弧,但對于更復(fù)雜的設(shè)計设江,它可能不會總是立即顯而易見的。 幸運(yùn)的是攘轩,你不必猜測叉存。 Xcode會一直保持計算,可以準(zhǔn)確地告訴你缺少什么度帮。
在文檔大綱中有一個小的紅色箭頭歼捏,在View Controller Scene旁邊。 單擊該箭頭以查看所有自動布局問題的列表:

真貼心笨篷!讓我們添加那個缺少Y位置的約束吧瞳秽。選擇新按鈕向下拖動:

此時彈出菜單有不同的選項。此菜單中的項目取決于上下文(您在其間拖動的視圖)和移動鼠標(biāo)的方向率翅。 選擇Bottom Space to Bottom Layout(底部空間到底部布局)寂诱。

新按鈕現(xiàn)在有一個到屏幕底部的垂直空間,還有一個水平空間安聘,它與其他按鈕鏈接痰洒。 因為這個空間很小(只有8分)浴韭,T條可能有點難以看到丘喻,但它絕對存在。

單擊文檔大綱中的Horizontal Space (8)約束將其選中:

當(dāng)選擇約束時念颈,它會點亮其所屬的控件泉粉。 這個特定約束位于兩個按鈕之間。 你在這里做的是說:

“第二個按鈕總是出現(xiàn)在第一個按鈕的左邊榴芳,無論第一個按鈕位于何處或有多大嗡靡。

選擇黃色的按鈕,并在其標(biāo)簽中鍵入一些長的“A longer label”窟感。 完成后讨彼,按鈕會調(diào)整大小,為新文本騰出空間柿祈,而另一個按鈕則會移動哈误。畢竟哩至,它被附加到第一個按鈕的左邊緣,所以這是你打算發(fā)生的事情:

只是為了獲得【這是如何工作的】更好感覺蜜自,再試一次菩貌。 將另一個按鈕拖動到畫布中,并將其放在黃色的上方重荠,以便它們垂直卡入到位(但不要嘗試對齊兩個按鈕的左邊緣):

給新按鈕設(shè)置一個背景顏色(綠色)箭阶,這樣你可以更容易地看到它的范圍。

因為你把兩個按鈕扣在一起戈鲁,根據(jù)HIG的推薦現(xiàn)在它們之間有一個標(biāo)準(zhǔn)的8pt空間仇参。 通過在兩個按鈕之間按住Ctrl鍵并拖動,將其轉(zhuǎn)換為約束荞彼。 從彈出菜單中選擇Vertical Spacing(垂直間距)冈敛。

注意:“HIG”是iOS人機(jī)交互指南的縮寫待笑,包含Apple關(guān)于設(shè)計良好用戶界面的建議鸣皂。 這是任何iOS開發(fā)人員的必須要閱讀的。 HIG解釋了哪些UI元素適合在哪些情況下使用暮蹂,以及使用它們的最佳做法寞缝。 您可以在此處找到此文檔。

但是仰泻,您并不受限于控件之間的標(biāo)準(zhǔn)間距荆陆。 約束是完整的對象,就像視圖一樣集侯,因此它們具有可以更改的屬性被啼。

選擇兩個按鈕之間的垂直空間約束。 你可以通過點擊T條在畫布中做到這一點棠枉,雖然這往往是有點過于挑剔 到目前為止浓体,最簡單的方法是單擊文檔大綱中的約束。 一旦選擇它辈讶,切換到Attributes inspector(屬性檢查器):

在Constant字段中輸入40以更改約束的大小∶。現(xiàn)在兩個按鈕分開了,但它們?nèi)匀贿B接:

運(yùn)行應(yīng)用程序并翻轉(zhuǎn)到橫屏模式以查看效果:

按鈕當(dāng)然仍然保持著垂直排列贱除,但他們不是在同一個水平位置生闲! 原因應(yīng)該很明顯:綠色按鈕還沒有X位置的約束。

從綠色按鈕向畫布的左邊緣添加水平空間約束將無法解決此問題月幌。 有了這樣的約束碍讯,綠色按鈕總是保持相同的X坐標(biāo),即使在橫屏模式下也同樣扯躺。 這看起來不是很好冲茸,所以你要表達(dá)以下意圖:

“黃色按鈕將始終水平居中屯阀,并且綠色按鈕的左邊緣要和黃色按鈕的左邊緣對齊。

您已經(jīng)有第一個約束了轴术,但還沒有第二個的約束难衰。 Interface Builder有顯示對齊的指引線,因此您可以拖動頂部按鈕逗栽,直到其左邊緣與黃色按鈕對齊:

如果您也拖動了按鈕的垂直距離盖袭,按鈕的邊框和垂直空間約束可能不在正確的距離下。 您將在T形條上看到橙色標(biāo)識:

如果發(fā)生這種情況彼宠,只需使用方向鍵將按鈕推入到位鳄虱,直到標(biāo)識消失。

最后凭峡,在兩個按鈕之間按住Ctrl鍵并拖動拙已,然后從彈出菜單中選擇Left。 這創(chuàng)建了一個對齊約束摧冀,它的意思是說:“這兩個視圖的左邊緣總是對齊的”倍踪。 換句話說,兩個按鈕將總是具有完全相同的X位置索昂。 這步解決了布局問題建车,同時T條轉(zhuǎn)為藍(lán)色:

運(yùn)行APP,并旋轉(zhuǎn)到橫屏模式以驗證其是否有效:


接下來做什么椒惨?

現(xiàn)在你已經(jīng)對 Auto Layout 有了第一次嘗試缤至,你喜歡它嗎? 適應(yīng)它可能還要花些功夫康谆,但可以使你的生活很容易领斥,你的應(yīng)用程序也會更靈活!

想了解更多沃暗? 繼續(xù)閱讀本part 2 of this Auto Layout tutorial月洛,您將繼續(xù)使用Interface Builder中的按鈕來更好地了解Auto Layout提供的功能以及您可能遇到的問題。最好就是 - 你也將使用Auto Layout 在你真正的APP中創(chuàng)建一個真正的布局描睦。

在此期間膊存,如果您有任何問題或意見,請加入下面的論壇討論忱叭!

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爵卒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撵彻,更是在濱河造成了極大的恐慌钓株,老刑警劉巖实牡,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異轴合,居然都是意外死亡创坞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門受葛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來题涨,“玉大人,你說我怎么就攤上這事总滩「俣拢” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵闰渔,是天一觀的道長席函。 經(jīng)常有香客問我,道長冈涧,這世上最難降的妖魔是什么茂附? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮炕舵,結(jié)果婚禮上何之,老公的妹妹穿的比我還像新娘跟畅。我一直安慰自己咽筋,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布徊件。 她就那樣靜靜地躺著奸攻,像睡著了一般盏档。 火紅的嫁衣襯著肌膚如雪静稻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天括享,我揣著相機(jī)與錄音部翘,去河邊找鬼硝训。 笑死,一個胖子當(dāng)著我的面吹牛新思,可吹牛的內(nèi)容都是我干的窖梁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼夹囚,長吁一口氣:“原來是場噩夢啊……” “哼纵刘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荸哟,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤假哎,失蹤者是張志新(化名)和其女友劉穎瞬捕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舵抹,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡肪虎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惧蛹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笋轨。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赊淑,靈堂內(nèi)的尸體忽然破棺而出爵政,到底是詐尸還是另有隱情,我是刑警寧澤陶缺,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布钾挟,位于F島的核電站,受9級特大地震影響饱岸,放射性物質(zhì)發(fā)生泄漏掺出。R本人自食惡果不足惜汤锨,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一百框、第九天 我趴在偏房一處隱蔽的房頂上張望闲礼。 院中可真熱鬧,春花似錦铐维、人聲如沸柬泽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睬棚。三九已至包警,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間新荤,已是汗流浹背揽趾。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留苛骨,地道東北人篱瞎。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓苟呐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親俐筋。 傳聞我的和親對象是個殘疾皇子牵素,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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