UICollectionView(二)——應(yīng)用UICollectionView實(shí)現(xiàn)一個(gè)簡(jiǎn)單的相冊(cè)

前言

趁著這幾天學(xué)習(xí)UICollectionView,也跟著別人的例子自己做了下關(guān)于UICollectionView應(yīng)用的Demo。下面要講的就是通過(guò)UICollectionView實(shí)現(xiàn)一個(gè)簡(jiǎn)單的相冊(cè)。上篇對(duì)理論知識(shí)已經(jīng)寫得比較完善了,所以本篇重點(diǎn)講例子的實(shí)現(xiàn)。


先看最終效果圖。該相冊(cè)只有一行圖片,可以左右滑動(dòng)瀏覽圖片,并且圖片滑到中間時(shí)會(huì)發(fā)生形變,到整個(gè)view的中點(diǎn)時(shí)達(dá)到峰值。而且體驗(yàn)更友好的一點(diǎn)是當(dāng)某圖片接近view中點(diǎn)時(shí)會(huì)自動(dòng)滑到view的中點(diǎn),感覺(jué)像被吸過(guò)去一樣。

photos.gif

思路

  • 1.確定相冊(cè)的基本布局通過(guò)UICollectionView實(shí)現(xiàn);
  • 2.自定義UICollectionViewFlowLayout布局視圖。我們可以看出某張圖片的大小(layoutAttribute的transform屬性值)是和它的位置有某種關(guān)系的。它們之間的算法我們?cè)趌ayoutAttributesForElementsInRect方法里完成,從而正確的展示圖片大小。
  • 3.注意一定要實(shí)現(xiàn)下面這個(gè)方法,不然滑動(dòng)時(shí)圖片大小是不會(huì)發(fā)生大小形變的,因?yàn)槟J(rèn)這個(gè)方法返回NO。只有返回YES時(shí),只要該layout哪里有布局屬性發(fā)生變化,便會(huì)重新加載該layout,從而實(shí)現(xiàn)實(shí)時(shí)更新layout布局界面。
// 當(dāng)布局屬性改變時(shí)重新加載layout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}
  • 4.所謂圖片滑到view中點(diǎn)有吸附感,其實(shí)就是判斷某item滑動(dòng)終止時(shí)的位置距離view的center是否達(dá)到了一個(gè)臨界點(diǎn),若達(dá)到了就把該item的位置改為view的中點(diǎn)即可。

上代碼

布局UICollectionView,搭建相冊(cè)的基本界面。

// create collectionView
- (void)loadCollectionView
{
    _flowLayout = [[YWPhotoFlowLayout alloc] init];
    _flowLayout.itemSize = CGSizeMake(200, 200);
    _flowLayout.minimumInteritemSpacing = 5.0f;
    _flowLayout.minimumLineSpacing = 5.0f;
    _flowLayout.sectionInset = UIEdgeInsetsMake(-50.f, 50.f, 5.f, 50.f);
    _flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

    _collectionView = [[UICollectionView alloc] initWithFrame:(CGRect){0,150.f,self.view.frame.size.width, 250} collectionViewLayout:_flowLayout];
    _collectionView.backgroundColor = [UIColor lightGrayColor];
    _collectionView.dataSource = self;
    _collectionView.delegate = self;
    [self.view addSubview:_collectionView];
    
    [_collectionView registerClass:[YWPhotoCell class] forCellWithReuseIdentifier:photoCellId];
}


#pragma mark ---- UICollectionViewDataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return _imgsArray.count;
}


- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    YWPhotoCell *photoCell = [_collectionView dequeueReusableCellWithReuseIdentifier:photoCellId forIndexPath:indexPath];
    
    photoCell.image = (UIImage *)_imgsArray[indexPath.row];

    return photoCell;
}

創(chuàng)建自定義布局類YWPhotoFlowLayout,注釋在代碼中寫得比較詳細(xì),所以在這不解釋。

#import "YWPhotoFlowLayout.h"

#define MinValue 100.f

@interface YWPhotoFlowLayout ()

@end


@implementation YWPhotoFlowLayout

- (id)init
{
    if(self = [super init])
    {
    }
    
    return self;
}


- (void)prepareLayout
{
    [super prepareLayout];
    
//  self.minimumInteritemSpacing = 5.0f;
//  self.minimumLineSpacing = 5.0f;
//  self.sectionInset = UIEdgeInsetsMake(0.f, 5.f, 5.f, 5.f);
//  self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    
}

// 當(dāng)布局改變時(shí)重新加載layout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}


// 對(duì)layoutAttrute根據(jù)需要做調(diào)整,也許是frame,alpha,transform等
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    // 獲取父類原先的(未放大形變的)attrsArray,我們要對(duì)其attr的frame屬性做下調(diào)整
    NSArray *attrsArray = [super layoutAttributesForElementsInRect:rect];
    CGFloat centerX = self.collectionView.frame.size.width*0.5 + self.collectionView.contentOffset.x;
    
    for(UICollectionViewLayoutAttributes *attr in attrsArray)
    {
        CGFloat length = 0.f;
        if(attr.center.x > centerX)
        {
            length = attr.center.x - centerX;
        }
        else
        {
            length = centerX - attr.center.x;
        }
        
        CGFloat scale = 1 - length / self.collectionView.frame.size.width;
        
        attr.transform = CGAffineTransformMakeScale(scale, scale);
    }
    
    return attrsArray;
}


- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    // 某cell滑動(dòng)停止時(shí)的最終rect
    CGRect rect;
    rect.origin.x = proposedContentOffset.x;
    rect.origin.y = 0.f;
    rect.size = self.collectionView.frame.size;
    
    // 計(jì)算collectionView最中心點(diǎn)的x值
    CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
    
    // 獲得super已經(jīng)計(jì)算好的布局屬性
    CGFloat offset = 0.0f;
    NSArray *attrsArray = [super layoutAttributesForElementsInRect:rect];
    for(UICollectionViewLayoutAttributes *attr in attrsArray)
    {
        if(attr.center.x - centerX > MinValue || centerX - attr.center.x > MinValue)
        {
            offset = attr.center.x - centerX; // 此刻,cell的center的x和此刻CollectionView的中心點(diǎn)的距離
        }
    }
    
    proposedContentOffset.x += offset;
    
    return proposedContentOffset;
}


@end

補(bǔ)充

我在寫這個(gè)Demo的時(shí)候遇到了下圖這個(gè)很蛋疼的問(wèn)題:
背景色為藍(lán)色的是layout,它的布局是OK的。但是自定義的cell位置確實(shí)亂的。


IMG_0068.jpg

這個(gè)問(wèn)題耽誤了好久,才突然被我找到問(wèn)題所在了。。。重寫的初始化方法initWithFrame傳進(jìn)來(lái)的frame值的x和y值并不是0,所以在下面一行創(chuàng)建UIImageView的initWithFrame直接傳入這個(gè)frame當(dāng)然會(huì)有問(wèn)題。把frame改為bounds就OK了。


屏幕快照 2015-12-04 下午6.21.28.png

感覺(jué)這是我個(gè)我很容易犯的毛病,所以記錄下來(lái)。下面是改正完善后的自定義cell的代碼:

#import "YWPhotoCell.h"

@interface YWPhotoCell ()
{
    UIImageView     *_imageView;
}
@end


@implementation YWPhotoCell


- (id)initWithFrame:(CGRect)frame
{
    if(self = [super initWithFrame:frame])
    {
        _imageView = [[UIImageView alloc] initWithFrame:self.bounds];
        // 給UIImageView加個(gè)圖層,使其有相框的效果
        _imageView.layer.borderColor = [UIColor whiteColor].CGColor;
        _imageView.layer.borderWidth = 5.0f;
        _imageView.contentMode = UIViewContentModeScaleToFill;
        [self.contentView addSubview:_imageView];
        
        self.backgroundColor = [UIColor blueColor];
    }
    
    return self;
}


#pragma mark ---- setter/getter

- (void)setImage:(UIImage *)image
{
    if(_image != image)
    {
        _image = image;
        _imageView.image = image;
    }
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,026評(píng)論 4 61
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,725評(píng)論 25 709
  • 世上最好的事情 是愛(ài)有回應(yīng) 沒(méi)有人告訴我 長(zhǎng)大以后的我們 會(huì)做著平凡的工作,談一場(chǎng)不怎么樣的戀愛(ài) 上學(xué)的時(shí)候的確寫...
    李天樂(lè)閱讀 849評(píng)論 0 0
  • 晚冬來(lái),風(fēng)雪皆至。枝上紅梅開(kāi),不怯寒。 初夏在,山雨欲來(lái)。街頭紅顏好,且懼炎。
    他眼里有星河閱讀 467評(píng)論 2 3
  • 第六章 勞動(dòng)關(guān)系管理 第四節(jié)企業(yè)勞動(dòng)爭(zhēng)議處理
    紅楓醉秋2閱讀 236評(píng)論 0 1

友情鏈接更多精彩內(nèi)容