主要实现的是滑动居中和点击居中两个小功能
1主要实现:自定义UICollectionViewFlowLayout代码如下
// // Card3DViewFlowLayout.m // Card3D // // Created by wangcj on 2020/9/9. // Copyright © 2020 wangcj. All rights reserved. //
#import "Card3DViewFlowLayout.h"
CGFloat ActiveDistance = 400; //垂直缩放除以系数 ,越小缩放越厉害
CGFloat ScaleFactor = 1; //缩放系数 越大缩放越大
@implementation Card3DViewFlowLayout
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
CGRect targectRect = CGRectMake(proposedContentOffset.x, 0.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
NSArray * attriArray = [super layoutAttributesForElementsInRect:targectRect];
CGFloat horizontalCenterX = proposedContentOffset.x + ([UIScreen mainScreen].bounds.size.width);
CGFloat offsetAdjustment = CGFLOAT_MAX;
for (UICollectionViewLayoutAttributes * layoutAttributes in attriArray) {
CGFloat itemHorizontalCenterX = layoutAttributes.center.x;
if (fabs(itemHorizontalCenterX-horizontalCenterX) < fabs(offsetAdjustment)) {
offsetAdjustment = itemHorizontalCenterX - horizontalCenterX;
}
}
return CGPointMake(proposedContentOffset.x , proposedContentOffset.y);
}
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray * array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect = CGRectZero;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes *attributes in array) {
CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
CGFloat normalizedDistance = fabs(distance / ActiveDistance);
CGFloat zoom = 1 - ScaleFactor * normalizedDistance;
attributes.transform3D = CATransform3DMakeScale(zoom, zoom, zoom);
}
return array;
}
//防止报错 先复制attributes
- (NSArray *)getCopyOfAttributes:(NSArray *)attributes
{
NSMutableArray *copyArr = [NSMutableArray new];
for (UICollectionViewLayoutAttributes *attribute in attributes) {
[copyArr addObject:[attribute copy]];
}
return copyArr;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return true;
}
@end
2:vc中的主要实现代码如下
// // Card3DViewController.m // Card3D // // Created by wangcj on 2020/9/9. // Copyright © 2020 wangcj. All rights reserved. //
#import "ViewController.h"
#import "Card3DCell.h"
#import "Card3DViewFlowLayout.h"
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
#define SCREEN_RATE ([UIScreen mainScreen].bounds.size.width/375.0)
static float imageHeight = 120;
static NSString * const cellID = @"CollectionViewCell";
@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
@property (nonatomic,strong) UICollectionView * collectionView;
@property (nonatomic, assign) NSIndexPath * selectedIndex ;
@property (nonatomic,strong) NSMutableArray * modelArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *appArray = [[self getDict] objectForKey:@"dictInfo"];
for (int i = 0; i < appArray.count; i++) {
[self.modelArray addObject:[NSString stringWithFormat:@"%i.png",i + 1]];
}
[self createCollectionView];
}
- (void)createCollectionView {
CGFloat pading = 30 * SCREEN_WIDTH/375;
Card3DViewFlowLayout * layout = [[Card3DViewFlowLayout alloc]init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.minimumLineSpacing = pading;
layout.minimumInteritemSpacing = pading;
layout.sectionInset = UIEdgeInsetsMake(0, (UIScreen.mainScreen.bounds.size.width - 120) / 2.0, 0, (UIScreen.mainScreen.bounds.size.width - 120) / 2.0);
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, imageHeight * SCREEN_RATE) collectionViewLayout:layout];
_collectionView.tag = 33;
_collectionView.dataSource = self;
_collectionView.delegate = self;
_collectionView.bounces = NO;
_collectionView.alwaysBounceHorizontal = NO;
_collectionView.alwaysBounceVertical = NO;
_collectionView.backgroundColor = [UIColor grayColor];
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.showsVerticalScrollIndicator = NO;
[self.view addSubview:_collectionView];
[_collectionView registerClass:[Card3DCell class] forCellWithReuseIdentifier:cellID];
}
- (NSDictionary *)getDict {
NSString * string = @"{\"dictInfo\":[{\"title\":\"你好啊\",\"url\":\"1.png\"},{\"title\":\"你好啊\",\"url\":\"2.png\"},{\"title\":\"你好啊\",\"url\":\"3.png\"},{\"title\":\"你好啊\",\"url\":\"4.png\"},{\"title\":\"你好啊\",\"url\":\"5.png\"},{\"title\":\"你好啊\",\"url\":\"6.png\"},{\"title\":\"是很好\",\"url\":\"7.png\"}]}";
NSDictionary *infoDic = [self dictionaryWithJsonString:string];
return infoDic;
}
-(NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
if (jsonString == nil) {
return nil;
}
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&err];
if(err)
{
NSLog(@"json解析失败:%@",err);
return nil;
}
return dic;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.modelArray.count;
}
- (NSMutableArray *)modelArray {
if (!_modelArray) {
_modelArray = [NSMutableArray array];
}
return _modelArray;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSString *img = self.modelArray[indexPath.row];
Card3DCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
[cell configCell:img];
return cell;
}
// 返回每个item的大小
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat CWidth = 120 * SCREEN_RATE;
CGFloat CHeight = 120 * SCREEN_RATE;
return CGSizeMake(CWidth, CHeight);
}
#pragma mark - UICollectionViewDelegate点击事件
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
CGFloat collectionViewHeight = CGRectGetWidth(self.collectionView.frame);
UICollectionViewCell * cell = [self.collectionView cellForItemAtIndexPath:indexPath];
CGPoint offset = CGPointMake(cell.center.x - collectionViewHeight/2, 0);
[self.collectionView setContentOffset:offset animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//居中
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGPoint originalTargetContentOffset = CGPointMake(targetContentOffset->x, targetContentOffset->y);
CGPoint targetCenter = CGPointMake(originalTargetContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2, CGRectGetHeight(self.collectionView.bounds) / 2);
NSIndexPath *indexPath = nil;
NSInteger i = 0;
while (indexPath == nil) {
targetCenter = CGPointMake(originalTargetContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2 + 10*i, CGRectGetHeight(self.collectionView.bounds) / 2);
indexPath = [self.collectionView indexPathForItemAtPoint:targetCenter];
i++;
}
self.selectedIndex = indexPath;
//这里用attributes比用cell要好很多,因为cell可能因为不在屏幕范围内导致cellForItemAtIndexPath返回nil
UICollectionViewLayoutAttributes *attributes = [self.collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath];
if (attributes) {
*targetContentOffset = CGPointMake(attributes.center.x - CGRectGetWidth(self.collectionView.bounds)/2, originalTargetContentOffset.y);
} else {
}
}
@end