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/
歡迎您的訪問...