1.設計思想
Snip20150903_1.png
1.1 首先,這是個水平布局 ,只是相對于普通流水布局多了一個水平縮放功能的實現.
1.2 通過視圖可以看出來, 圖片在中心處處于最大,并且隨著移動圖片的尺寸也會發生變化.
1.3 所以需要對系統的流水布局進行一定修改,讓其能夠實現這種功能. 需要自定義流水布局
1.4 怎么對流水布局進行修改呢?有沒有提供方法進行重寫呢?
1.4.1 在類中只提供了一些屬性,并沒有提供方法進行重寫
1.4.2 在其父類進行尋求,發現分類方法中提供了重寫方法
// 意思是:返回 一組為給定區域中所有的控件的布局特性屬性 (此方法,是對其布局屬性進行設定.所以,只要對其進行重寫,讓每個控件擁有一定的布局屬性)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
UICollectionViewLayoutAttributes// 布局屬性
// 可以理解為一種模型, 其模型中有以下屬性(每個 cell 根據這些屬性來設定它的相關參數) (和 tableView 一樣,每個 cell 都對應一個模型,根據模型在進行設定 cell 的相關像是) (在 collectionView 中的 cell 的相關布局模型就是這個布局屬性.所以說,collectionView 比tableView 更高級.它是由兩個模型進行設定的,一個是布局模型(設置其相關布局),一個是內容模型(設置其相關模型) )
@property (nonatomic) CGRect frame;
@property (nonatomic) CGPoint center;
@property (nonatomic) CGSize size;
@property (nonatomic) CATransform3D transform3D;
@property (nonatomic) CGRect bounds;
@property (nonatomic) CGAffineTransform transform;
@property (nonatomic) CGFloat alpha;
// 重寫方法
// 返回區域內每一個元素的布局屬性 (重寫的話, 相當于 要給每一個元素增添屬性)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
// 系統父類寫的方法, 系統子類必須調用父類,進行執行(只是對部分屬性進行修改,所以不必一個個進行設置布局屬性)
NSArray *layoutAtts = [super layoutAttributesForElementsInRect:rect];
CGFloat collectionViewCenterX = self.collectionView.bounds.size.width * 0.5;
CGFloat contentOffsetX = self.collectionView.contentOffset.x;
for (UICollectionViewLayoutAttributes *layoutAtt in layoutAtts) {
CGFloat centerX = layoutAtt.center.x;
// 形變值,根據當前cell 距離中心位置,的遠近 進行反比例縮放。 (不要忘記算其偏移量的值。)
CGFloat scale = 1 - ABS((centerX - collectionViewCenterX - contentOffsetX)/self.collectionView.bounds.size.width);
// 給 布局屬性 添加形變
layoutAtt.transform = CGAffineTransformMakeScale(scale, scale);
}
return layoutAtts;
}
1.5 發現及時設置屬性,但是依然不會進行安排的屬性進行設置,需要執行以下方法. (實時更改 bounds) [為什么沒有實時更新呢, 是因為上面的方法,只會在第一次調用,以及使勁拖拽的時候才會調用]
// 是否允許 運行時,(在無效(未確定)的layout 情況下)改變bounds
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
- 現在實現另一個功能.想讓每次都有一個圖片放在 collectionView 的中間,也就是總有一張大的圖片.,也就是上圖的情況. (需要讓其停止拖拽的時候, 讓圖片的偏移量 進行一定的修改, 離中線最近的 cell, 移至中心). 關于偏移量的方法, 我們找到其相關方法,再次進行重寫的
// 通過目標移動的偏移量, 提取期望偏移量 (一般情況下,期望偏移量,就是 目標偏移量)
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
// 根據偏移量 , 確定區域
CGRect rect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.frame.size.width, self.collectionView.frame.size.height);
// 將屏幕所顯示區域的 元素布局 取出。
NSArray *layoutAtts = [super layoutAttributesForElementsInRect:rect];
CGFloat minMargin = MAXFLOAT;
CGFloat collectionViewCenterX = self.collectionView.frame.size.width * 0.5;
CGFloat contentOffsetX = proposedContentOffset.x;
// 取出區域內元素, 并根據其中心位置, 與視圖中心位置 進行比較, 比出最小的距離差
for (UICollectionViewLayoutAttributes *layoutAtt in layoutAtts) {
CGFloat margin = layoutAtt.center.x - contentOffsetX - collectionViewCenterX;
if (ABS(margin) < ABS(minMargin)) {
minMargin = margin;
}
}
NSLog(@"%f",minMargin);
// 期望偏移量 加上差值, 讓整體,沿差值 反方向移動,這樣的話, 最近的一個,剛好在中心位置
proposedContentOffset.x += minMargin;
return proposedContentOffset;
}