iOS collection的UICollectionViewFlowLayout居中顯示, 左右cell 各顯示一部分
阿新 • • 發佈:2020-12-21
swift 版本
class JYCollectFlowLayout: UICollectionViewFlowLayout { override func prepare() { let itemWidth = (self.collectionView?.frame.width ?? 0) - 40 let itemHeight = (self.collectionView?.frame.height ?? 0) self.itemSize = CGSize(width: itemWidth, height: itemHeight) } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } // override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { //// var newAttrubtArr: [UICollectionViewLayoutAttributes] = [] //// if let attrubtArr = super.layoutAttributesForElements(in: rect) { //// for attrubt in attrubtArr { //// attrubt.transform = CGAffineTransform(scaleX: 0.9, y: 1) //// newAttrubtArr.append(attrubt) //// } //// } //// return newAttrubtArr // } override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { let rect = CGRect(x: proposedContentOffset.x, y: 0, width: self.collectionView?.frame.width ?? 0, height: self.collectionView?.frame.height ?? 0) let centerX = proposedContentOffset.x + (self.collectionView?.frame.width ?? 0) * 0.5 - 20 var minpace: CGFloat = CGFloat(MAXFLOAT) if let tempArr = super.layoutAttributesForElements(in: rect) { for attrubt in tempArr { if abs(attrubt.center.x - centerX) < abs(minpace) { minpace = attrubt.center.x - centerX; } } } return CGPoint(x: proposedContentOffset.x + minpace - 20 , y: proposedContentOffset.y) } }
OC版本
.h 檔案
@interface DoubleFestivalRechargeLayout : UICollectionViewFlowLayout @end
.m檔案
@implementation DoubleFestivalRechargeLayout - (instancetype)init { if (self = [super init]) { } return self; } - (void)prepareLayout { [super prepareLayout]; // 垂直滾動 self.scrollDirection = UICollectionViewScrollDirectionHorizontal; self.minimumInteritemSpacing = 20; // 設定collectionView裡面內容的內邊距(上、左、下、右) CGFloat inset = (self.collectionView.frame.size.width - 2*self.itemSize.width) /3; self.sectionInset = UIEdgeInsetsMake(inset, inset, inset, inset); } - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; } - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { // 拿到系統已經幫我們計算好的佈局屬性陣列,然後對其進行拷貝一份,後續用這個新拷貝的陣列去操作 NSArray * originalArray = [super layoutAttributesForElementsInRect:rect]; NSArray * curArray = [[NSArray alloc] initWithArray:originalArray copyItems:YES]; // 計算collectionView中心點的y值(這個中心點可不是螢幕的中線點哦,是整個collectionView的,所以是包含在螢幕之外的偏移量的哦) CGFloat centerY = self.collectionView.contentOffset.y + self.collectionView.frame.size.height * 0.5; // 拿到每一個cell的佈局屬性,在原有佈局屬性的基礎上,進行調整 for (UICollectionViewLayoutAttributes *attrs in curArray) { // cell的中心點y 和 collectionView最中心點的y值 的間距的絕對值 CGFloat space = ABS(attrs.center.y - centerY); // 根據間距值 計算 cell的縮放比例 // 間距越大,cell離螢幕中心點越遠,那麼縮放的scale值就小 CGFloat scale = 1 - space / self.collectionView.frame.size.height; // 設定縮放比例 attrs.transform = CGAffineTransformMakeScale(scale, scale); } return curArray; } - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // 計算出停止滾動時(不是鬆手時)最終顯示的矩形框 CGRect rect; rect.origin.y = proposedContentOffset.y; rect.origin.x = 0; rect.size = self.collectionView.frame.size; // 獲得系統已經幫我們計算好的佈局屬性陣列 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 計算collectionView最中心點的y值 // 再囉嗦一下,這個proposedContentOffset是系統幫我們已經計算好的,當我們鬆手後它慣性完全停止後的偏移量 CGFloat centerY = proposedContentOffset.y + self.collectionView.frame.size.height * 0.5; // 當完全停止滾動後,離中點Y值最近的那個cell會通過我們多給出的偏移量回到螢幕最中間 // 存放最小的間距值 // 先將間距賦值為最大值,這樣可以保證第一次一定可以進入這個if條件,這樣可以保證一定能鬧到最小間距 CGFloat minSpace = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { if (ABS(minSpace) > ABS(attrs.center.y - centerY)) { minSpace = attrs.center.y - centerY; } } // 修改原有的偏移量 proposedContentOffset.y += minSpace; return proposedContentOffset; } @end