iOS 越來越人性化了,用戶可以在設(shè)置-通用-輔助功能中動(dòng)態(tài)調(diào)整字體大小了。你會(huì)發(fā)現(xiàn)所有 iOS 自帶的APP的字體大小都變了,可惜我們開發(fā)的第三方APP依然是以前的字體。在 iOS 7 之后我們可以用 UIFont 的preferredFontForTextStyle: 類方法來指定一個(gè)樣式,并讓字體大小符合用戶設(shè)定的字體大小。目前可供選擇的有六種樣式:
成都創(chuàng)新互聯(lián)公司專注于企業(yè)營(yíng)銷型網(wǎng)站、網(wǎng)站重做改版、巫山網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5建站、成都做商城網(wǎng)站、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為巫山等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
UIFontTextStyleHeadline UIFontTextStyleBody UIFontTextStyleSubheadline UIFontTextStyleFootnote UIFontTextStyleCaption1 UIFontTextStyleCaption2
iOS會(huì)根據(jù)樣式的用途來合理調(diào)整字體。
問題來了,諸如字體大小這種“動(dòng)態(tài)類型”,我們需要對(duì)其進(jìn)行動(dòng)態(tài)的UI調(diào)整,否則總是覺得我們的界面怪怪的:
我們想要讓Cell 的高度隨著字體大小而作出調(diào)整:
總之,還會(huì)有其他動(dòng)態(tài)因素導(dǎo)致我們需要修改布局。
解決方案
UITableView
有三種策略可以調(diào)節(jié)Cell(或者是Header和Footer)的高度:
a.調(diào)節(jié)Height屬性
b.通過委托方法tableView: heightForRowAtIndexPath:
c.Cell的“自排列”(self-sizing)
前兩種策略都是我們所熟悉的,后面將介紹第三種策略。UITableViewCell 和 UICollectionViewCell 都支持 self-sizing。
在 iOS 7 中,UITableViewDelegate新增了三個(gè)方法來滿足用戶設(shè)定Cell、Header和Footer預(yù)計(jì)高度的方法:
- tableView:estimatedHeightForRowAtIndexPath: - tableView:estimatedHeightForHeaderInSection: - tableView:estimatedHeightForFooterInSection:
當(dāng)然對(duì)應(yīng)這三個(gè)方法 UITableView 也 estimatedRowHeight、estimatedSectionHeaderHeight 和 estimatedSectionFooterHeight 三個(gè)屬性,局限性在于只能統(tǒng)一定義所有行和節(jié)的高度。
以 Cell 為例,iOS 會(huì)根據(jù)給出的預(yù)計(jì)高度來創(chuàng)建一個(gè)Cell,但等到真正要顯示它的時(shí)候,iOS 8會(huì)在 self-sizing 計(jì)算得出新的 Size 并調(diào)整 table 的 contentSize 后,將 Cell 繪制顯示出來。關(guān)鍵在于如何得出 Cell 新的 Size,iOS提供了兩種方法:
自動(dòng)布局
這個(gè)兩年前推出的神器雖然在一開始表現(xiàn)不佳,但隨著 Xcode 的越來越給力,在iOS7中自動(dòng)布局儼然成了默認(rèn)勾選的選項(xiàng),通過設(shè)定一系列約束來使得我們的UI能夠適應(yīng)各種尺寸的屏幕。如果你有使用約束的經(jīng)驗(yàn),想必已經(jīng)有了解決思路:向 Cell 的 contentView 添加約束。iOS 會(huì)先調(diào)用 UIView 的 systemLayoutSizeFittingSize: 方法來根據(jù)約束計(jì)算新的Size,如果你沒實(shí)現(xiàn)約束,systemLayoutSizeFittingSize: 會(huì)接著調(diào)用sizeThatFits:方法。
人工代碼
我們可以重寫sizeThatFits:方法來自己定義新的Size,這樣我們就不必學(xué)習(xí)約束相關(guān)的知識(shí)了。
下面我給出了一個(gè)用 Swift 語(yǔ)言寫的 Demo-HardChoice ,使用自動(dòng)布局來調(diào)整UITableViewCell的高度。我通過實(shí)現(xiàn)一個(gè)UITableViewCell的子類DynamicCell來實(shí)現(xiàn)自動(dòng)布局,你可以再GitHub上下載源碼:
import UIKit class DynamicCell: UITableViewCell { required init(coder: NSCoder) { super.init(coder: coder) if textLabel != nil { textLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline) textLabel.numberOfLines = 0 } if detailTextLabel != nil { detailTextLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) detailTextLabel.numberOfLines = 0 } } override func constraints() - [AnyObject] { var constraints = [AnyObject]() if textLabel != nil { constraints.extend(constraintsForView(textLabel)) } if detailTextLabel != nil { constraints.extend(constraintsForView(detailTextLabel)) } constraints.append(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: contentView, attribute: NSLayoutAttribute.Height, multiplier: 0, constant: 44)) contentView.addConstraints(constraints) return constraints } func constraintsForView(view:UIView) - [AnyObject]{ var constraints = [NSLayoutConstraint]() constraints.append(NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.FirstBaseline, relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.Top, multiplier: 1.8, constant: 30.0)) constraints.append(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: view, attribute: NSLayoutAttribute.Baseline, multiplier: 1.3, constant: 8)) return constraints } }
上面的代碼需要注意的是,Objective-C中的類在Swift中都可以被當(dāng)做AnyObject,這在類型兼容問題上很管用。
別忘了在相應(yīng)的 UITableViewController 中的 viewDidLoad 方法中加上:
self.tableView.estimatedRowHeight = 44
自適應(yīng)效果如下:
UICollectionView
UITableView 和 UICollectionView 都是 data-source 和 delegate 驅(qū)動(dòng)的。UICollectionView 在此之上進(jìn)行了進(jìn)一步抽象。它將其子視圖的位置,大小和外觀的控制權(quán)委托給一個(gè)單獨(dú)的布局對(duì)象。通過提供一個(gè)自定義布局對(duì)象,你幾乎可以實(shí)現(xiàn)任何你能想象到的布局。布局繼承自 UICollectionViewLayout 抽象基類。iOS 6 中以 UICollectionViewFlowLayout 類的形式提出了一個(gè)具體的布局實(shí)現(xiàn)。在 UICollectionViewFlowLayout 中,self-sizing 同樣適用:
采用self-sizing后:
UICollectionView 實(shí)現(xiàn) self-sizing 不僅可以通過在 Cell 的 contentView 上加約束和重寫 sizeThatFits: 方法,也能在 Cell 層面(以前都是在 contentSize 上進(jìn)行 self-sizing)上做文章:重寫 UICollectionReusableView 的preferredLayoutAttributesFittingAttributes: 方法來在 self-sizing 計(jì)算出 Size 之后再修改,這樣就達(dá)到了對(duì)Cell布局屬性(UICollectionViewLayoutAttributes)的全面控制。
PS:preferredLayoutAttributesFittingAttributes: 方法默認(rèn)調(diào)整Size屬性來適應(yīng) self-sizing Cell,所以重寫的時(shí)候需要先調(diào)用父類方法,再在返回的 UICollectionViewLayoutAttributes 對(duì)象上做你想要做的修改。
由此我們從最經(jīng)典的 UICollectionViewLayout 強(qiáng)制計(jì)算屬性(還記得 UICollectionViewLayoutAttributes 的一系列工廠方法么?)到使用 self-sizing 來根據(jù)我們需求調(diào)整屬性中的Size,再到重寫UICollectionReusableView(UICollectionViewCell也是繼承于它)的 preferredLayoutAttributesFittingAttributes: 方法來從Cell層面對(duì)所有屬性進(jìn)行修改:
下面來說說如何在 UICollectionViewFlowLayout 實(shí)現(xiàn) self-sizing:
首先,UICollectionViewFlowLayout 增加了estimatedItemSize 屬性,這與 UITableView 中的 ”estimated...Height“ 很像(注意我用省略號(hào)囊括那三種屬性),但畢竟 UICollectionView 中的 Item 都需要約束 Height 和 Width的,所以它是個(gè) CGSIze,除了這點(diǎn)它與 UITableView 中的”estimated...Height“用法沒區(qū)別。
其...沒有其次,在 UICollectionView 中實(shí)現(xiàn) self-sizing,只需給 estimatedItemSize 屬性賦值(不能是 CGSizeZero ),一行代碼足矣。
InvalidationContext
假如設(shè)備屏幕旋轉(zhuǎn),或者需要展示一些其妙的效果(比如 CoverFlow ),我們需要將當(dāng)前的布局失效,并重新計(jì)算布局。當(dāng)然每次計(jì)算都有一定的開銷,所以我們應(yīng)該謹(jǐn)慎的僅在我們需要的時(shí)候調(diào)用 invalidateLayout 方法來讓布局失效。
在 iOS 6 時(shí)代,有的人會(huì)“聰明地”這樣做:
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { CGRect oldBounds = self.collectionView.bounds; if (CGRectGetWidth(newBounds) != CGRectGetWidth(oldBounds)) { return YES; } return NO; }
而 iOS 7 新加入的 UICollectionViewLayoutInvalidationContext 類聲明了在布局失效時(shí)布局的哪些部分需要被更新。當(dāng)數(shù)據(jù)源變更時(shí),invalidateEverything 和 invalidateDataSourceCounts 這兩個(gè)只讀 Bool 屬性標(biāo)記了UICollectionView 數(shù)據(jù)源“全部過期失效”和“Section和Item數(shù)量失效”,UICollectionView會(huì)將它們自動(dòng)設(shè)定并提供給你。
你可以調(diào)用invalidateLayoutWithContext:方法并傳入一個(gè)UICollectionViewLayoutInvalidationContext對(duì)象,這能優(yōu)化布局的更新效率。
當(dāng)你自定義一個(gè) UICollectionViewLayout 子類時(shí),你可以調(diào)用 invalidationContextClass 方法來返回一個(gè)你定義的 UICollectionViewLayoutInvalidationContext 的子類,這樣你的 Layout 子類在失效時(shí)會(huì)使用你自定義的InvalidationContext 子類來優(yōu)化更新布局。
你還可以重寫 invalidationContextForBoundsChange: 方法,在實(shí)現(xiàn)自定義 Layout 時(shí)通過重寫這個(gè)方法返回一個(gè) InvalidationContext 對(duì)象。
綜上所述都是 iOS 7 中新加入的內(nèi)容,并且還可以應(yīng)用在 UICollectionViewFlowLayout 中。在 iOS 8 中,UICollectionViewLayoutInvalidationContext 也被用在self-sizing cell上。
iOS8 中 UICollectionViewLayoutInvalidationContext 新加入了三個(gè)方法使得我們可以更加細(xì)致精密地使某一行某一節(jié)Item(Cell)、Supplementary View 或 Decoration View 失效:
invalidateItemsAtIndexPaths: invalidateSupplementaryElementsOfKind:atIndexPaths: invalidateDecorationElementsOfKind:atIndexPaths:
對(duì)應(yīng)著添加了三個(gè)只讀數(shù)組屬性來標(biāo)記上面那三種組件:
invalidatedItemIndexPaths invalidatedSupplementaryIndexPaths invalidatedDecorationIndexPaths
iOS自帶的照片應(yīng)用會(huì)將每一節(jié)照片的信息(時(shí)間、地點(diǎn))停留顯示在最頂部,實(shí)現(xiàn)這種將 Header 粘在頂端的功能其實(shí)就是將那個(gè) Index 的 Supplementary View 失效,就這么簡(jiǎn)單。
UICollectionViewLayoutInvalidationContext 新加入的 contentOffsetAdjustment 和 contentSizeAdjustment 屬性可以讓我們更新 CollectionView 的 content 的位移和尺寸。
此外 UICollectionViewLayout 還加入了一對(duì)兒方法來幫助我們使用self-sizing:
shouldInvalidateLayoutForPreferredLayoutAttributes:withOriginalAttributes: invalidationContextForPreferredLayoutAttributes:withOriginalAttributes:
當(dāng)一個(gè)self-sizing Cell發(fā)生屬性發(fā)生變化時(shí),第一個(gè)方法會(huì)被調(diào)用,它詢問是否應(yīng)該更新布局(即原布局失效),默認(rèn)為NO;而第二個(gè)方法更細(xì)化的指明了哪些屬性應(yīng)該更新,需要調(diào)用父類的方法獲得一個(gè)InvalidationContext 對(duì)象,然后對(duì)其做一些你想要的修改,最后返回。
試想,如果在你自定義的布局中,一個(gè)Cell的Size因?yàn)槟撤N原因發(fā)生了變化(比如由于字體大小變化),其他的Cell會(huì)由于 self-sizing 而位置發(fā)生變化,你需要實(shí)現(xiàn)上面兩個(gè)方法來讓指定的Cell更新布局中的部分屬性;別忘了整個(gè) CollectionView 的 contentSize 和 contentOffset 因此也會(huì)發(fā)生變化,你需要給 contentOffsetAdjustment 和 contentSizeAdjustment 屬性賦值。
iOS 越來越人性化了,用戶可以在設(shè)置-通用-輔助功能中動(dòng)態(tài)調(diào)整字體大小了。你會(huì)發(fā)現(xiàn)所有 iOS 自帶的APP的字體大小都變了,可惜我們開發(fā)的第三方APP依然是以前的字體。在 iOS 7 之后我們可以用 UIFont 的preferredFontForTextStyle: 類方法來指定一個(gè)樣式,并讓字體大小符合用戶設(shè)定的字體大小。目前可供選擇的有六種樣式: UIFontTextStyleHeadline UIFontTextStyleBody UIFontTextStyleSubheadline UIFontTextStyleFootnote UIFontTextStyleCaption1 UIFontTextStyleCaption2 iOS會(huì)根據(jù)樣式的用途來合理調(diào)整字體。問題來了,諸如字體大小這種“動(dòng)態(tài)類型”,我們需要對(duì)其進(jìn)行動(dòng)態(tài)的UI調(diào)整,否則總是覺得我們的界面怪怪的:我們想要讓Cell 的高度隨著字體大小而作出調(diào)整:總之,還會(huì)有其他動(dòng)態(tài)因素導(dǎo)致我們需要修改布局。解決方案 UITableView 有三種策略可以調(diào)節(jié)Cell(或者是Header和Footer)的高度:a.調(diào)節(jié)Height屬性 b.通過委托方法tableView: heightForRowAtIndexPath: c.Cell的“自排列”(self-sizing)前兩種策略都是我們所熟悉的,后面將介紹第三種策略。UITableViewCell 和 UICollectionViewCell 都支持 self-sizing。在 iOS 7 中,UITableViewDelegate新增了三個(gè)方法來滿足用戶設(shè)定Cell、Header和Footer預(yù)計(jì)高度的方法: - tableView:estimatedHeightForRowAtIndexPath: - tableView:estimatedHeightForHeaderInSection: - tableView:estimatedHeightForFooterInSection: 當(dāng)然對(duì)應(yīng)這三個(gè)方法 UITableView 也 estimatedRowHeight、estimatedSectionHeaderHeight 和 estimatedSectionFooterHeight 三個(gè)屬性,局限性在于只能統(tǒng)一定義所有行和節(jié)的高度。以 Cell 為例,iOS 會(huì)根據(jù)給出的預(yù)計(jì)高度來創(chuàng)建一個(gè)Cell,但等到真正要顯示它的時(shí)候,iOS 8會(huì)在 self-sizing 計(jì)算得出新的 Size 并調(diào)整 table 的 contentSize 后,將 Cell 繪制顯示出來。關(guān)鍵在于如何得出 Cell 新的 Size,iOS提供了兩種方法:自動(dòng)布局 這個(gè)兩年前推出的神器雖然在一開始表現(xiàn)不佳,但隨著 Xcode 的越來越給力,在iOS7中自動(dòng)布局儼然成了默認(rèn)勾選的選項(xiàng),通過設(shè)定一系列約束來使得我們的UI能夠適應(yīng)各種尺寸的屏幕。如果你有使用約束的經(jīng)驗(yàn),想必已經(jīng)有了解決思路:向 Cell 的 contentView 添加約束。iOS 會(huì)先調(diào)用 UIView 的 systemLayoutSizeFittingSize: 方法來根據(jù)約束計(jì)算新的Size,如果你沒實(shí)現(xiàn)約束,systemLayoutSizeFittingSize: 會(huì)接著調(diào)用sizeThatFits:方法。人工代碼 我們可以重寫sizeThatFits:方法來自己定義新的Size,這樣我們就不必學(xué)習(xí)約束相關(guān)的知識(shí)了。下面我給出了一個(gè)用 Swift 語(yǔ)言寫的 Demo-HardChoice ,使用自動(dòng)布局來調(diào)整UITableViewCell的高度。我通過實(shí)現(xiàn)一個(gè)UITableViewCell的子類DynamicCell來實(shí)現(xiàn)自動(dòng)布局,你可以再GitHub上下載源碼: import UIKit class DynamicCell: UITableViewCell { required init(coder: NSCoder) { super.init(coder: coder) if textLabel != nil { textLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline) textLabel.numberOfLines = 0 } if detailTextLabel != nil { detailTextLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) detailTextLabel.numberOfLines = 0 } } override func constraints() - [AnyObject] { var constraints = [AnyObject]() if textLabel != nil { constraints.extend(constraintsForView(textLabel)) } if detailTextLabel != nil { constraints.extend(constraintsForView(detailTextLabel)) } constraints.append(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: contentView, attribute: NSLayoutAttribute.Height, multiplier: 0, constant: 44)) contentView.addConstraints(constraints) return constraints } func constraintsForView(view:UIView) - [AnyObject]{ var constraints = [NSLayoutConstraint]() constraints.append(NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.FirstBaseline, relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.Top, multiplier: 1.8, constant: 30.0)) constraints.append(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: view, attribute: NSLayoutAttribute.Baseline, multiplier: 1.3, constant: 8)) return constraints } } 上面的代碼需要注意的是,Objective-C中的類在Swift中都可以被當(dāng)做AnyObject,這在類型兼容問題上很管用。別忘了在相應(yīng)的 UITableViewController 中的 viewDidLoad 方法中加上: self.tableView.estimatedRowHeight = 44 自適應(yīng)效果如下:UICollectionView UITableView 和 UICollectionView 都是 data-source 和 delegate 驅(qū)動(dòng)的。UICollectionView 在此之上進(jìn)行了進(jìn)一步抽象。它將其子視圖的位置,大小和外觀的控制權(quán)委托給一個(gè)單獨(dú)的布局對(duì)象。通過提供一個(gè)自定義布局對(duì)象,你幾乎可以實(shí)現(xiàn)任何你能想象到的布局。布局繼承自 UICollectionViewLayout 抽象基類。iOS 6 中以 UICollectionViewFlowLayout 類的形式提出了一個(gè)具體的布局實(shí)現(xiàn)。在 UICollectionViewFlowLayout 中,self-sizing 同樣適用:采用self-sizing后:UICollectionView 實(shí)現(xiàn) self-sizing 不僅可以通過在 Cell 的 contentView 上加約束和重寫 sizeThatFits: 方法,也能在 Cell 層面(以前都是在 contentSize 上進(jìn)行 self-sizing)上做文章:重寫 UICollectionReusableView 的preferredLayoutAttributesFittingAttributes: 方法來在 self-sizing 計(jì)算出 Size 之后再修改,這樣就達(dá)到了對(duì)Cell布局屬性(UICollectionViewLayoutAttributes)的全面控制。PS:preferredLayoutAttributesFittingAttributes: 方法默認(rèn)調(diào)整Size屬性來適應(yīng) self-sizing Cell,所以重寫的時(shí)候需要先調(diào)用父類方法,再在返回的 UICollectionViewLayoutAttributes 對(duì)象上做你想要做的修改。由此我們從最經(jīng)典的 UICollectionViewLayout 強(qiáng)制計(jì)算屬性(還記得 UICollectionViewLayoutAttributes 的一系列工廠方法么?)到使用 self-sizing 來根據(jù)我們需求調(diào)整屬性中的Size,再到重寫UICollectionReusableView(UICollectionViewCell也是繼承于它)的 preferredLayoutAttributesFittingAttributes: 方法來從Cell層面對(duì)所有屬性進(jìn)行修改:下面來說說如何在 UICollectionViewFlowLayout 實(shí)現(xiàn) self-sizing: 首先,UICollectionViewFlowLayout 增加了estimatedItemSize 屬性,這與 UITableView 中的 ”estimated...Height“ 很像(注意我用省略號(hào)囊括那三種屬性),但畢竟 UICollectionView 中的 Item 都需要約束 Height 和 Width的,所以它是個(gè) CGSIze,除了這點(diǎn)它與 UITableView 中的”estimated...Height“用法沒區(qū)別。 其...沒有其次,在 UICollectionView 中實(shí)現(xiàn) self-sizing,只需給 estimatedItemSize 屬性賦值(不能是 CGSizeZero ),一行代碼足矣。InvalidationContext 假如設(shè)備屏幕旋轉(zhuǎn),或者需要展示一些其妙的效果(比如 CoverFlow ),我們需要將當(dāng)前的布局失效,并重新計(jì)算布局。當(dāng)然每次計(jì)算都有一定的開銷,所以我們應(yīng)該謹(jǐn)慎的僅在我們需要的時(shí)候調(diào)用 invalidateLayout 方法來讓布局失效。在 iOS 6 時(shí)代,有的人會(huì)“聰明地”這樣做: - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { CGRect oldBounds = self.collectionView.bounds; if (CGRectGetWidth(newBounds) != CGRectGetWidth(oldBounds)) { return YES; } return NO; } 而 iOS 7 新加入的 UICollectionViewLayoutInvalidationContext 類聲明了在布局失效時(shí)布局的哪些部分需要被更新。當(dāng)數(shù)據(jù)源變更時(shí),invalidateEverything 和 invalidateDataSourceCounts 這兩個(gè)只讀 Bool 屬性標(biāo)記了UICollectionView 數(shù)據(jù)源“全部過期失效”和“Section和Item數(shù)量失效”,UICollectionView會(huì)將它們自動(dòng)設(shè)定并提供給你。你可以調(diào)用invalidateLayoutWithContext:方法并傳入一個(gè)UICollectionViewLayoutInvalidationContext對(duì)象,這能優(yōu)化布局的更新效率。當(dāng)你自定義一個(gè) UICollectionViewLayout 子類時(shí),你可以調(diào)用 invalidationContextClass 方法來返回一個(gè)你定義的 UICollectionViewLayoutInvalidationContext 的子類,這樣你的 Layout 子類在失效時(shí)會(huì)使用你自定義的InvalidationContext 子類來優(yōu)化更新布局。你還可以重寫 invalidationContextForBoundsChange: 方法,在實(shí)現(xiàn)自定義 Layout 時(shí)通過重寫這個(gè)方法返回一個(gè) InvalidationContext 對(duì)象。綜上所述都是 iOS 7 中新加入的內(nèi)容,并且還可以應(yīng)用在 UICollectionViewFlowLayout 中。在 iOS 8 中,UICollectionViewLayoutInvalidationContext 也被用在self-sizing cell上。iOS8 中 UICollectionViewLayoutInvalidationContext 新加入了三個(gè)方法使得我們可以更加細(xì)致精密地使某一行某一節(jié)Item(Cell)、Supplementary View 或 Decoration View 失效: invalidateItemsAtIndexPaths: invalidateSupplementaryElementsOfKind:atIndexPaths: invalidateDecorationElementsOfKind:atIndexPaths: 對(duì)應(yīng)著添加了三個(gè)只讀數(shù)組屬性來標(biāo)記上面那三種組件: invalidatedItemIndexPaths invalidatedSupplementaryIndexPaths invalidatedDecorationIndexPaths iOS自帶的照片應(yīng)用會(huì)將每一節(jié)照片的信息(時(shí)間、地點(diǎn))停留顯示在最頂部,實(shí)現(xiàn)這種將 Header 粘在頂端的功能其實(shí)就是將那個(gè) Index 的 Supplementary View 失效,就這么簡(jiǎn)單。UICollectionViewLayoutInvalidationContext 新加入的 contentOffsetAdjustment 和 contentSizeAdjustment 屬性可以讓我們更新 CollectionView 的 content 的位移和尺寸。此外 UICollectionViewLayout 還加入了一對(duì)兒方法來幫助我們使用self-sizing: shouldInvalidateLayoutForPreferredLayoutAttributes:withOriginalAttributes: invalidationContextForPreferredLayoutAttributes:withOriginalAttributes: 當(dāng)一個(gè)self-sizing Cell發(fā)生屬性發(fā)生變化時(shí),第一個(gè)方法會(huì)被調(diào)用,它詢問是否應(yīng)該更新布局(即原布局失效),默認(rèn)為NO;而第二個(gè)方法更細(xì)化的指明了哪些屬性應(yīng)該更新,需要調(diào)用父類的方法獲得一個(gè)InvalidationContext 對(duì)象,然后對(duì)其做一些你想要的修改,最后返回。試想,如果在你自定義的布局中,一個(gè)Cell的Size因?yàn)槟撤N原因發(fā)生了變化(比如由于字體大小變化),其他的Cell會(huì)由于 self-sizing 而位置發(fā)生變化,你需要實(shí)現(xiàn)上面兩個(gè)方法來讓指定的Cell更新布局中的部分屬性;別忘了整個(gè) CollectionView 的 contentSize 和 contentOffset 因此也會(huì)發(fā)生變化,你需要給 contentOffsetAdjustment 和 contentSizeAdjustment 屬性賦值。
ios14好看的桌面布局需要添加小組件,具體操作方法如下:
1、以蘋果11為例,打開iPhone手機(jī)桌面,在空白處長(zhǎng)按桌面。
2、在彈出來的內(nèi)容中,點(diǎn)擊左上角的“+”圖標(biāo)。
3、進(jìn)入iPhone手機(jī)小組件頁(yè)面后,點(diǎn)擊“照片”小組件。
4、設(shè)置照片小組件的展示樣式,再點(diǎn)擊下方的“添加小組件”。
5、設(shè)置小組件的位置后,點(diǎn)擊“完成”即可成功添加新布局。
以IPAD設(shè)置桌面布局為例:
1、需要把手機(jī)更新到iOS14,然后長(zhǎng)按桌面。
2、在彈出來的內(nèi)容中,點(diǎn)擊左上角的“+”選項(xiàng)。
3、進(jìn)入小組件頁(yè)面里,選擇要添加的小組件。
4、在小組件設(shè)置頁(yè)面里,選擇組件的類型,點(diǎn)擊下方的“添加小組件”。
5、把組件放到合適的位置,再點(diǎn)擊“完成”即可成功添加小組件。