UICollectionViewを使用して画像ブラウジング効果を実現します

ナンセンスな始まり:UICollectionViewを使用して、画像ブラウジング効果を実装するだけです。

1.エフェクト表示

スクリーンレコーディング2022-07-113.34.16pm

第二に、アイデアの実現

1. UICollectionViewLayoutをカプセル化して、内部UICollectionViewCellのレイアウトを実現します。

UICollectionViewLayoutは、ウォーターフォールフローをカプセル化するときに使用され、コア関数の実装を担当します。実際、 UICollectionViewLayoutは、別の観点からは「データソース」として理解することもできます。このデータは、UIの表示項目ではなく、UIサイズ項目です。UICollectionViewCellフレームを内部的に事前計算します。

UICollectionViewUIScrollViewのサブクラスですが、その中のサブコントロールは「再利用」メカニズムによって最適化されており、再利用の複雑なロジックがシステムにスローされて処理されます。開発プロセスでは、UICollectionViewLayoutがいつ実行する必要があるかをカスタマイズする責任があるだけです。

2. UICollectionViewの現在表示されているセルを取得し、変換をスケーリングおよび回転することでいくつかの単純な効果を実現します。
3.セルをカスタマイズし、アンカープロパティを変更します。

3.コード仕上げ

1、PhotoBrowseViewLayout

ここで注意すべきことの1つは、各セルフレームがUICollectionViewLayout内で計算されることです。計算中に、回転変換をより適切に表示するために、セルのアンカーポイントが(0.5、1)に変更され、次に、UIを確実にするために、表示が変わらない場合は、セルの高さの半分だけyを増やす必要があります

#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;
}

//计算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值需要进行如此设置,以抵抗cell修改锚点导致的UI错乱
    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;
}

//准备布局
- (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

アンカーポイントの変更(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]) {
        //设置(0.5,1)锚点,以底部中点为轴旋转
        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は、いくつかのセルグラフィック変換を担当します。

#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{
    //设置自定义 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];
    //执行一次可见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 - 滚动进行图形变换
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    //滑动的时候,动态进行cell图形变换
    [self visibleCellTransform];
}

#pragma mark - 图形变化
- (void)visibleCellTransform
{
    //获取当前可见cell的indexPath集合
    NSArray * visibleItems =  [self.photoCollectView indexPathsForVisibleItems];
    //遍历动态进行图形变换
    for (NSIndexPath * visibleIndexPath in visibleItems) {
        UICollectionViewCell * visibleCell = [self.photoCollectView cellForItemAtIndexPath:visibleIndexPath];
        [self transformRotateWithView:visibleCell];
    }
}

//进行图形转换
- (void)transformRotateWithView:(UICollectionViewCell *)cell
{
    //获取cell在当前视图的位置
    CGRect rect = [cell convertRect:cell.bounds toView:self];
    //计算当前cell中轴线与中轴线的距离的比值
    float present = ((CGRectGetMidX(rect) - self.center.x) / (self.frame.size.width / 2.0));
    //根据位置设置选择角度
    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
复制代码

4.まとめと考え方

UICollectionViewビューですが、開発者により良いサービスを提供するために、システムは特定の開発シナリオを迅速かつ効率的に実装し、複雑なロジックを単一の管理クラスにカプセル化および最適化してカプセル化します複雑なロジック。したがって、複雑なUIをカスタマイズする場合は、コード接続を改善するために機能モジュールを十分に改良する必要があります。コードは不器用です、偉大な神を笑わないでください

おすすめ

転載: juejin.im/post/7119028552263008293