collectionView 實(shí)現(xiàn)畫(huà)廊效果

效果

效果.png

標(biāo)題是collectionView,但其實(shí)這篇文章說(shuō)的是自定義FlowLayout的事??

大家都知道collectionView關(guān)于元素的事情,更多是于布局決定的。

比如滾動(dòng)方向,元素間距,元素尺寸,布局的組間距,布局的行間距(這些都決定了元素的位置)。

如果要實(shí)現(xiàn)畫(huà)廊效果只需要關(guān)心三個(gè)方法

/**
 *  當(dāng)bounds發(fā)生改變(滾動(dòng)就是改變了bounds,改變了可視區(qū))的時(shí)候是否允許刷新布局。
 *
 *  @param newBounds 
 *
 *  @return 默認(rèn)返會(huì)NO
 */
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
   return YES;
}
/**
 *  返回區(qū)域內(nèi)的cell,這個(gè)方法做根據(jù)cell距離中心點(diǎn) 來(lái)縮放
 *
 *  @param rect 區(qū)域
 *
 *  @return 區(qū)域內(nèi)的cell
 */
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    //bounds的改變就是可視范圍的改變, 那么我們?nèi)ツ每梢暦秶鷥?nèi)的cell
    NSArray *attrs = [super layoutAttributesForElementsInRect:self.collectionView.bounds];
    
    //計(jì)算每一個(gè)cell與中心點(diǎn)的距離, 并通過(guò)cell與中心點(diǎn)距離的改變來(lái)縮放cell
    for (UICollectionViewLayoutAttributes *attr in attrs) {
        CGFloat delta = fabs((attr.center.x - self.collectionView.contentOffset.x) - self.collectionView.frame.size.width * 0.5);
        
        CGFloat scale = 1 - (delta / self.collectionView.bounds.size.width * 0.5) * 0.55;
        
        attr.transform = CGAffineTransformMakeScale(scale, scale);
    }
    
    return attrs;
}
/**
 *  計(jì)算最終的偏移量, 在這個(gè)方法里做判斷最小距離自動(dòng)滾動(dòng)到中間效果
 *
 *  @param proposedContentOffset 預(yù)計(jì)偏移
 *  @param velocity              速率
 *
 *  @return 最終偏移
 */
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
    
    CGFloat collectionW = self.collectionView.bounds.size.width;
    CGFloat collectionH = self.collectionView.bounds.size.height;
    
//    1確定最終的滾動(dòng)位置
    CGPoint targetP = [super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity];
//    2利用滾動(dòng)位置去拿當(dāng)前顯示的所有元素
    CGRect rect = CGRectMake(targetP.x, 0, collectionW, collectionH);
    NSArray<UICollectionViewLayoutAttributes *> *attrs = [super layoutAttributesForElementsInRect:rect];
    
//    3獲取所有滾動(dòng)元素距離中心點(diǎn)的最小值
    CGFloat minDelta = MAXFLOAT;
    for (UICollectionViewLayoutAttributes *attr in attrs) {
        CGFloat delta = attr.center.x - targetP.x - collectionW * 0.5;
        
        if (fabs(delta) < fabs(minDelta))
            minDelta = delta;
    }
    
//    4用最終的偏移量加最小值 形成自動(dòng)滑動(dòng)的效果
    targetP.x += minDelta;
    if (targetP.x < 0)
        targetP.x = 0;
        
    return targetP;
}
bounds
bounds的origin是可以改變的,取決于有沒(méi)有可視范圍外的可滾動(dòng)區(qū)域。
scrollView的滾動(dòng)是通過(guò)可視范圍的改變(bounds)來(lái)實(shí)現(xiàn)滾動(dòng)的。

想要實(shí)現(xiàn)這個(gè)效果的朋友直接自定義FlowLayout,重寫(xiě)以上三個(gè)方法即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容