約束
1.Storyboard中通過拖拽設(shè)置constraint;
2.VFL和原聲語法代碼設(shè)置constraint;
3.約束的常用優(yōu)雅的第三方框架:Objective - c - Masonry ,Swift - SnapKit
iOS布局機(jī)制 auto layout
- 某個View(視圖)需要使用auto layout布局篓像,需要設(shè)置:
translatesAutoresizingMaskIntoConstraints = false
- 幾個常用API
1.intrinsinContentSize (在約束條件下褪秀,返回固有尺寸的內(nèi)容)
//就UILable而言下面這個方法比intrinsinContentSize先調(diào)用姨蝴,且修改后的tmpRect就是修改前的contentSize
override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect{
var tmpRect = super.textRectForBounds(bounds, limitedToNumberOfLines: numberOfLines)
print("textRectForBoundsA:\(tmpRect)")
tmpRect.size.width += 15
tmpRect.size.height += 15
print("textRectForBoundsB:\(tmpRect)")
return tmpRect
}
//實現(xiàn)這些效果腹忽,只是應(yīng)為我們知道現(xiàn)有內(nèi)容所需的尺寸,并且在其內(nèi)容下擴(kuò)展闻察,就造成了這個臨界效果
override func intrinsicContentSize() -> CGSize {
var contentSize = super.intrinsicContentSize()
//這個方法就是通過約束來返回一個渲染時內(nèi)容需要的Size捆探,會多次回調(diào)
//(所謂的內(nèi)容所需要的size,比如一個label約束寬度為了300斤吐,但是內(nèi)容達(dá)不到這個寬度搔涝,返回的值可能是小于300的size厨喂。
eg:(267.5,14.5)),這個方法在一個控件完全需要內(nèi)容撐大的時候非常有效
print(contentSize)
contentSize.width += 20
contentSize.height += 20
print(contentSize)
return contentSize
}
使用:可以通過重寫這個方法來獲取健全約束后的控件frame,也可以改變其值再返回庄呈,這個方法只適合存在固有內(nèi)容的控件重寫蜕煌。比如:UILable、UIButton和UIImage诬留,其他不適固有內(nèi)容的View統(tǒng)一返回(-1,-1)
總結(jié):system auto layout 通過健全的約束和固有內(nèi)容來獲取該控件需 要的渲染的frame斜纪,就是用這個方法來回調(diào)獲得的,然后我們通過改變返回值文兑,來達(dá)到我們的各種效果盒刚。這個返回值的改變臨界值就是約束和改變后值取小。這句話的理解就是绿贞,改變后的size(30因块,30),而有一個約束條件是width <= 25,那么最終效果size就是 (25,30)
2.preferredMaxLayoutWidth
就我目前的手法而言籍铁,這個方法暫時沒什么用涡上,這個方法可以用一個上限約束 "<=" 代替,這個方法在不需要通過約束計算size的時候有效拒名,但是你在某種情況下需要計算出高度那么就需要設(shè)置這個屬性了(比如在ios7下計算撐大的cell高度)
a.這種方式在iOS9下無效吩愧,iOS8下設(shè)置有效
class LayoutLabel: UILabel {
override func layoutSubviews() {
self.preferredMaxLayoutWidth = self.frame.size.width
super.layoutSubviews()
}
}
b.這種方式在iOS9下也無效,iOS8下設(shè)置有效
override func layoutSubviews() {
super.layoutSubviews()
self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.bounds.width
super.layoutSubviews()
}
總結(jié):在iOS9下暫時只能如下處理(這么處理的缺點就是橫屏的時候不能滿足)
override func awakeFromNib() {
super.awakeFromNib()
self.titleLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - 20
}
3.sizeThatFits:方法和sizeToFit方法
let tmpsize = testTextView.sizeThatFits(self.testTextView.bounds.size)
self.testTextViewHeightConstraint.constant = tmpsize.height
使用:類似上面的方法可以實現(xiàn)那種contentSize和高度一致的效果增显,不產(chǎn)生滾動條耻警。對于tableview實現(xiàn)這個還沒嘗試過,只測試了textView
總結(jié):調(diào)用sizeThatFits:并不改變View的size甸怕,它只是根據(jù)已有的content和給定的size計算出最合適的view的size甘穿。
4.systemLayoutSizeFittingSize:方法
對于固有內(nèi)容的View在布局完成之前獲得frame可以用intrinsinContentSize,
對于非自有內(nèi)容在布局完成之前要獲得一個View的frame那就需要這個方法了。使用這個方法之前確保約束的完整性能足夠撐大外層的view梢杭,否則約束不完整温兼,根據(jù)傳入的參數(shù)UILayoutFittingCompressedSize對應(yīng)size.width = 0
,UILayoutFittingExpandedSize對應(yīng)size.width = 1000
eg:動態(tài)計算cell的高度常用這個方法武契,此方法不能計算包含UITextView的募判,這種情況的解決方案就是,還是上面的計算然后加上textView的高咒唆,textView用上面的sizeThatFits:來計算
這個方法有時候要和preferredMaxLayoutWidth搭載一起使用才有效果
self.testLabelB.text = "這包含的另外一層意思"
self.testLabelB.preferredMaxLayoutWidth = 300
let outViewFitSize = self.testUIViewA.systemLayoutSizeFittingSize(UILayoutFittingExpandedSize)
print("outViewFitSize:\(outViewFitSize)")
總結(jié):就我的理解為什么要在這里設(shè)置preferredMaxLayoutWidth才有效果的原因届垫,因為以前不需要設(shè)置這個是因為由外到內(nèi)的約束都是完整的,可以計算出preferredMaxLayoutWidth全释,但是現(xiàn)在的情況是計算外層的size装处,那么就無法使用外層約束來揣測內(nèi)層約束,從而無法得到preferredMaxLayoutWidth浸船,那么就需要顯示聲明了
5.壓縮阻力(Compression Resistance)和 內(nèi)容吸附(Content
值越大妄迁,越不容易被壓縮和吸附(拉伸),用過自動布局就知道這種場景吧寝蹈,,場景:2個view并排登淘,Width都是>=0 ,且2邊都leading 0 箫老,training 為 0 ,你想要拉伸或者壓縮那個view呢黔州,就取決于這個條件約束
參考資料
http://zhangbuhuai.com/2015/07/16/beginning-auto-layout-part-1
https://www.mgenware.com/blog/?p=491
http://objccn.io/issue-3-5/