功能概述和預覽
功能描述:WSL_RollView 是基於UICollectionView實現的支持水平和垂直兩個方向上的的分頁和漸進循環輪播效果,可以設置時間間隔、漸進速率、是否循環、分頁寬度和間隔,還支持高度自定義分頁視圖的控件。
一、實現方法
1.1、 首先用UICollectionView和計時器實現一個基本的水平滾動效果,如下圖,這個太簡單就不在此詳述。
1.2、對比上面的效果圖,我們還需要解決分頁的寬度和循環滾動的問題。
- 自定義分頁寬度:默認的分頁寬度是UICollectionView的寬度,所以當分頁寬度的不等於UICollectionView的寬度或分頁間隔不等於0時會出現錯誤,這時就需要我們通過自定義UICollectionViewFlowLayout來實現效果。
/** 返回值決定了collectionView停止滾動時的偏移量 手指松開后執行
* proposedContentOffset:原本情況下,collectionView停止滾動時最終的偏移量
* velocity 滾動速率,通過這個參數可以了解滾動的方向
*/
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{
if (_scrollStyle == WSLRollViewScrollStylePage) {
CGSize size = self.collectionView.frame.size;
// 計算可見區域的面積
CGRect rect = CGRectMake(proposedContentOffset.x, proposedContentOffset.y, size.width, size.height);
NSArray *array = [super layoutAttributesForElementsInRect:rect];
// 標記 cell 的中點與 UICollectionView 中點最小的間距
CGFloat minDetal = MAXFLOAT;
if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal){
// 計算 CollectionView 中點值
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{
// 計算 CollectionView 中點值
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;
}
- 循環滾動:思想當然還是3 >4 >0 >1 >2 >3 >4 >0 >1,關鍵就在於怎么確定彌補兩端輪播首尾相連需要增加的cell,前邊尾首相連需要UICollectionView可見范圍內的數據源后邊的元素cell,后邊首尾相連需要UICollectionView可見范圍內的數據源前邊的元素cell
//獲取首尾相連循環滾動時需要用到的元素,並重組數據源
- (void)resetDataSourceForLoop{
if(_loopEnabled == NO){
return;
}
if(_scrollDirection == UICollectionViewScrollDirectionHorizontal && _collectionView.contentSize.width >= self.frame.size.width){
//用於右側連接元素數量
_addRightCount = [_collectionView indexPathForItemAtPoint:CGPointMake(self.frame.size.width - 1, 0)].row + 1 ;
if (_scrollStyle == WSLRollViewScrollStylePage){
//如果是分頁,還需要用於左側連接元素數量
_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){
//用於右側連接元素數量
_addRightCount = [_collectionView indexPathForItemAtPoint:CGPointMake(0, self.frame.size.height - 1)].row + 1 ;
if (_scrollStyle == WSLRollViewScrollStylePage){
//用於左側連接元素數量
_addLeftCount = _sourceArray.count - [_collectionView indexPathForItemAtPoint:CGPointMake(0, _collectionView.contentSize.height - self.frame.size.height + 1)].row;
}
}
NSArray * rightSubArray = [_sourceArray subarrayWithRange:NSMakeRange(0, _addRightCount)];
//增加右側連接元素
[_dataSource addObjectsFromArray:rightSubArray];
if (_scrollStyle == WSLRollViewScrollStylePage){
NSArray * leftSubArray = [_sourceArray subarrayWithRange:NSMakeRange(_sourceArray.count - _addLeftCount, _addLeftCount)];
//增加左側連接元素
[_dataSource insertObjects:leftSubArray atIndexes: [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,_addLeftCount)]];
}
}
二、WSL_RollView用法
請看WSLRollView.h文件中的注釋,屬性和用法很明朗,詳情和效果可以看代碼。
//
// WSLRollView.h
// WSL_RollView
//
// Created by 王雙龍 on 2018/9/8.
// Copyright © 2018年 https://www.jianshu.com/u/e15d1f644bea. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
默認cell樣式 WSLItemID
*/
@interface WSLRollViewCell : UICollectionViewCell
@end
@class WSLRollView;
//代理協議
@protocol WSLRollViewDelegate <NSObject>
@optional
/**
返回itemSize 默認值是CGSizeMake(self.frame.size.width, self.frame.size.height);
*/
- (CGSize)rollView:(WSLRollView *)rollView sizeForItemAtIndex:(NSInteger)index;
/**
item的間隔 默認值0
*/
- (CGFloat)spaceOfItemInRollView:(WSLRollView *)rollView;
/**
內邊距 上 左 下 右 默認值UIEdgeInsetsMake(0, 0, 0, 0)
*/
- (UIEdgeInsets)paddingOfRollView:(WSLRollView *)rollView;
/**
點擊事件
*/
- (void)rollView:(WSLRollView *)rollView didSelectItemAtIndex:(NSInteger)index;
/**
自定義item樣式
*/
- (WSLRollViewCell *)rollView:(WSLRollView *)rollView cellForItemAtIndex:(NSInteger )index;
@end
/**
滾動樣式
*/
typedef NS_ENUM(NSInteger, WSLRollViewScrollStyle) {
WSLRollViewScrollStylePage = 0, /** 分頁 必須等寬或高*/
WSLRollViewScrollStyleStep /** 漸進 可以不等寬或高*/
};
@interface WSLRollView : UIView
/**
原始數據源
*/
@property (nonatomic, strong) NSMutableArray * sourceArray;
/**
是否循環輪播 默認YES
*/
@property (nonatomic, assign) BOOL loopEnabled;
/**
輪播方向 默認是 UICollectionViewScrollDirectionHorizontal 水平
*/
@property (nonatomic, assign) UICollectionViewScrollDirection scrollDirection;
/**
輪播樣式 默認是 WSLRollViewScrollStylePage 分頁
*/
@property (nonatomic, assign) WSLRollViewScrollStyle scrollStyle;
/**
漸進輪播速率 單位是Point/s,以坐標系單位為准 默認60/s 如果為0 表示禁止計時器
*/
@property (nonatomic, assign) CGFloat speed;
/**
分頁輪播間隔時長 單位是s 默認3s 如果為0 表示禁止計時器
*/
@property (nonatomic, assign) CGFloat interval;
/**
item的間隔 默認值0
*/
@property (nonatomic, assign) CGFloat spaceOfItem;
/**
內邊距 上 左 下 右 默認值UIEdgeInsetsMake(0, 0, 0, 0)
*/
@property (nonatomic, assign) UIEdgeInsets padding;
/** delegate*/
@property (nonatomic, weak) id<WSLRollViewDelegate> delegate;
/**
初始化方法 direction 滾動方向
*/
- (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;
/**
刷新數據源
*/
- (void)reloadData;
/**
暫停自動輪播
*/
- (void)pause;
/**
繼續自動輪播
*/
- (void)play;
/**
釋放計時器 必須執行,防止內存暴漲
*/
- (void)close;
@end
三、項目結構
以上就是我實現這個效果的過程;如果小伙伴們有其他的實現方法,歡迎再此留言交流😊😊😀😀🤗🤗
iOS 封裝跑馬燈和輪播效果
注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權