UICollectionView 自定義布局(---照片瀏覽器)

類似于美團(tuán)的購買電影票時(shí)的滾動輪播視圖
廢話不多說,直接上效果圖:

1396426-ac86d04e97d33d7f.png

還是在這里對文章的主題UICollectionView做個簡單的介紹,官方名稱集合視圖控制器.怎么說,就是一個很牛X的Excel.現(xiàn)在你能看到的稍微復(fù)雜一點(diǎn)的蘋果主流的應(yīng)用布局 基本都是這玩意.OK,下面開始介紹它的使用方法(PS:針對的是有一定ios基礎(chǔ)的同學(xué),大神勿噴,水軍直接忽視就好)

首先你需要繼承系統(tǒng)自帶布局,有兩種(UICollectionViewLayout,UICollectionViewFlowLayout),推薦使用第二種(流水布局),要是繼承第一種,所有的布局都要自己寫,本來我們的工作就是一天的寫寫寫,說實(shí)話能少些點(diǎn),就少寫點(diǎn).我一向主張用最少的時(shí)間與精力完成上面交給的任務(wù)就好.所以,像這種一個方向的滾動還是流水布局比較方便些.下面是具體實(shí)現(xiàn)方法:


-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

{

       return YES;

}

這個方法告訴系統(tǒng)只要用戶改變了item的邊界,就要重新刷新布局,而一旦重新刷新布局就會調(diào)用.打個比方,就好比你去跑步,你跑步時(shí)總要聽音樂吧,反正我干跑我是不愛跑,總要有些動力嘛.而每首歌的不同感覺也會影響你的節(jié)奏,所以你要時(shí)刻記錄每首歌的感覺來配合自己的狀態(tài).

-(void)prepareLayout

{

   [super prepareLayout];

  //一次性初始化

  self.itemSize = CGSizeMake(YJItemSizeWH,  YJItemSizeWH);

   //NSLog(@"%d",self.collectionView.frame.size.width);

   CGFloat inset = (self.collectionView.frame.size.width - YJItemSizeWH) * 0.5;

   self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);

   self.scrollDirection = UICollectionViewScrollDirectionHorizontal;

   self.minimumLineSpacing = YJItemSizeWH;

// 每一個cell(item)都有自己的UICollectionViewLayoutAttributes

//每一個indexPath都有自己的UICollectionViewLayoutAttributes

// UICollectionViewLayoutAttributes

}

很多人會習(xí)慣于在-(void)init方法里實(shí)現(xiàn)一些初始化工作,但是這樣會引起一些錯誤.比如我們我們想實(shí)現(xiàn)一打開視圖控制器,第一張和最后一張圖片要在中間,即

1396426-ac86d04e97d33d7f.png

我們會設(shè)置它的sectionInset屬性,而左邊的寬度我們是用整個UICollectionView的寬度減去item的寬度再除以2得到的,如果在-(void)init初始化這個屬性,當(dāng)主控制器調(diào)用這個方法時(shí),UICollectionView這個寬度還沒有被創(chuàng)建出來,即寬度為0.一般這種邏輯性的bug很難被發(fā)現(xiàn),這就需要我們平時(shí)的多積累與練習(xí)才好.

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect

{

//計(jì)算可見的矩形框

   CGRect visiableRect;

   visiableRect.size = self.collectionView.frame.size;

   visiableRect.origin = self.collectionView.contentOffset;

//NSLog(@"layoutAttributesForElementsInRect --");

//我們直接拿父類默認(rèn)的屬性修改就好了,不然還得重新創(chuàng)建

   NSArray *array = [super layoutAttributesForElementsInRect:rect];

//計(jì)算屏幕最中間的x(滾出去的寬度 + collectionView寬度的一般)

   CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;

//遍歷所有的布局屬性

   for (UICollectionViewLayoutAttributes *attrs in array) {

//優(yōu)化值遍歷看得見的

   if (!CGRectIntersectsRect(visiableRect, attrs.frame)) {

continue;

}

//每一個item的中點(diǎn)x

   CGFloat itemCenterX = attrs.center.x;

//差距越小,縮放比例越大

//根據(jù)屏幕最中間的距離計(jì)算縮放比例

   CGFloat scale = 1 + 0.8 *(1 - ABS(itemCenterX - centerX) / self.collectionView.frame.size.width);

//attrs.transform3D =    CATransform3DMakeScale(scale, scale,1.0);

   attrs.transform = CGAffineTransformMakeScale(scale, scale);

 }

   return array;

}

這個方法,是返回item的布局屬性,我們對item進(jìn)行的每個動畫效果都可以在這里面設(shè)置,部分細(xì)節(jié) 可以看里面的注釋. 很重要的一點(diǎn)就是,我們要時(shí)刻注意內(nèi)存的管理與優(yōu)化,避免不必要的浪費(fèi),很多人說自己是個完美主義者,我只想說你能有我們程序猿更注重完美?!連一點(diǎn)資源,一個字母的編寫都要力求完美,生怕用戶用起來會不流暢.所以我們在遍歷每個item時(shí)候,應(yīng)該只遍歷用戶看的見的從而對他進(jìn)行3D變換,那些看不見的何必去管呢?大致思路就是:判斷可見區(qū)域的frame與item的frame是否重疊.

最后一個很特別的方法,他不屬于布局屬性,但是如果我們想設(shè)置collectionView停止?jié)L動那一刻的 位置,可以調(diào)用這個方法.

-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

{

//1.計(jì)算出scrollView最后會停留的范圍

   CGRect lastRect;

   lastRect.origin = proposedContentOffset;

   lastRect.size = self.collectionView.frame.size;

//計(jì)算屏幕最中間的x(滾出去的寬度 + collectionView寬度的一般)

   CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;

//2.取出這個范圍內(nèi)所有屬性

   NSArray *array = [self layoutAttributesForElementsInRect:lastRect];

//3.遍歷所有屬性

   CGFloat adjustOffsetX = MAXFLOAT;

   for (UICollectionViewLayoutAttributes *attrs in array) {

   if(ABS(attrs.center.x - centerX)

adjustOffsetX = attrs.center.x - centerX;

        }

}

   return CGPointMake(proposedContentOffset.x + adjustOffsetX,   proposedContentOffset.y);

}

其中,參數(shù)proposedContentOffset是原來collectionView停止?jié)L動那一刻的位置,velocity即滾動速度.

OK,這篇文章就當(dāng)練手吧,也是為了能和大家一起交流討論,希望可以共同進(jìn)步.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容