123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- //
- // TXCarouselViewLayout.m
- // HJCarouselDemo
- //
- // Created by 新华龙mac on 2018/1/17.
- // Copyright © 2018年 新华龙mac. All rights reserved.
- //
- #import "TXCarouselViewLayout.h"
- #define INTERSPACEPARAM 0.90
- @interface TXCarouselViewLayout ()
- @property (nonatomic, assign) CGFloat collectionViewWidth;
- @property (nonatomic, assign) CGFloat itemWidth;
- @property (nonatomic, assign) CGFloat lastDirectionIndex;
- @property (nonatomic, assign) CGFloat slidDistance;
- @property (nonatomic, strong) NSIndexPath *lastIndexOne;
- @end
- @implementation TXCarouselViewLayout
- /**
- * 当collectionView的显示范围发生改变的时候,是否需要重新刷新布局
- * 一旦重新刷新布局,就会重新调用下面的方法
- 1.prepareLayout
- 2.layoutAttributesForElementsInRect:方法
- */
- - (void)prepareLayout{
- [super prepareLayout];
- self.visibleCount = 9;
- self.collectionViewWidth = CGRectGetWidth(self.collectionView.frame);
- self.itemWidth = self.itemSize.width;
- // self.itemWidth = self.itemSize.width;
- }
- - (CGSize)collectionViewContentSize{
- NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
- if (self.scrollDirection == UICollectionViewScrollDirectionVertical){
- return CGSizeMake(CGRectGetWidth(self.collectionView.frame), cellCount * self.itemWidth);
- }
- return CGSizeMake(cellCount * self.itemWidth, CGRectGetHeight(self.collectionView.frame));
- }
- /**
- * 这个方法的返回值是一个数组(数组里面存放着rect范围内所有元素的布局属性)
- * 这个数组中存放的都是UICollectionViewLayoutAttributes对象
- * 这个方法的返回值决定了rect范围内所有元素的排布(frame)
- * */
- - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
-
- NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
- CGFloat centerX = self.collectionView.contentOffset.x + self.collectionViewWidth / 2;
- NSInteger totalCount = centerX / self.itemWidth;
- NSInteger count = (self.visibleCount) / 2;
- NSInteger minIndex = MAX(0, (totalCount - count));
- NSInteger maxIndex = MIN((cellCount - 1), (totalCount + count));
- // NSLog(@"minIndex = %ld maxIndex = %ld",minIndex,maxIndex);
- NSMutableArray *array = [NSMutableArray array];
- for (NSInteger i = minIndex; i <= maxIndex; i++){
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
- UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
- [array addObject:attributes];
- }
- return array;
- //
-
- }
- //返回每个cell的中心值和 缩放系数
- - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
-
- UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
- attributes.size = self.itemSize;
- CGFloat cX = self.collectionView.contentOffset.x + self.collectionViewWidth / 2;
- CGFloat attributesX = self.itemWidth * indexPath.row + self.itemWidth / 2;//
- attributes.zIndex = -ABS(attributesX - cX);
- CGFloat delta = cX - attributesX;
- CGFloat ratio = - delta / (self.itemWidth * 2);
- CGFloat scale = 0.6 - ABS(delta) / (self.itemWidth * 6.0) * cos(ratio * M_2_PI*0.9);
- attributes.transform = CGAffineTransformMakeScale(scale, scale);
- CGFloat centerY = attributesX;
- // NSLog(@"scale= %f",scale);
- // NSLog(@"indexPath = %ld",(long)indexPath.row);
- // NSLog(@"self.lastIndexOne = %ld",(long)self.lastIndexOne.row);
- // NSLog(@"scale ======== %f",scale);
- if (scale>0.999){//滑动到最前面时, 交换持有者
- self.lastIndexOne = indexPath;
- }
- if (self.lastIndexOne == indexPath){
- CGFloat index1 = 0.0f;
- if ([self judgeDirection:centerY]){
- index1 = 2;
- }else{
- index1 = -2;
- }
- centerY = cX + sin(ratio * 1.31) * self.itemWidth * INTERSPACEPARAM*2.2+index1;
- //双保险,如果滑动急快的情况下,方法没有获取到最高点的坐标会导致判断失败scale>0.999 实效,
- //所以启用判断scale <= 0.84加以纠正。(且只有在上述方法实效的情况下调用,所以不能使用|| ,不然有冲突,)
- if (scale <= 0.84){
- if ([self judgeDirection:centerY]){
- NSIndexPath *indexNext = [NSIndexPath indexPathForRow:self.lastIndexOne.row+1 inSection:0];
- self.lastIndexOne = indexNext;
- }else{
- NSIndexPath *indexNext = [NSIndexPath indexPathForRow:self.lastIndexOne.row-1 inSection:0];
- self.lastIndexOne = indexNext;
- }
- }
- if (scale <=0.9172) {
- CGFloat sinIndex = sin(ratio * 1.31) * self.itemWidth * INTERSPACEPARAM*2.7+index1;
- if ([self judgeDirection:centerY]) {
- centerY = centerY-(sinIndex+(self.itemSize.width*96/124));
- }else{
- centerY = centerY-(sinIndex-(self.itemSize.width*96/124));
- }
- }
- self.lastDirectionIndex = centerY;
- }else{
- centerY = cX + sin(ratio * 1.217) * self.itemWidth * INTERSPACEPARAM;
- }
- attributes.center = CGPointMake(centerY, CGRectGetHeight(self.collectionView.frame) / 2);
- return attributes;
-
- }
- /**
- * 这个方法的返回值,就决定了collectionView停止滚动时的偏移量
- * 这个方法在滚动松手的那一刻调用
- */
- - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{
-
- // NSLog(@"proposedContentOffset = (%f,%f)",proposedContentOffset.x,proposedContentOffset.y);
- // NSLog(@"velocity = (%f,%f)",velocity.x,velocity.y);
- CGFloat index = roundf((proposedContentOffset.x + self.collectionViewWidth / 2 - self.itemWidth / 2) / self.itemWidth);
- // NSLog(@"test1 = %f",proposedContentOffset.x + self.collectionViewWidth / 2 - self.itemWidth / 2);
- // NSLog(@"test2 = %f",(proposedContentOffset.x + self.collectionViewWidth / 2 - self.itemWidth / 2) / self.itemWidth);
- // [index intVelue];
- // NSLog(@"self.collectionViewWidth = %f",self.collectionViewWidth);
- // NSLog(@"self.itemWidth = %f",self.itemWidth);
- // NSLog(@"indexindexindexindex = %f",index);
- proposedContentOffset.x = self.itemWidth * index + self.itemWidth / 2 - self.collectionViewWidth / 2;
- // proposedContentOffset 预计的位置(滚动结束时)
-
- NSInteger i = (NSInteger)index;
- [[NSNotificationCenter defaultCenter] postNotificationName:@"ThisIsANoticafication" object:@{@"parameter":@(i)}];
-
- // //leon 回调i值
- // NSInteger i = (NSInteger)index;
- // if (self.TargetScrollEnd){
- // self.TargetScrollEnd(i);
- // }
-
- return proposedContentOffset;
-
- }
- //判断滑动的方向(yes往左,no为右);
- -(BOOL)judgeDirection:(CGFloat)index{
-
- if (self.lastDirectionIndex>index){
- NSLog(@"滑动 = YES");
- return YES;
- }else{
- NSLog(@"滑动 = NO");
- return NO;
- }
- }
- - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
- return YES;
- }
- @end
|