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
