【iOS系列】- iOS吸附效果的實現 之 UICollectionView的使用全解
UICollectionView可以做很多的布局,在iOS開發中較為重要,所以這里就以實例來講解UICollectionView的使用進階。
注: 用StoryBoard拖出來的UICollectionView的布局就是流水布局,無法修改,所以如果要實現一些自定義的效果需要通過代碼創建UICollectionView
項目示例如下:效果為吸附的效果,App Store中也有類似的效果,就是單元格出來小於一半:則就讓其回退;如果大於一半:則就讓其直接移出界面顯示區域:

Demo下載地址:iOS_Demo
一些概念
UICollectionView中有個重要的內容UICollectionViewLayout,UICollectionView的顯示是由其布局文件決定的。
UICollectionViewFlowLayout:系統提供的流水布局,如果要自定義流水布局的效果可以自定義這個類。
布局決定每一個cell的尺寸,位置,間距等等。
每一個cell/item都有自己UICollectionViewLayoutAttributes
每一個indexPath也都有自己UICollectionViewLayoutAttributes
開始
所以這次做的吸附效果也完全是自定義了UICollectionViewFlowLayout,
下面對這個類的主要方法進行大體介紹:
-
prepareLayout:一些初始化的工作最好這里完成,比如item的大小等等-(void)prepareLayout { [super prepareLayout];//需要調用super方法 //初始化 self.itemSize = CGSizeMake(90, 90);//設置item的大小 self.scrollDirection = UICollectionViewScrollDirectionHorizontal;//設置滾動防線 self.minimumLineSpacing = 10;//設置cell的間距 self.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);//設置四周的間距 } -
targetContentOffsetForProposedContentOffset:控制控制最后UICollectionView的最后去哪里,我們這里需要做的吸附效果的邏輯代碼就需要在這里完成。參數介紹proposedContentOffset:原本UICollectionView停止滾動那一刻的位置;velocity:滾動速度-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { //TODO } -
shouldInvalidateLayoutForBoundsChange:邊界發生改變時,是否需要重新布局,返回YES就需要重新布局(會自動調用layoutAttributesForElementsInRect方法,獲得所有cell的布局屬性)-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
} -
layoutAttributesForElementsInRect:返回所有cell的布局屬性-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { return [super layoutAttributesForElementsInRect:rect]; }
方法介紹完畢,我們在prepareLayout
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
//1.計算scrollview最后停留的范圍
CGRect lastRect ;
lastRect.origin = proposedContentOffset;
lastRect.size = self.collectionView.frame.size;
//2.取出這個范圍內的所有屬性
NSArray *array = [self layoutAttributesForElementsInRect:lastRect];
//起始的x值,也即默認情況下要停下來的x值
CGFloat startX = proposedContentOffset.x;
//3.遍歷所有的屬性
CGFloat adjustOffsetX = MAXFLOAT;
for (UICollectionViewLayoutAttributes *attrs in array) {
CGFloat attrsX = CGRectGetMinX(attrs.frame);
CGFloat attrsW = CGRectGetWidth(attrs.frame) ;
if (startX - attrsX < attrsW/2) {
adjustOffsetX = -(startX - attrsX+ItemMaigin);
}else{
adjustOffsetX = attrsW - (startX - attrsX);
}
break ;//只循環數組中第一個元素即可,所以直接break了
}
return CGPointMake(proposedContentOffset.x + adjustOffsetX, proposedContentOffset.y);
}
這樣我們要做的吸附效果的Layout文件就完成了。
我們在初始化UICollectionView的時候選擇帶有Layout參數的init方法即可。
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:rect collectionViewLayout:viscosityLayout];
Demo地址:iOS_Demo-自定義UICollectionView的布局
Demo下載地址:iOS_Demo
注:把Demo中的ViewController.m的33行
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:rect collectionViewLayout:viscosityLayout];
改成//具體初始化的邏輯已經實現了。
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:rect collectionViewLayout:flowLayout];
即可實現下圖所示的效果(cell滾動的時候,中間會慢慢變大,也有吸附效果,不過在最中心的cell才會吸附在中心),具體做法是在layoutAttributesForElementsInRect方法中修復了布局屬性,可下載Demo自行查看。

作者:Darren
微博:@IT_攻城師
github:@Darren90
博客:http://www.cnblogs.com/fengtengfei/
歡迎您的訪問...
