UICollectionView 實(shí)現(xiàn)圖片瀏覽效果
一、效果展示
廢話開篇:利用 UICollectionView 簡單實(shí)現(xiàn)一個(gè)圖片瀏覽效果。

二、實(shí)現(xiàn)思路
1.封裝 UICollectionViewLayout ,實(shí)現(xiàn)內(nèi)部 UICollectionViewCell 的布局。
UICollectionViewLayout 在封裝瀑布流的時(shí)候會(huì)用到,而且擔(dān)負(fù)著核心功能的實(shí)現(xiàn)。其實(shí)從另一個(gè)角度也可以把 UICollectionViewLayout 理解成“數(shù)據(jù)源”,這個(gè)數(shù)據(jù)不是 UI 的展示項(xiàng),而是 UI 的尺寸項(xiàng)。在內(nèi)部進(jìn)行預(yù)計(jì)算 UICollectionViewCell 的 frame。
UICollectionView 是 UIScrollView的子類,只不過,它里面子控件通過“重用”機(jī)制實(shí)現(xiàn)了優(yōu)化,一些復(fù)用的復(fù)雜邏輯還是扔給了系統(tǒng)處理。開發(fā)過程中只負(fù)責(zé)對 UICollectionViewLayout 什么時(shí)候需要干什么進(jìn)行自定義即可。
2.獲取 UICollectionView 目前可見的 cells,通過進(jìn)行縮放、旋轉(zhuǎn)變換實(shí)現(xiàn)一些簡單的效果。
3、自定義 cell ,修改錨點(diǎn)屬性。
三、代碼整理
1、PhotoBrowseViewLayout
這里有一點(diǎn)需要注意的,在 UICollectionViewLayout 內(nèi)部會(huì)進(jìn)行計(jì)算每一個(gè) cell 的 frame,在計(jì)算過程中,為了更好的展示旋轉(zhuǎn)變換,cell 的錨點(diǎn)會(huì)修改到 (0.5,1),那么,為了保證 UI 展示不變,那么,就需要將 y 增加 cell 高度的一半。
#import "PhotoBrowseViewLayout.h"
@interface PhotoBrowseViewLayout()
@property(nonatomic,strong) NSMutableArray * attributeArray;
@property(nonatomic,assign) CGFloat cellWidth;
@property(nonatomic,assign) CGFloat cellHeight;
@property(nonatomic,assign) CGFloat sep;
@property(nonatomic,assign) int showCellNum;
@end
@implementation PhotoBrowseViewLayout
- (instancetype)init
{
if (self = [super init]) {
self.sep = 20;
self.showCellNum = 2;
}
return self;
}
//計(jì)算cell的frame
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (self.cellWidth == 0) {
self.cellWidth = **self**.collectionView.frame.size.width * 2 / 3.0;
}
if (self.cellHeight == 0) {
self.cellHeight = self.collectionView.frame.size.height;
}
CGFloat x = (self.cellWidth + self.sep) * indexPath.item;
//這里y值需要進(jìn)行如此設(shè)置,以抵抗cell修改錨點(diǎn)導(dǎo)致的UI錯(cuò)亂
CGFloat y = self.collectionView.frame.size.height / 2.0;
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.frame = CGRectMake(x, y, self.cellWidth, self.cellHeight);
return attrs;
}
//準(zhǔn)備布局
- (void)prepareLayout
{
[super prepareLayout];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i <count; i++) {
UICollectionViewLayoutAttributes *attris = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
[self.attributeArray addObject:attris];
}
}
//返回全部cell的布局集合
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.attributeArray;
}
//一次性提供UICollectionView 的 contentSize
- (CGSize)collectionViewContentSize
{
NSInteger count = [self.collectionView numberOfItemsInSection:0];
CGFloat maxWidth = count * self.cellWidth + (count - 1) * self.sep;
return CGSizeMake(maxWidth, 0);
}
- (NSMutableArray *)attributeArray
{
if (!_attributeArray) {
_attributeArray = [[NSMutableArray alloc] init];
}
return _attributeArray;
}
@end
2、PhotoBrowseCollectionViewCell
這里主要是進(jìn)行了錨點(diǎn)修改(0.5,1),代碼很簡單。
#import "PhotoBrowseCollectionViewCell.h"
@interface PhotoBrowseCollectionViewCell()
@property(nonatomic,strong) UIImageView * imageView;
@end
@implementation PhotoBrowseCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
//設(shè)置(0.5,1)錨點(diǎn),以底部中點(diǎn)為軸旋轉(zhuǎn)
self.layer.anchorPoint = CGPointMake(0.5, 1);
self.layer.masksToBounds = YES;
self.layer.cornerRadius = 8;
}
return self;
}
- (void)setImage:(UIImage *)image
{
self.imageView.image = image;
}
- (UIImageView *)imageView
{
if (!_imageView) {
_imageView = [[UIImageView alloc] init];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
_imageView.backgroundColor = [UIColor groupTableViewBackgroundColor];
[self.contentView addSubview:_imageView];
}
return _imageView;
}
- (void)layoutSubviews
{
[super layoutSubviews];
self.imageView.frame = **self**.contentView.bounds;
}
@end
3、CollectPhotoBrowseView
CollectPhotoBrowseView 負(fù)責(zé)進(jìn)行一些 cell 的圖形變換。
#import "CollectPhotoBrowseView.h"
#import "PhotoBrowseCollectionViewCell.h"
#import "PhotoBrowseViewLayout.h"
@interface CollectPhotoBrowseView()<UICollectionViewDelegate,UICollectionViewDataSource>
@property(nonatomic,strong) UICollectionView * photoCollectView;
@end
@implementation CollectPhotoBrowseView
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self makeUI];
}
return self;
}
- (void)makeUI{
//設(shè)置自定義 UICollectionViewLayout
PhotoBrowseViewLayout * photoBrowseViewLayout = [[PhotoBrowseViewLayout alloc] init];
self.photoCollectView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:photoBrowseViewLayout];
self.photoCollectView.delegate = self;
self.photoCollectView.dataSource = self;
[self.photoCollectView registerClass:[PhotoBrowseCollectionViewCell class] forCellWithReuseIdentifier:@"CELL"];
self.photoCollectView.showsHorizontalScrollIndicator = NO;
[self addSubview:self.photoCollectView];
//執(zhí)行一次可見cell的圖形變換
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self visibleCellTransform];
});
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 20;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoBrowseCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath];
[cell setImage: [UIImage imageNamed:[NSString stringWithFormat:@"fd%ld",indexPath.item % 3 + 1]]];
return cell;
}
#pragma mark - 滾動(dòng)進(jìn)行圖形變換
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//滑動(dòng)的時(shí)候,動(dòng)態(tài)進(jìn)行cell圖形變換
[self visibleCellTransform];
}
#pragma mark - 圖形變化
- (void)visibleCellTransform
{
//獲取當(dāng)前可見cell的indexPath集合
NSArray * visibleItems = [self.photoCollectView indexPathsForVisibleItems];
//遍歷動(dòng)態(tài)進(jìn)行圖形變換
for (NSIndexPath * visibleIndexPath in visibleItems) {
UICollectionViewCell * visibleCell = [self.photoCollectView cellForItemAtIndexPath:visibleIndexPath];
[self transformRotateWithView:visibleCell];
}
}
//進(jìn)行圖形轉(zhuǎn)換
- (void)transformRotateWithView:(UICollectionViewCell *)cell
{
//獲取cell在當(dāng)前視圖的位置
CGRect rect = [cell convertRect:cell.bounds toView:self];
//計(jì)算當(dāng)前cell中軸線與中軸線的距離的比值
float present = ((CGRectGetMidX(rect) - self.center.x) / (self.frame.size.width / 2.0));
//根據(jù)位置設(shè)置選擇角度
CGFloat radian = (M_PI_2 / 15) * present;
//圖形角度變換
CGAffineTransform transformRotate = CGAffineTransformIdentity;
transformRotate = CGAffineTransformRotate(transformRotate, radian);
//圖形縮放變換
CGAffineTransform transformScale = CGAffineTransformIdentity
transformScale = CGAffineTransformScale(transformScale,1 - 0.2 * fabs(present),1 - 0.2 * fabsf(present));
//合并變換
cell.transform = CGAffineTransformConcat(transformRotate,transformScale);
}
@end
四、總結(jié)與思考
UICollectionView 也是 View,只不過系統(tǒng)為了更好的服務(wù)于開發(fā)者,快速高效的實(shí)現(xiàn)某些開發(fā)場景,進(jìn)行了封裝與優(yōu)化,將復(fù)雜的邏輯單獨(dú)的封裝成一個(gè)管理類,這里就是 UICollectionViewLayout,交給它去做一些固定且復(fù)雜的邏輯。所以,自定義復(fù)雜UI的時(shí)候,就需要將功能模塊足夠細(xì)化,以實(shí)現(xiàn)更好的代碼銜接。
以上就是UICollectionView 實(shí)現(xiàn)圖片瀏覽效果的詳細(xì)內(nèi)容,更多關(guān)于UICollectionView 圖片瀏覽的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS報(bào)Multiple?commands?produceMultiple錯(cuò)誤的解決方案
這篇文章主要為大家介紹了iOS報(bào)Multiple?commands?produceMultiple錯(cuò)誤的解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
iOS實(shí)現(xiàn)百度地圖拖拽后更新位置以及反編碼
百度地圖已經(jīng)開放了地圖API,大家可以很方便的調(diào)用地圖中的相應(yīng)數(shù)據(jù),并完成各項(xiàng)個(gè)性化的展示,下面這篇文章主要給大家介紹了關(guān)于iOS如何實(shí)現(xiàn)百度地圖拖拽后更新位置以及反編碼的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-12-12
iOS中l(wèi)ebel特殊字符的自動(dòng)換行問題解決
這篇文章主要給大家介紹了關(guān)于iOS中l(wèi)ebel特殊字符的實(shí)現(xiàn)不自動(dòng)換行的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)iOS具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
iOS應(yīng)用中UICollectionViewCell定制Button
這篇文章主要介紹了iOS應(yīng)用中UICollectionViewCell如何定制Button,設(shè)置每行顯示的按鈕的個(gè)數(shù),自定制按鈕的顯示樣式,感興趣的小伙伴們可以參考一下2016-08-08
iOS編程學(xué)習(xí)中關(guān)于throttle的那些事
這篇文章主要給大家介紹了關(guān)于iOS編程學(xué)習(xí)中throttle的那些事,文中通過示例代碼介紹的非常詳細(xì),對各位iOS的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
iOS實(shí)現(xiàn)簡易的導(dǎo)航欄顏色漸變實(shí)例代碼
很多APP 都有導(dǎo)航欄顏色漸變的效果,下面這篇文章主要給大家介紹了關(guān)于iOS如何實(shí)現(xiàn)簡易的導(dǎo)航欄顏色漸變效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧2018-10-10

