// // HDLCoverFlowLayout.m // CoverFlow // // Created by JLCHEN on 2019/8/26. // Copyright © 2019 JLCHEN. All rights reserved. // #import "HDLCoverFlowLayout.h" @implementation HDLCoverFlowLayout - (void)prepareLayout { [super prepareLayout]; // 1.è°ƒæ•´æ»šåŠ¨æ–¹å‘ self.scrollDirection = UICollectionViewScrollDirectionHorizontal; // 2.è®¾ç½®å¤§å° CGFloat itemH = self.collectionView.bounds.size.height * 0.8; CGFloat itemW = self.collectionView.bounds.size.width * 0.65; self.itemSize = CGSizeMake(itemW, itemH); // 3.è®¾ç½®é—´è· self.minimumLineSpacing = 0; // self.minimumInteritemSpacing = 0; // 4.è®¾ç½®å†…è¾¹è· CGFloat inset = (self.collectionView.bounds.size.width - itemW) * 0.5; // CGFloat inset = 0; self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset); } #pragma mark - 布局一定å´ä¸Žçš„cell - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { // 1.先获å–系统布局好的结果! NSArray<UICollectionViewLayoutAttributes *> *oldAttrsArr = [super layoutAttributesForElementsInRect:rect]; // 2.é历集åˆ,进行修改 // 2.1 ä¸´æ—¶é›†åˆ NSMutableArray *tempArrM = [NSMutableArray array]; // 2.2 é历集åˆ,修改属性 [oldAttrsArr enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { // 2.2.1 修改之å‰å…ˆcopy! UICollectionViewLayoutAttributes *newAttr = obj.copy; // newAttr.transform3D = CATransform3DRotate(newAttr.transform3D, M_PI_4, 0, 1, 0); // 2.2.2 修改属性! -> 缩放 & 旋转! // MARK: - 1.缩放 // - 1.å±å¹•ä¸çº¿çš„ä½ç½® CGFloat screenCenterX = self.collectionView.bounds.size.width * 0.5 + self.collectionView.contentOffset.x; // - 2.æ¯ä¸ªcellçš„ä¸å¿ƒçš„x!! CGFloat itemCenterX = newAttr.center.x; // - 3.计算è·ç¦» CGFloat distance = screenCenterX - itemCenterX; // - 4.å°†è·ç¦»è½¬æ¢æˆç¼©æ”¾çš„æ¯”例! ABS() -> å–ç»å¯¹å€¼! CGFloat scale = 1 - ABS(distance/4) / self.collectionView.bounds.size.width; // NSLog(@"scale: %f",scale); // - 5.旋转 // - 5.1 旋转的角度! CGFloat angle = (1 - scale) * M_PI_2 *2; // 如果è·ç¦»å¤§äºŽ0,左边 -> * 1,æ£çš„角度 // 如果è·ç¦»å°äºŽ0,å³è¾¹ -> * -1,负的角度! angle *= ((distance > 0) ? 1 : -1); // - å•ä½çŸ©é˜µ CATransform3D transform = CATransform3DIdentity; // - 5.3 å¢žåŠ é€è§†æ•ˆæžœ transform.m34 = - 1.0 / 500; // - 4.2 缩放 transform = CATransform3DScale(transform, scale, scale, 1); // - 5.2 旋转 transform = CATransform3DRotate(transform, angle, 0, 1, 0); // 4.3 赋值! newAttr.transform3D = transform; // 2.2.x ä¿å˜åˆ°ä¸´æ—¶é›†åˆ [tempArrM addObject:newAttr]; }]; // 3.返回 return tempArrM; } #pragma mark - åªè¦æ˜¾ç¤ºçš„区域å‘生å˜åŒ–,就釿–°è®¡ç®—布局! // Invalidate 失效! 返回YES! åªè¦æ˜¾ç¤ºçš„区域å‘生改å˜,就让布局失效! // 釿–°è®¡ç®—布局! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; } #pragma mark - 计算åœç•™çš„ä½ç½® - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // 1.获å–系统计算好的值 CGPoint point = [super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity]; // 2.计算å±å¹•å¯è§åŒºåŸŸ -> CGRect! CGRect rect; rect.size = self.collectionView.bounds.size; #warning - 预计åœç•™çš„ä½ç½®æ—¶,内容的åç§»é‡! rect.origin = proposedContentOffset; // 3.获å–å¯è§åŒºåŸŸå†…çš„cell! #warning - 利用上é¢çš„æ–¹æ³•,计算å¯è§åŒºåŸŸå†…çš„cell! NSArray<UICollectionViewLayoutAttributes *> *visibleAttrs = [self layoutAttributesForElementsInRect:rect]; // 4.éœ€è¦æ‰¾å‡ºå…¶ä¸æœ€è¿‘çš„cell! // 4.2 é历,找出è·ç¦»å±å¹•ä¸çº¿æœ€è¿‘çš„cell对应的attr // - å±å¹•ä¸çº¿çš„x CGFloat screenCenterX = proposedContentOffset.x + self.collectionView.bounds.size.width * 0.5; // - 定义一个最å°çš„é—´è· __block CGFloat minMargin = CGFLOAT_MAX; // - 定义一个索引,用æ¥è®°å½•最近那个attr的在数组ä¸!索引! __block NSInteger index = -1; [visibleAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { CGFloat distance = screenCenterX - obj.center.x; if (ABS(distance) < minMargin) { minMargin = ABS(distance); index = idx; } }]; // 5.计算需è¦å移的è·ç¦»! CGFloat offsetX = screenCenterX - visibleAttrs[index].center.x; // 2.è¿”å›žç‚¹åæ ‡ return CGPointMake(point.x - offsetX, point.y); } @end