iOS UICollectionView實(shí)現(xiàn)跑馬燈和輪播效果
功能描述:WSL_RollView 是基于UICollectionView實(shí)現(xiàn)的支持水平和垂直兩個(gè)方向上的的分頁(yè)和漸進(jìn)循環(huán)輪播效果,可以設(shè)置時(shí)間間隔矢否、漸進(jìn)速率饮焦、是否循環(huán)、分頁(yè)寬度和間隔勒虾,還支持自定義分頁(yè)視圖的控件,用法和UICollectionView基本一樣瘸彤。
一修然、實(shí)現(xiàn)方法
①、 首先用UICollectionView和計(jì)時(shí)器實(shí)現(xiàn)一個(gè)基本的水平滾動(dòng)效果质况,如下圖愕宋,這個(gè)太簡(jiǎn)單就不在此詳述。
iOS UICollectionView
②结榄、對(duì)比上面的效果圖中贝,我們還需要解決分頁(yè)的寬度和循環(huán)滾動(dòng)的問題。
- 自定義分頁(yè)寬度:默認(rèn)的分頁(yè)寬度是UICollectionView的寬度臼朗,所以當(dāng)分頁(yè)寬度的不等于UICollectionView的寬度或分頁(yè)間隔不等于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){
//如果是分頁(yè)跪呈,還需要用于左側(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用法
請(qǐng)看WSLRollView.h文件中的注釋,代理方法庆械、屬性很明朗薇溃,用法和UICollectionView基本一樣,詳情和效果請(qǐng)前往我的Github查看示例:WSL_RollView
//
// WSLRollView.h
// WSL_RollView
//
// Created by 王雙龍 on 2018/9/8.
// Copyright ? 2018年 http://www.reibang.com/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, /** 分頁(yè) 必須等寬或高*/
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 分頁(yè)
*/
@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;
/**
分頁(yè)輪播間隔時(shí)長(zhǎng) 單位是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;
/**
注冊(cè)item樣式 用法和UICollectionView相似
*/
- (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
/**
注冊(cè)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è)效果的過程,示例代碼請(qǐng)看這兒WSL_RollView堕绩;如果小伙伴們有其他的實(shí)現(xiàn)方法策幼,歡迎再此留言交流????
推薦閱讀:
iOS UITableView/UICollectionView獲取特定位置的cell
iOS 圖片瀏覽的放大縮小
UIScrollerView當(dāng)前顯示3張圖
iOS 自定義轉(zhuǎn)場(chǎng)動(dòng)畫
iOS 瀑布流封裝
WKWebView的使用
UIScrollView視覺差動(dòng)畫
iOS 傳感器集錦
iOS 音樂播放器之鎖屏歌詞+歌詞解析+鎖屏效果
UIActivityViewController系統(tǒng)原生分享-仿簡(jiǎn)書分享