iOS 循環(huán)漸進(jìn)輪播

iOS UICollectionView實(shí)現(xiàn)跑馬燈和輪播效果

功能描述:WSL_RollView 是基于UICollectionView實(shí)現(xiàn)的支持水平和垂直兩個(gè)方向上的的分頁和漸進(jìn)循環(huán)輪播效果,可以設(shè)置時(shí)間間隔、漸進(jìn)速率、是否循環(huán)、分頁寬度和間隔,還支持自定義分頁視圖的控件,用法和UICollectionView基本一樣。

一、實(shí)現(xiàn)方法

①、 首先用UICollectionView和計(jì)時(shí)器實(shí)現(xiàn)一個(gè)基本的水平滾動(dòng)效果,如下圖,這個(gè)太簡單就不在此詳述。
iOS UICollectionView
②、對比上面的效果圖,我們還需要解決分頁的寬度和循環(huán)滾動(dòng)的問題。
  • 自定義分頁寬度:默認(rèn)的分頁寬度是UICollectionView的寬度,所以當(dāng)分頁寬度的不等于UICollectionView的寬度或分頁間隔不等于0時(shí)會(huì)出現(xiàn)錯(cuò)誤,這時(shí)就需要我們通過自定義UICollectionViewFlowLayout來實(shí)現(xiàn)效果。

/** 返回值決定了collectionView停止?jié)L動(dòng)時(shí)的偏移量 手指松開后執(zhí)行
 * proposedContentOffset:原本情況下,collectionView停止?jié)L動(dòng)時(shí)最終的偏移量
 * velocity 滾動(dòng)速率,通過這個(gè)參數(shù)可以了解滾動(dòng)的方向
 */
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{
    
    if (_scrollStyle == WSLRollViewScrollStylePage) {
        CGSize size = self.collectionView.frame.size;
        // 計(jì)算可見區(qū)域的面積
        CGRect rect = CGRectMake(proposedContentOffset.x, proposedContentOffset.y, size.width, size.height);
        NSArray *array = [super layoutAttributesForElementsInRect:rect];
        // 標(biāo)記 cell 的中點(diǎn)與 UICollectionView 中點(diǎn)最小的間距
        CGFloat minDetal = MAXFLOAT;
        
        if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal){
            // 計(jì)算 CollectionView 中點(diǎn)值
            CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
            for (UICollectionViewLayoutAttributes *attrs in array){
                if (ABS(minDetal) > ABS(centerX - attrs.center.x)){
                    minDetal = attrs.center.x - centerX;
                }
            }
            return CGPointMake(proposedContentOffset.x + minDetal, proposedContentOffset.y);
        }else{
            // 計(jì)算 CollectionView 中點(diǎn)值
            CGFloat centerY = proposedContentOffset.y + self.collectionView.frame.size.height * 0.5;
            for (UICollectionViewLayoutAttributes *attrs in array){
                if (ABS(minDetal) > ABS(centerY - attrs.center.y)){
                    minDetal = attrs.center.y - centerY;
                }
            }
            return CGPointMake(proposedContentOffset.x, proposedContentOffset.y + minDetal);
        }
    }
    return proposedContentOffset;
}

  • 循環(huán)滾動(dòng):思想當(dāng)然還是3 >4 >0 >1 >2 >3 >4 >0 >1,關(guān)鍵就在于怎么確定彌補(bǔ)兩端輪播首尾相連需要增加的cell,前邊尾首相連需要UICollectionView可見范圍內(nèi)的數(shù)據(jù)源后邊的元素cell,后邊首尾相連需要UICollectionView可見范圍內(nèi)的數(shù)據(jù)源前邊的元素cell

//獲取首尾相連循環(huán)滾動(dòng)時(shí)需要用到的元素,并重組數(shù)據(jù)源
- (void)resetDataSourceForLoop{
    if(_loopEnabled == NO){
        return;
    }
    if(_scrollDirection == UICollectionViewScrollDirectionHorizontal && _collectionView.contentSize.width >= self.frame.size.width){
        //用于右側(cè)連接元素?cái)?shù)量
        _addRightCount = [_collectionView  indexPathForItemAtPoint:CGPointMake(self.frame.size.width - 1, 0)].row + 1 ;
        if (_scrollStyle == WSLRollViewScrollStylePage){
            //如果是分頁,還需要用于左側(cè)連接元素?cái)?shù)量
            _addLeftCount = _sourceArray.count - [_collectionView  indexPathForItemAtPoint:CGPointMake(_collectionView.contentSize.width - self.frame.size.width + 1, 0)].row;
        }
    }else if(_scrollDirection == UICollectionViewScrollDirectionVertical && _collectionView.contentSize.height >= self.frame.size.height){
        //用于右側(cè)連接元素?cái)?shù)量
        _addRightCount = [_collectionView  indexPathForItemAtPoint:CGPointMake(0, self.frame.size.height - 1)].row + 1 ;
        if (_scrollStyle == WSLRollViewScrollStylePage){
            //用于左側(cè)連接元素?cái)?shù)量
            _addLeftCount = _sourceArray.count - [_collectionView  indexPathForItemAtPoint:CGPointMake(0, _collectionView.contentSize.height - self.frame.size.height + 1)].row;
        }
    }
    NSArray * rightSubArray = [_sourceArray subarrayWithRange:NSMakeRange(0, _addRightCount)];
    //增加右側(cè)連接元素
    [_dataSource addObjectsFromArray:rightSubArray];
    
    if (_scrollStyle == WSLRollViewScrollStylePage){
        NSArray * leftSubArray = [_sourceArray subarrayWithRange:NSMakeRange(_sourceArray.count - _addLeftCount, _addLeftCount)];
        //增加左側(cè)連接元素
        [_dataSource insertObjects:leftSubArray atIndexes: [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,_addLeftCount)]];
    }
}

二、WSL_RollView用法

請看WSLRollView.h文件中的注釋,代理方法、屬性很明朗,用法和UICollectionView基本一樣,詳情和效果請前往我的Github查看示例:WSL_RollView

//
//  WSLRollView.h
//  WSL_RollView
//
//  Created by 王雙龍 on 2018/9/8.
//  Copyright ? 2018年 http://www.itdecent.cn/u/e15d1f644bea. All rights reserved.
//

#import <UIKit/UIKit.h>

/**
 默認(rèn)cell樣式 WSLItemID
 */
@interface WSLRollViewCell : UICollectionViewCell
@end

@class WSLRollView;

//代理協(xié)議
@protocol WSLRollViewDelegate <NSObject>
@optional
/**
 返回itemSize 默認(rèn)值是CGSizeMake(self.frame.size.width, self.frame.size.height);
 */
- (CGSize)rollView:(WSLRollView *)rollView sizeForItemAtIndex:(NSInteger)index;
/**
 item的間隔 默認(rèn)值0
 */
- (CGFloat)spaceOfItemInRollView:(WSLRollView *)rollView;
/**
 內(nèi)邊距 上 左 下 右 默認(rèn)值UIEdgeInsetsMake(0, 0, 0, 0)
 */
- (UIEdgeInsets)paddingOfRollView:(WSLRollView *)rollView;
/**
 點(diǎn)擊事件
 */
- (void)rollView:(WSLRollView *)rollView didSelectItemAtIndex:(NSInteger)index;
/**
 自定義item樣式
 */
- (WSLRollViewCell *)rollView:(WSLRollView *)rollView cellForItemAtIndex:(NSInteger )index;
@end

/**
 滾動(dòng)樣式
 */
typedef NS_ENUM(NSInteger, WSLRollViewScrollStyle) {
    WSLRollViewScrollStylePage = 0, /** 分頁 必須等寬或高*/
    WSLRollViewScrollStyleStep   /** 漸進(jìn) 可以不等寬或高*/
};

@interface WSLRollView : UIView

/**
 原始數(shù)據(jù)源
 */
@property (nonatomic, strong) NSMutableArray * sourceArray;

/**
 是否循環(huán)輪播 默認(rèn)YES
 */
@property (nonatomic, assign) BOOL loopEnabled;

/**
 輪播方向 默認(rèn)是 UICollectionViewScrollDirectionHorizontal 水平
 */
@property (nonatomic, assign) UICollectionViewScrollDirection scrollDirection;

/**
 輪播樣式 默認(rèn)是 WSLRollViewScrollStylePage 分頁
 */
@property (nonatomic, assign) WSLRollViewScrollStyle scrollStyle;

/**
 漸進(jìn)輪播速率 單位是Point/s,以坐標(biāo)系單位為準(zhǔn) 默認(rèn)60/s 如果為0 表示禁止計(jì)時(shí)器
 */
@property (nonatomic, assign) CGFloat speed;
/**
 分頁輪播間隔時(shí)長 單位是s  默認(rèn)3s 如果為0 表示禁止計(jì)時(shí)器
 */
@property (nonatomic, assign) CGFloat interval;

/**
 item的間隔 默認(rèn)值0
 */
@property (nonatomic, assign) CGFloat spaceOfItem;

/**
 內(nèi)邊距 上 左 下 右 默認(rèn)值UIEdgeInsetsMake(0, 0, 0, 0)
 */
@property (nonatomic, assign) UIEdgeInsets padding;

/** delegate*/
@property (nonatomic, weak) id<WSLRollViewDelegate> delegate;

/**
  初始化方法 direction 滾動(dòng)方向
 */
- (instancetype)initWithFrame:(CGRect)frame scrollDirection:(UICollectionViewScrollDirection)direction;

/**
 注冊item樣式 用法和UICollectionView相似
 */
- (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
/**
 注冊item樣式 用法和UICollectionView相似
 */
- (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
/**
 用于初始化和獲取WSLRollViewCell,自定義cell樣式 用法和UICollectionView相似
 */
- (WSLRollViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index;
/**
 刷新數(shù)據(jù)源
 */
- (void)reloadData;
/**
 暫停自動(dòng)輪播
 */
- (void)pause;
/**
 繼續(xù)自動(dòng)輪播
 */
- (void)play;

@end

以上就是我實(shí)現(xiàn)這個(gè)效果的過程,示例代碼請看這兒WSL_RollView;如果小伙伴們有其他的實(shí)現(xiàn)方法,歡迎再此留言交流????

推薦閱讀:
iOS UITableView/UICollectionView獲取特定位置的cell
iOS 圖片瀏覽的放大縮小
UIScrollerView當(dāng)前顯示3張圖
iOS 自定義轉(zhuǎn)場動(dòng)畫
iOS 瀑布流封裝
WKWebView的使用
UIScrollView視覺差動(dòng)畫
iOS 傳感器集錦
iOS 音樂播放器之鎖屏歌詞+歌詞解析+鎖屏效果
UIActivityViewController系統(tǒng)原生分享-仿簡書分享

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

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

  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,171評論 3 119
  • 今天把目錄整理了出來,供大家參考。 悄悄說瑪雅歷 目錄 Part1 入門:遇見瑪雅會(huì)幸福 一、13月亮28天歷是什...
    星之奇旅的馮晶晶閱讀 4,628評論 0 15
  • 說來說去,創(chuàng)始人沒理想最重要的影響就是沒有圈定一個(gè)功能范圍,對內(nèi)容型 的產(chǎn)品,除了功能外還要確定內(nèi)容的邊界。 我在...
    但我覺得有用閱讀 320評論 0 0
  • 文/拂曉晚風(fēng) 少了一份記憶 多了一份空白 哆嗦暫時(shí)失去了知覺 夢也不曾到訪 就在這個(gè)時(shí)空下 身體狠狠戳痛后依然流浪...
    拂曉晚風(fēng)閱讀 891評論 12 28

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