iOS使用UICollectionView實(shí)現(xiàn)橫向滾動(dòng)照片效果
本文實(shí)例為大家分享了iOS使用UICollectionView實(shí)現(xiàn)橫向滾動(dòng)展示照片的具體代碼,供大家參考,具體內(nèi)容如下
這是Demo鏈接
效果圖
思路
1. 界面搭建
界面的搭建十分簡(jiǎn)單,采用UICollectionView和自定義cell進(jìn)行搭建即可。
// ViewController.m // 下面使用到的宏和全局變量 #define ScreenW [UIScreen mainScreen].bounds.size.width #define ScreenH [UIScreen mainScreen].bounds.size.height static NSString *const cellID = @"cellID"; // 創(chuàng)建collectionView的代碼 - (void)setupCollectionView { // 使用系統(tǒng)自帶的流布局(繼承自UICollectionViewLayout) UICollectionViewFlowLayout *layout = ({ UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; // 每個(gè)cell的大小 layout.itemSize = CGSizeMake(180, 180); // 橫向滾動(dòng) layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; // cell間的間距 layout.minimumLineSpacing = 40; //第一個(gè)cell和最后一個(gè)cell居中顯示(這里我的Demo里忘記改了我用的是160,最后微調(diào)數(shù)據(jù)cell的大小是180) CGFloat margin = (ScreenW - 180) * 0.5; layout.sectionInset = UIEdgeInsetsMake(0, margin, 0, margin); layout; }); // 使用UICollectionView必須設(shè)置UICollectionViewLayout屬性 UICollectionView *collectionView = ({ UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; collectionView.center = self.view.center; collectionView.bounds = CGRectMake(0, 0, ScreenW, 200); collectionView.backgroundColor = [UIColor brownColor]; // 這里千萬(wàn)記得在interface哪里寫(xiě)<UICollectionViewDataSource>?。?! collectionView.dataSource = self; [collectionView setShowsHorizontalScrollIndicator:NO]; [self.view addSubview:collectionView]; collectionView; }); // 實(shí)現(xiàn)注冊(cè)cell,其中PhotoCell是我自定義的cell,繼承自UICollectionViewCell UINib *collectionNib = [UINib nibWithNibName:NSStringFromClass([PhotoCell class]) bundle:nil]; [collectionView registerNib:collectionNib forCellWithReuseIdentifier:cellID]; } // UICollectionViewCellDataSource - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 10; } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; // 圖片名是 0 ~ 9 cell.imageName = [NSString stringWithFormat:@"%ld", (long)indexPath.row]; return cell; }
// 界面是一個(gè)xib文件,在cell里拖了個(gè)ImageView,約束上下左右都是10 // 圖片名是數(shù)字 0 ~ 9 // PhotoCell.h @property (nonatomic, strong) NSString *imageName; // PhotoCell.m @interface PhotoCell () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation PhotoCell - (void)awakeFromNib { [super awakeFromNib]; // Initialization code } - (void)setImageName:(NSString *)imageName { _imageName = imageName; self.imageView.image = [UIImage imageNamed:imageName]; }
到這里最基礎(chǔ)的效果就實(shí)現(xiàn)完了,一組大小相等的圖片cell。
2.大小變化已經(jīng)居中效果實(shí)現(xiàn)
由于系統(tǒng)的UICollectionViewFlowLayout無(wú)法實(shí)現(xiàn)我想要的效果,因此我重寫(xiě)下該類(lèi)中的某些方法。
在UICollectionViewLayout中有這樣兩句注釋?zhuān)?
1. Methods in this class are meant to be overridden and will be called by its collection view to gather layout information.
在這個(gè)類(lèi)中的方法意味著被重寫(xiě)(overridden),并且將要被它的 collection view 調(diào)用,用于收集布局信息
2. To get the truth on the current state of the collection view, call methods on UICollectionView rather than these.
要獲取 collection view 的當(dāng)前狀態(tài)的真相,調(diào)用UICollectionView上的方法,而不是這些
其中有一點(diǎn)需要解釋下,collectionView的bounds的x和y實(shí)際上就是collectionView的內(nèi)容視圖的 x和y。關(guān)于這點(diǎn),請(qǐng)看我寫(xiě)的一篇博文的解釋?zhuān)篿OS bounds學(xué)習(xí)筆記以及仿寫(xiě)UIScrollView的部分功能
// MyFlowLayout.h #import <UIKit/UIKit.h> // 注意!繼承自UICollectionViewFlowLayout,因?yàn)樗^承自UICollectionViewLayout。 @interface TWLayout : UICollectionViewFlowLayout // MyFlowLayout.m /** * The default implementation of this method returns NO. Subclasses can override it and return an appropriate value based on whether changes in the bounds of the collection view require changes to the layout of cells and supplementary views. 此方法的默認(rèn)實(shí)現(xiàn)返回NO。 子類(lèi)可以覆蓋它,并根據(jù) collection view 的 bounds 中的更改是否需要更改 cells 和 supplementary views(補(bǔ)充視圖) 的布局返回適當(dāng)?shù)闹怠? * If the bounds of the collection view change and this method returns YES, the collection view invalidates the layout by calling the invalidateLayoutWithContext: method. 如果 collection view 的 bounds 更改并且此方法返回YES,則 collection view 通過(guò)調(diào)用invalidateLayoutWithContext:方法使布局更新。 @param newBounds The new bounds of the collection view. @return YES if the collection view requires a layout update or NO if the layout does not need to change. */ - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; } /** * Returns the layout attributes for all of the cells and views in the specified rectangle. 返回指定矩形中所有cells和views的布局屬性。 @param rect * The rectangle (specified in the collection view's coordinate system) containing the target views. 包含目標(biāo)視圖的矩形(在集合視圖的坐標(biāo)系中指定)。 @return * An array of UICollectionViewLayoutAttributes objects representing the layout information for the cells and views. The default implementation returns nil. UICollectionViewLayoutAttributes對(duì)象數(shù)組,表示cell和view的布局信息。默認(rèn)實(shí)現(xiàn)返回nil。 */ - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { // 獲取collectionView的寬帶 CGFloat collectionW = self.collectionView.bounds.size.width; // 獲取布局屬性數(shù)組 NSArray<UICollectionViewLayoutAttributes *> *attrs = [super layoutAttributesForElementsInRect:self.collectionView.bounds]; for (int i = 0; i < attrs.count; i++) { UICollectionViewLayoutAttributes *attr = attrs[i]; //每個(gè)顯示的cell距離中心距離 CGFloat margin = fabs((attr.center.x - self.collectionView.contentOffset.x) - collectionW * 0.5); // 縮放比例:(margin / (collectionW * 0.5))得出的結(jié)論相當(dāng)于 0 ~ 1。而我們需要它的縮放比例是 1 ~ 0.65,這樣就是 (1 - 0)~(1 - 0.35) CGFloat scale = 1 - (margin / (collectionW * 0.5)) * 0.35; attr.transform = CGAffineTransformMakeScale(scale, scale); } return attrs; } /** * Returns the point at which to stop scrolling. * 關(guān)于這個(gè)方法,最終的偏移量,并不是由手指滑動(dòng)過(guò)的偏移量決定的。如果手指滑動(dòng)比較快,手指滑動(dòng)過(guò)后,視圖還會(huì)多滾動(dòng)一段距離;如果手指滑動(dòng)緩慢,手指滑到何處,就停到何處。 @param proposedContentOffset 建議的點(diǎn)(在集合視圖的內(nèi)容視圖的坐標(biāo)空間中)用于可見(jiàn)內(nèi)容的左上角。 這表示集合視圖計(jì)算為在動(dòng)畫(huà)結(jié)束時(shí)最可能使用的值。 @param velocity 沿著水平軸和垂直軸的當(dāng)前滾動(dòng)速度。 該值以每秒點(diǎn)數(shù)為單位。 @return 要使用的內(nèi)容偏移量。 此方法的默認(rèn)實(shí)現(xiàn)返回proposedContentOffset參數(shù)中的值。 */ - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // 獲取collectionView的寬度 CGFloat collectionW = self.collectionView.bounds.size.width; // 獲取當(dāng)前的內(nèi)容偏移量 CGPoint targetP = proposedContentOffset; // 獲取顯示cell的布局屬性數(shù)組,橫向滾動(dòng),所以只用考慮橫向的x和width,縱向不用考慮 NSArray *attrs = [super layoutAttributesForElementsInRect:CGRectMake(targetP.x, 0, collectionW, MAXFLOAT)]; // 距離中心點(diǎn)最近的cell的間距(中間那個(gè)cell距離最近,值可正可負(fù)) CGFloat minSpacing = MAXFLOAT; for (UICollectionViewLayoutAttributes *attr in attrs) { // 距離中心點(diǎn)的偏移量 CGFloat centerOffsetX = attr.center.x - targetP.x - collectionW * 0.5; // fabs():CGFloat絕對(duì)值 if (fabs(centerOffsetX) < fabs(minSpacing)) { minSpacing = centerOffsetX; } } targetP.x += minSpacing; return targetP; }
最后,記得把 UICollectionViewFlowLayout 改成你自定義的FlowLayout對(duì)象!!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- iOS實(shí)現(xiàn)卡片式滾動(dòng)效果 iOS實(shí)現(xiàn)電影選片效果
- iOS ScrollView嵌套tableView聯(lián)動(dòng)滾動(dòng)的思路與最佳實(shí)踐
- iOS自定義時(shí)間滾動(dòng)選擇控件
- iOS自定義水平滾動(dòng)條、進(jìn)度條
- iOS自定義可展示、交互的scrollView滾動(dòng)條
- iOS仿網(wǎng)易新聞滾動(dòng)導(dǎo)航條效果
- iOS Swift UICollectionView橫向分頁(yè)滾動(dòng),cell左右排版問(wèn)題詳解
- iOS?實(shí)現(xiàn)類(lèi)似抖音滾動(dòng)效果
相關(guān)文章
阿里數(shù)據(jù)iOS端啟動(dòng)速度優(yōu)化心得
本篇文章給大家詳細(xì)分析了阿里數(shù)據(jù)iOS端啟動(dòng)速度優(yōu)化的知識(shí)點(diǎn)以及心得,對(duì)此有興趣的朋友參考學(xué)習(xí)下吧。2018-02-02IOS UI學(xué)習(xí)教程之設(shè)置UITextField各種屬性
這篇文章主要為大家詳細(xì)介紹了IOS UI學(xué)習(xí)教程之設(shè)置UITextField各種屬性,感興趣的小伙伴們可以參考一下2016-03-03IOS關(guān)于大型網(wǎng)站搶購(gòu)、距活動(dòng)結(jié)束,剩余時(shí)間倒計(jì)時(shí)的實(shí)現(xiàn)代碼
這篇文章主要介紹了IOS關(guān)于大型網(wǎng)站搶購(gòu)、距活動(dòng)結(jié)束,剩余時(shí)間倒計(jì)時(shí)的實(shí)現(xiàn)代碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08iOS自動(dòng)進(jìn)行View標(biāo)記的方法詳解
這篇文章主要給大家介紹了關(guān)于iOS自動(dòng)進(jìn)行View標(biāo)記的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位iOS開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04iOS 水波紋動(dòng)畫(huà)的實(shí)現(xiàn)效果
本篇文章主要介紹了iOS 水波紋的實(shí)現(xiàn)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01Objective-C實(shí)現(xiàn)無(wú)限循環(huán)輪播器
這篇文章主要介紹了Objective-C實(shí)現(xiàn)無(wú)限循環(huán)輪播器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05iOS仿支付寶芝麻信用分?jǐn)?shù)儀表盤(pán)動(dòng)畫(huà)效果
這篇文章主要為大家詳細(xì)介紹了iOS仿支付寶芝麻信用分?jǐn)?shù)儀表盤(pán)動(dòng)畫(huà)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09iOS開(kāi)發(fā)系列--通知與消息機(jī)制詳解
這篇文章主要介紹了iOS開(kāi)發(fā)系列--通知與消息機(jī)制詳解,有需要的同學(xué)可以了解一下。2016-11-11iOS開(kāi)發(fā)中實(shí)現(xiàn)hook消息機(jī)制的方法探究
這篇文章主要介紹了iOS開(kāi)發(fā)中實(shí)現(xiàn)hook消息機(jī)制的方法探究,這里用到了一個(gè)Method Swizzling原理,需要的朋友可以參考下2015-10-10iOS三級(jí)聯(lián)動(dòng)選擇器的實(shí)現(xiàn)代碼示例
本篇文章主要介紹了iOS三級(jí)聯(lián)動(dòng)選擇器的實(shí)現(xiàn)代碼示例,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下2017-09-09