国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

iOS開發(fā)之窺探UICollectionViewController(五)--一款炫酷的圖片瀏覽組件

2019-11-14 18:09:07
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  本篇博客應(yīng)該算的上CollectionView的高級(jí)應(yīng)用了,從iOS開發(fā)之窺探UICollectionViewController(一)到今天的(五),可謂是由淺入深的窺探了一下UICollectionView的用法,這些用法不僅包括SDK中自帶的流式布局(UICollectionViewDelegateFlowLayout)而且介紹了如何根據(jù)你的需求去自定義屬于你自己的CollectionView。自定義的CollectionView可謂是非常靈活,其靈活性也決定了其功能的強(qiáng)大。CollectionView的自定義就是其Cell高度可定制的屬性,通過(guò)對(duì)Cell賦值不同的屬性來(lái)達(dá)到自定義的目的。

  在上篇博客iOS開發(fā)之窺探UICollectionViewController(四) --一款功能強(qiáng)大的自定義瀑布流中,通過(guò)自定義的CollectionView創(chuàng)建了一個(gè)可定制的自定義瀑布流,效果還是蠻ok的。本篇博客是使用自定義CollectionView的另一個(gè)實(shí)例,自定義CollectionView的方式和上一篇是一致的,都是重寫UICollectionViewLayout相應(yīng)的方法,然后再通過(guò)委托回調(diào)來(lái)設(shè)置布局的參數(shù)。自定義CollectionView的思路是一樣的,只是具體的實(shí)現(xiàn)方式不同。學(xué)習(xí)么,要學(xué)會(huì)舉一反三,希望大家能通過(guò)這兩篇自定義CollectionView的博客來(lái)寫出屬于你自己的自定義效果。

  一.效果展示

  廢話少說(shuō),進(jìn)入今天博客的主題,下方就是今天博客中Demo的運(yùn)行效果。雖然運(yùn)行效果做成gif丟幀了,看起來(lái)有些卡,不過(guò)跑起來(lái)還是比較流暢的。切換圖片時(shí)進(jìn)行一個(gè)360度的旋轉(zhuǎn),并且修改Cell的層級(jí),當(dāng)前顯示的圖片層級(jí)最高。并且移動(dòng)時(shí),如果要顯示的圖片不在屏幕中央就做一個(gè)位置矯正。點(diǎn)擊圖片時(shí),使用仿射變換使其放大,再點(diǎn)擊使其縮小。接下來(lái)將會(huì)詳細(xì)的介紹其實(shí)現(xiàn)方案。

  二.該自定義布局的使用方式

    我們先看一下該自定義布局是如何使用的,然后再通過(guò)使用方式來(lái)逐步介紹它是如何實(shí)現(xiàn)的。這也是一個(gè)由淺入深的過(guò)程,因?yàn)橛闷饋?lái)要比做起了更容易。比如開汽車容易,造汽車可就麻煩多了。所以在本篇博客的第二部分,將要介紹如何去使用該自定義組件

    其實(shí)所有CollectionView的自定義布局的使用方式都是一樣的,分為以下幾步:

    1.為我們的CollectionView指定該布局,本篇博客的CollectionView是通過(guò)Storyboard來(lái)實(shí)現(xiàn)的,所以我們可以通過(guò)Storyboard來(lái)指定自定義的布局文件,如果你是使用純代碼方式,可以在CollectionView實(shí)例化時(shí)來(lái)指定所需的布局。下方是使用Storyboard來(lái)指定的布局文件,需要把Layout選項(xiàng)調(diào)到Custom下,然后下方的Class選項(xiàng)就是你要關(guān)聯(lián)的自定義布局文件,具體如下所示。代碼的就在此不做贅述了,網(wǎng)上一抓一大把。

 

    2.給Storyboard上的CollectionViewController關(guān)聯(lián)一個(gè)類,然后我們就可以使用自定義的布局了。獲取指定的自定義布局對(duì)象,然后指定委托代理對(duì)象,如下所示:

1 - (void)viewDidLoad {2     [super viewDidLoad];3     4     _customeLayout = (CustomTransformCollecionLayout *) self.collectionViewLayout;5     _customeLayout.layoutDelegate = self;6 }

 

    3.除了實(shí)現(xiàn)CollectionView的DataSource和Delegate, 我們還需實(shí)現(xiàn)布局的代理方法,該自定義布局要實(shí)現(xiàn)的代理方法如下。第一個(gè)是設(shè)置Cell的大小,也就是寬高。第二個(gè)是設(shè)置Cell間的邊距。

 1 #PRagma mark <CustomTransformCollecionLayoutDelegate> 2  3 - (CGSize)itemSizeWithCollectionView:(UICollectionView *)collectionView 4                  collectionViewLayout:(CustomTransformCollecionLayout *)collectionViewLayout { 5     return CGSizeMake(200, 200); 6 } 7  8 - (CGFloat)marginSizeWithCollectionView:(UICollectionView *)collectionView 9                     collectionViewLayout:(CustomTransformCollecionLayout *)collectionViewLayout {10     return 10.0f;11 }

 

  4.點(diǎn)擊Cell放大和縮小是在UICollectionViewDataSource中點(diǎn)擊Cell的代理方法中做的,在此就不做贅述了,詳見GitHub上分享的鏈接。

 

  三. 如何實(shí)現(xiàn)

    上面介紹了如何去使用該自定義組件,接下來(lái)就是“造車”的過(guò)程了。本篇博客的第三部分介紹如何去實(shí)現(xiàn)這個(gè)自定義布局。

    1. CustomTransformCollecionLayout頭文件中的代碼如下所示,該文件中定義了一個(gè)協(xié)議,協(xié)議中的方法就是在CollectionView中要實(shí)現(xiàn)的那兩個(gè)代理方法。這些代理方法提供了Cell的大小和邊距。該文件的接口中定義了一個(gè)代理對(duì)象,當(dāng)然為了強(qiáng)引用循環(huán),該代理對(duì)象是weak類型的。

 1 // 2 //  CustomTransformCollecionLayout.h 3 //  CustomTransformCollecionLayout 4 // 5 //  Created by Mr.LuDashi on 15/9/24. 6 //  Copyright (c) 2015年 ZeluLi. All rights reserved. 7 // 8  9 #import <UIKit/UIKit.h>10 11 #define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width12 #define SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height13 14 @class CustomTransformCollecionLayout;15 16 @protocol CustomTransformCollecionLayoutDelegate <NSObject>17 /**18  * 確定cell的大小19  */20 - (CGSize) itemSizeWithCollectionView:(UICollectionView *)collectionView21                  collectionViewLayout:(CustomTransformCollecionLayout *)collectionViewLayout;22 23 /**24  * 確定cell的大小25  */26 - (CGFloat) marginSizeWithCollectionView:(UICollectionView *)collectionView27                  collectionViewLayout:(CustomTransformCollecionLayout *)collectionViewLayout;28 29 @end30 31 @interface CustomTransformCollecionLayout : UICollectionViewLayout32 33 @property (nonatomic, weak) id<CustomTransformCollecionLayoutDelegate> layoutDelegate;34 35 @end

 

    2.接下來(lái)介紹一下CustomTransformCollecionLayout實(shí)現(xiàn)文件也就是.m中的代碼,其中的延展中的屬性如下所示。numberOfSections:該參數(shù)代表著CollectionView的Section的個(gè)數(shù)。numberOfCellsInSection:代表著每個(gè)Section中Cell的個(gè)數(shù)。itemSize則是Cell的尺寸(寬高),該屬性的值是由布局代理方法提供。itemMargin: 該屬性是Cell的邊距,它也是通過(guò)布局的代理方法提供。itemsX: 用來(lái)存儲(chǔ)計(jì)算的每個(gè)Cell的X坐標(biāo)。

 1 // 2 //  CustomTransformCollecionLayout.m 3 //  CustomTransformCollecionLayout 4 // 5 //  Created by Mr.LuDashi on 15/9/24. 6 //  Copyright (c) 2015年 ZeluLi. All rights reserved. 7 // 8  9 #import "CustomTransformCollecionLayout.h"10 11 @interface CustomTransformCollecionLayout()12 13 @property (nonatomic) NSInteger numberOfSections;14 @property (nonatomic) NSInteger numberOfCellsInSection;15 @property (nonatomic) CGSize itemSize;16 @property (nonatomic) CGFloat itemMargin;18 @property (nonatomic, strong) NSMutableArray *itemsX;19 20 @end

 

    3. 在實(shí)現(xiàn)中我們需要重寫UICollectionViewLayout中相關(guān)的方法,需要重寫的方法如下:

    (1). 預(yù)加載布局方法, 該方法會(huì)在UICollectionView加載數(shù)據(jù)時(shí)執(zhí)行一次,在該方法中負(fù)責(zé)調(diào)用一些初始化函數(shù)。具體如下所示。

1 #pragma mark -- UICollectionViewLayout 重寫的方法2 - (void)prepareLayout {3     [super prepareLayout];4     5     [self initData];6     7     [self initItemsX];8 }

 

    (2).下面的方法會(huì)返回ContentSize, 說(shuō)白一些,就是CollectionView滾動(dòng)區(qū)域的大小。

1 /**2  * 該方法返回CollectionView的ContentSize的大小3  */4 - (CGSize)collectionViewContentSize {5     CGFloat width = _numberOfCellsInSection * (_itemSize.width + _itemMargin);6     return CGSizeMake(width,  SCREEN_HEIGHT);7 }

 

    (3).下方的方法是為每個(gè)Cell綁定一個(gè)UICollectionViewLayoutAttributes對(duì)象,用來(lái)設(shè)置每個(gè)Cell的屬性。

 1 /** 2  * 該方法為每個(gè)Cell綁定一個(gè)Layout屬性~ 3  */ 4 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { 5      6     NSMutableArray *array = [NSMutableArray array]; 7      8     //add cells 9     for (int i = 0; i < _numberOfCellsInSection; i++) {10         NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];11         12         UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];13         14         [array addObject:attributes];15     }16     return array;17 }

  

    (4).下方這個(gè)方法是比較重要的,重寫這個(gè)方法是為了為每個(gè)Cell設(shè)定不同的屬性值。其中transform的值是根據(jù)CollectionView的滾動(dòng)偏移量來(lái)計(jì)算的,所以在滾動(dòng)CollectionView時(shí),Cell也會(huì)跟著旋轉(zhuǎn)。具體的實(shí)現(xiàn)方案在代碼中添加了注釋,如下所示:

 1 /** 2  * 為每個(gè)Cell設(shè)置attribute 3  */ 4 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ 5      6     //獲取當(dāng)前Cell的attributes 7     UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 8      9     //獲取滑動(dòng)的位移10     CGFloat contentOffsetX = self.collectionView.contentOffset.x;11     //根據(jù)滑動(dòng)的位移計(jì)算當(dāng)前顯示的時(shí)第幾個(gè)Cell12     NSInteger currentIndex = [self countIndexWithOffsetX: contentOffsetX];13     //獲取Cell的X坐標(biāo)14     CGFloat centerX = [_itemsX[indexPath.row] floatValue];15     //計(jì)算Cell的Y坐標(biāo)16     CGFloat centerY = SCREEN_HEIGHT/2;17     18     //設(shè)置Cell的center和size屬性19     attributes.center = CGPointMake(centerX, centerY);20     attributes.size = CGSizeMake(_itemSize.width, _itemSize.height);21 22     //計(jì)算當(dāng)前偏移量(滑動(dòng)后的位置 - 滑動(dòng)前的位置)23     CGFloat animationDistance = _itemSize.width + _itemMargin;24     CGFloat change = contentOffsetX - currentIndex * animationDistance + SCREEN_WIDTH / 2 - _itemSize.width / 2;25     26     //做一個(gè)位置修正,因?yàn)楫?dāng)滑動(dòng)過(guò)半時(shí),currentIndex就會(huì)加一,就不是上次顯示的Cell的索引,所以要減去一做個(gè)修正27     if (change < 0) {28         change = contentOffsetX - (currentIndex - 1) * animationDistance + SCREEN_WIDTH/2 - _itemSize.width/2;29     }30     31     if (currentIndex == 0 && contentOffsetX <= 0) {32         change = 0;33     }34     35     //旋轉(zhuǎn)量36     CGFloat temp = M_PI * 2 * (change / (_itemSize.width + _itemMargin));37     38     //仿射變換 賦值39     attributes.transform = CGAffineTransformMakeRotation(temp);40     41     //把當(dāng)前顯示的Cell的zIndex設(shè)置成較大的值42     if (currentIndex == indexPath.row) {43         attributes.zIndex = 1000;44     } else {45         attributes.zIndex = currentIndex;46     }47     48     return attributes;49 }
View Code

 

    (5).要讓Cell隨著滾動(dòng)旋轉(zhuǎn)起來(lái),你需要重寫下面這個(gè)方法,并且返回YES。該方法返回YES意味著當(dāng)滾動(dòng)時(shí),會(huì)再次執(zhí)行上面(4)的方法,重新為每個(gè)Cell的屬性賦值。所以重寫下面的方法,并返回YES(下面的表達(dá)式也是一樣的)才可以運(yùn)動(dòng)起來(lái)呢。

1 //當(dāng)邊界發(fā)生改變時(shí),是否應(yīng)該刷新布局。如果YES則在邊界變化(一般是scroll到其他地方)時(shí),將重新計(jì)算需要的布局信息。2 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {3     return !CGRectEqualToRect(newBounds, self.collectionView.bounds);4 }

 

    (6).重寫下面的方法是為了修正CollectionView滾動(dòng)的偏移量,使當(dāng)前顯示的Cell出現(xiàn)在屏幕的中心的位置,方法如下:

 1 //修正Cell的位置,使當(dāng)前Cell顯示在屏幕的中心 2 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{ 3      4      5     //計(jì)算顯示的是第幾個(gè)Cell 6     NSInteger index = [self countIndexWithOffsetX:proposedContentOffset.x]; 7      8     CGFloat centerX = index * (_itemSize.width + _itemMargin) + (_itemSize.width/2); 9     10     proposedContentOffset.x = centerX - SCREEN_WIDTH/2;11     12     return proposedContentOffset;13 }
View Code

 

    4.下方就是我自己實(shí)現(xiàn)的方法了,也就在重寫的方法中調(diào)用的函數(shù),具體如下。

 1 #pragma mark -- 自定義的方法 2 /** 3  * 根據(jù)滾動(dòng)便宜量來(lái)計(jì)算當(dāng)前顯示的時(shí)第幾個(gè)Cell 4  */ 5 - (NSInteger) countIndexWithOffsetX: (CGFloat) offsetX{ 6     return (offsetX + (SCREEN_WIDTH / 2)) / (_itemSize.width + _itemMargin); 7 } 8  9 /**10  * 初始化私有屬性,通過(guò)代理獲取配置參數(shù)11  */12 - (void) initData{13     _numberOfSections = self.collectionView.numberOfSections;14     15     _numberOfCellsInSection = [self.collectionView numberOfItemsInSection:0];16 17     _itemSize = [_layoutDelegate itemSizeWithCollectionView:self.collectionView collectionViewLayout:self];18     19     _itemMargin = [_layoutDelegate marginSizeWithCollectionView:self.collectionView collectionViewLayout:self];20     21 }22 23 /**24  * 計(jì)算每個(gè)Cell的X坐標(biāo)25  */26 - (void) initItemsX{27     _itemsX = [[NSMutableArray alloc] initWithCapacity:_numberOfCellsInSection];28     29     for (int i = 0; i < _numberOfCellsInSection; i ++) {30         CGFloat tempX = i * (_itemSize.width + _itemMargin) + _itemSize.width/2;31         [_itemsX addObject:@(tempX)];32     }33     34     35 }

 

  至此,Demo的代碼講解完畢,經(jīng)過(guò)上述步驟,你就可以寫出上面動(dòng)畫中的自定義效果了,具體代碼會(huì)在github中進(jìn)行分享。分享鏈接如下:

  github上Demo的鏈接地址:https://github.com/lizelu/CustomTransformCollecionLayout


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 特克斯县| 兰州市| 拉孜县| 平遥县| 托克逊县| 都兰县| 且末县| 沂源县| 昌江| 永年县| 新河县| 武清区| 宁河县| 五家渠市| 石渠县| 左权县| 安庆市| 博客| 宜章县| 兴安盟| 水富县| 新昌县| 芒康县| 舟山市| 崇仁县| 梓潼县| 梁河县| 景泰县| 凉城县| 天水市| 陆河县| 长寿区| 株洲市| 昌图县| 澄城县| 宜宾县| 乐昌市| 若尔盖县| 邢台市| 右玉县| 仙居县|