版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.04.27 星期六 |
前言
iOS中有關視圖控件用戶能看到的都在UIKit框架里面兴猩,用戶交互也是通過UIKit進行的。感興趣的參考上面幾篇文章。
1. UIKit框架(一) —— UIKit動力學和移動效果(一)
2. UIKit框架(二) —— UIKit動力學和移動效果(二)
3. UIKit框架(三) —— UICollectionViewCell的擴張效果的實現(xiàn)(一)
4. UIKit框架(四) —— UICollectionViewCell的擴張效果的實現(xiàn)(二)
5. UIKit框架(五) —— 自定義控件:可重復使用的滑塊(一)
6. UIKit框架(六) —— 自定義控件:可重復使用的滑塊(二)
7. UIKit框架(七) —— 動態(tài)尺寸UITableViewCell的實現(xiàn)(一)
8. UIKit框架(八) —— 動態(tài)尺寸UITableViewCell的實現(xiàn)(二)
9. UIKit框架(九) —— UICollectionView的數(shù)據異步預加載(一)
10. UIKit框架(十) —— UICollectionView的數(shù)據異步預加載(二)
11. UIKit框架(十一) —— UICollectionView的重用、選擇和重排序(一)
12. UIKit框架(十二) —— UICollectionView的重用跨算、選擇和重排序(二)
13. UIKit框架(十三) —— 如何創(chuàng)建自己的側滑式面板導航(一)
14. UIKit框架(十四) —— 如何創(chuàng)建自己的側滑式面板導航(二)
15. UIKit框架(十五) —— 基于自定義UICollectionViewLayout布局的簡單示例(一)
Step 3: Adoptng the CustomLayout
在構建和運行項目之前,您需要:
- 使集合視圖采用
CustomLayout
類椭懊。 - 使
JungleCupCollectionViewController
支持自定義補充視圖supplementary views
诸蚕。
打開Main.storyboard
并在Jungle Cup Collection View Controller Scene
中選擇Collection View Flow Layout
,如下所示:
接下來灾搏,打開Identity Inspector
并將Custom Class
更改為CustomLayout
挫望,如下所示:
接下來立润,打開JungleCupCollectionViewController.swift
狂窑。
添加計算屬性customLayout
以避免詳細代碼重復。
您的代碼應如下所示:
var customLayout: CustomLayout? {
return collectionView?.collectionViewLayout as? CustomLayout
}
接下來桑腮,使用以下內容替換setUpCollectionViewLayout()
:
private func setupCollectionViewLayout() {
guard let collectionView = collectionView,
let customLayout = customLayout else {
return
}
// 1
collectionView.register(
UINib(nibName: "HeaderView", bundle: nil),
forSupplementaryViewOfKind: CustomLayout.Element.header.kind,
withReuseIdentifier: CustomLayout.Element.header.id
)
collectionView.register(
UINib(nibName: "MenuView", bundle: nil),
forSupplementaryViewOfKind: CustomLayout.Element.menu.kind,
withReuseIdentifier: CustomLayout.Element.menu.id
)
// 2
customLayout.settings.itemSize = CGSize(width: collectionView.frame.width, height: 200)
customLayout.settings.headerSize = CGSize(width: collectionView.frame.width, height: 300)
customLayout.settings.menuSize = CGSize(width: collectionView.frame.width, height: 70)
customLayout.settings.sectionsHeaderSize = CGSize(width: collectionView.frame.width, height: 50)
customLayout.settings.sectionsFooterSize = CGSize(width: collectionView.frame.width, height: 50)
customLayout.settings.isHeaderStretchy = true
customLayout.settings.isAlphaOnHeaderActive = true
customLayout.settings.headerOverlayMaxAlphaValue = CGFloat(0)
customLayout.settings.isMenuSticky = true
customLayout.settings.isSectionHeadersSticky = true
customLayout.settings.isParallaxOnCellsEnabled = true
customLayout.settings.maxParallaxOffset = 60
customLayout.settings.minimumInteritemSpacing = 0
customLayout.settings.minimumLineSpacing = 3
}
以下是上面代碼的作用:
- 1) 首先泉哈,注冊用于彈性標題和自定義菜單的自定義類。 這些是已在初始項目中實現(xiàn)的
UICollectionReusableView
子類破讨。 - 2) 最后丛晦,設置
CustomLayout
設置的大小,行為和間距sizes, behaviours and spacings
提陶。
在構建運行應用程序之前烫沙,將以下兩個case
選項添加到viewForSupplementaryElementOfKind(_:viewForSupplementaryElementOfKind:at :)
以處理自定義補充視圖類型:
case CustomLayout.Element.header.kind:
let topHeaderView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: CustomLayout.Element.header.id,
for: indexPath)
return topHeaderView
case CustomLayout.Element.menu.kind:
let menuView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: CustomLayout.Element.menu.id,
for: indexPath)
if let menuView = menuView as? MenuView {
menuView.delegate = self
}
return menuView
做得好! 這是一段漫長的旅程隙笆,但你差不多完成了锌蓄。
構建并運行項目! 您應該看到類似于以下內容的內容:
入門項目中的UICollectionView
現(xiàn)在有一些額外的功能:
- 在頂部有一個巨大的標題顯示叢林杯的標志撑柔。
- 在這之下瘸爽,有一個帶有四個按鈕的菜單,每個團隊一個铅忿。 如果點擊按鈕剪决,集合視圖將重新加載相應的團隊。
你已經做得很好檀训,但你可以做得更好柑潦。 現(xiàn)在是時候為你的UICollectionView
打造一些漂亮的視覺效果了。
Adding Stretchy, Sticky and Parallax Effects
在本UICollectionViewLayout
教程的最后一部分中峻凫,您將添加以下視覺效果:
- 1) 使
header
有彈性妒茬。 - 2) 在菜單和
section headers
中添加粘性效果。 - 3) 實現(xiàn)平滑的視差效果蔚晨,使用戶界面更具吸引力乍钻。
注意:
UICollectionViewLayout
教程的以下部分暗示了仿射變換的基本知識肛循。
1. Affine Transforms
Core Graphics
CGAffineTransform API
是將視覺效果應用于UICollectionView
元素的最佳方式。
由于各種原因银择,仿射變換非常有用:
- 1) 它們允許您在極少數(shù)代碼行中創(chuàng)建復雜的視覺效果多糠,如平移,縮放和旋轉浩考,或三者的組合夹孔。
- 2) 它們以完美的方式與
UIKit
組件和AutoLayout
進行互操作。 - 3) 它們可幫助您在復雜情況下保持最佳性能析孽。
仿射變換背后的數(shù)學真的很酷搭伤。 但是,解釋CGATransform
幕后矩陣的工作方式超出了本UICollectionViewLayout
教程的范圍袜瞬。
如果您對此主題感興趣怜俐,可以在 Apple’s Core Graphic Framework Documentation中找到更多詳細信息。
2. Transforming Visible Attributes
打開CustomLayout.swift
并將layoutAttributesForElements(in :)
更新為以下內容:
override public func layoutAttributesForElements(
in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let collectionView = collectionView else {
return nil
}
visibleLayoutAttributes.removeAll(keepingCapacity: true)
// 1
let halfHeight = collectionViewHeight * 0.5
let halfCellHeight = cellHeight * 0.5
// 2
for (type, elementInfos) in cache {
for (indexPath, attributes) in elementInfos {
// 3
attributes.parallax = .identity
attributes.transform = .identity
// 4
updateSupplementaryViews(
type,
attributes: attributes,
collectionView: collectionView,
indexPath: indexPath)
if attributes.frame.intersects(rect) {
// 5
if type == .cell,
settings.isParallaxOnCellsEnabled {
updateCells(attributes, halfHeight: halfHeight, halfCellHeight: halfCellHeight)
}
visibleLayoutAttributes.append(attributes)
}
}
}
return visibleLayoutAttributes
}
以下是對上述情況的逐步說明:
- 1) 您存儲一些有用的值以避免在循環(huán)中計算它們邓尤。
- 2) 這與此方法的先前版本相同拍鲤。 您迭代所有緩存的屬性。
- 3) 重置為默認值視差
parallax
變換和元素屬性transform
汞扎。 - 4) 目前季稳,您只需調用一種方法來更新不同類型的補充視圖
(supplementary views)
。 您將在此代碼塊之后實現(xiàn)它澈魄。 - 5) 檢查當前屬性是否屬于一個單元格景鼠。 如果在布局設置中激活了視差效果,請調用方法以更新其屬性痹扇。 如上所述辩恼,您將在此代碼塊之后實現(xiàn)此方法璃饱。
接下來,是時候實現(xiàn)上面循環(huán)中調用的兩個方法了:
updateSupplementaryViews(_:attributes:collectionView:indexPath:)
updateCells(_:halfHeight:halfCellHeight:)
添加以下內容:
private func updateSupplementaryViews(_ type: Element,
attributes: CustomLayoutAttributes,
collectionView: UICollectionView,
indexPath: IndexPath) {
// 1
if type == .sectionHeader,
settings.isSectionHeadersSticky {
let upperLimit =
CGFloat(collectionView.numberOfItems(inSection: indexPath.section))
* (cellHeight + settings.minimumLineSpacing)
let menuOffset = settings.isMenuSticky ? menuSize.height : 0
attributes.transform = CGAffineTransform(
translationX: 0,
y: min(upperLimit,
max(0, contentOffset.y - attributes.initialOrigin.y + menuOffset)))
}
// 2
else if type == .header,
settings.isHeaderStretchy {
let updatedHeight = min(
collectionView.frame.height,
max(headerSize.height, headerSize.height - contentOffset.y))
let scaleFactor = updatedHeight / headerSize.height
let delta = (updatedHeight - headerSize.height) / 2
let scale = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
let translation = CGAffineTransform(
translationX: 0,
y: min(contentOffset.y, headerSize.height) + delta)
attributes.transform = scale.concatenating(translation)
if settings.isAlphaOnHeaderActive {
attributes.headerOverlayAlpha = min(
settings.headerOverlayMaxAlphaValue,
contentOffset.y / headerSize.height)
}
}
// 3
else if type == .menu,
settings.isMenuSticky {
attributes.transform = CGAffineTransform(
translationX: 0,
y: max(attributes.initialOrigin.y, contentOffset.y) - headerSize.height)
}
}
依次記錄每個編號的注釋:
- 1) 測試當前元素是否為
section header
。 然后球化,如果在布局設置中激活粘性行為促绵,則計算transform
又厉。 最后將計算值分配給屬性的transform
屬性菠镇。 - 2) 與上面相同的例程,但這次檢查元素是否是
top header
禀梳。 如果激活了彈性效果杜窄,請執(zhí)行變換計算。 - 3) 同樣的例程算途。 這次執(zhí)行粘性菜單的變換計算塞耕。
現(xiàn)在是時候transform
集合視圖單元格了:
private func updateCells(_ attributes: CustomLayoutAttributes,
halfHeight: CGFloat,
halfCellHeight: CGFloat) {
// 1
let cellDistanceFromCenter = attributes.center.y - contentOffset.y - halfHeight
// 2
let parallaxOffset = -(settings.maxParallaxOffset * cellDistanceFromCenter)
/ (halfHeight + halfCellHeight)
// 3
let boundedParallaxOffset = min(
max(-settings.maxParallaxOffset, parallaxOffset),
settings.maxParallaxOffset)
// 4
attributes.parallax = CGAffineTransform(translationX: 0, y: boundedParallaxOffset)
}
下面進行細分:
- 1) 計算單元格與集合視圖中心
center
的距離。 - 2) 在最大視差
parallax
值(在布局設置中設置)中按比例映射單元格與中心的距離 - 3) 綁定
parallaxOffset
以避免視覺故障嘴瓤。 - 4) 使用計算的視差
parallax
值創(chuàng)建CAAffineTransform
轉換扫外。 最后莉钙,將translation
分配給單元格的屬性的transform
屬性。
為了實現(xiàn)對PlayerCell
的視差效果筛谚,圖像的frame
應具有頂部和底部負間距磁玉。 在初始項目中,為您設置了這些約束驾讲。 您可以在Constraint
檢查器中查看它們(見下文)蚊伞。
在構建之前,您必須修復一個最終細節(jié)吮铭。 打開JungleCupCollectionViewController.swift
时迫。 在setupCollectionViewLayout()
內部更改以下值:
customLayout.settings.headerOverlayMaxAlphaValue = CGFloat(0)
為下面
customLayout.settings.headerOverlayMaxAlphaValue = CGFloat(0.6)
此值表示布局可以分配給headerView
上的黑色疊加層的最大不透明度值。
構建并運行項目以欣賞所有視覺效果谓晌。 滾動吧掠拳! 滾動吧!
如果您想了解有關自定義UICollectionViewLayout
的更多信息扎谎,請考慮閱讀 Collection View Programming Guide for iOS中的Creating Custom Layouts
部分碳想,該部分詳細介紹了此主題烧董。
后記
本篇主要講述了基于自定義UICollectionViewLayout布局的簡單示例毁靶,感興趣的給個贊或者關注~~~