iOS无限循环滚动控件(Objective-C版)

前言


循环滚动是在目前我们开发中经常碰到的需求,而且网上有很多实现方式,但总是不能满足开发需要,闲来无事自己写了一个控件(GitHub下载),主要能实现以下功能:

1.循环滚动(水平/垂直方向)开启或关闭
2.自动滚动开启或关闭
3.自定义自动滚动时间间隔
4.用户自定义任何布局
5.用户自定义任何数据模型
6.自定义PgaeControl
7.自定义PgaeControl的指示器背景图
8.自定义PgaeControl的指示器间距
9.自定义PgaeControl的水平/垂直方向展示
10.自定义PgaeControl在控件中的位置
(1)水平方向的PgaeControl可以在上左、上中、上有、下左、下中和下右6个位置展示
(2)垂直方向的PgaeControl可以在左上、左中、左下、右上、右中和右下6个位置展示
更多功能等待你的发现……

代码说明


项目核心类有3个,分别是 LBCycleScrollViewLBPageControlUICollectionViewCell+LBCycleScrollView

LBCycleScrollView

LBCycleScrollView 类中实现循环滚动是的 UICollectionView。要点如下:
1.利用 UICollectionViewCell 的复用原理,当数据源的个数 >=3 的时候,UICollectionViewCell 只创建3个即可。
2.循环滚动的实现是将 UICollectionViewcell 个数加倍,即 2 x 数据源的个数。
3.使用 UIScrollViewsetContentOffset:animated: 函数将控件滚动到争取的位置。
4.使用 NSTimer 实现自动滚动。

self.totalItemsCount = self.itemArray.count <= 1 ? self.itemArray.count : 2 * self.itemArray.count;
[self.collectionView reloadData];

if (self.totalItemsCount > 1) {
    // scroll to the middle of the view
    if (self.scrollDirection == LBCycleScrollViewScrollDirectionHorizontal) {
        [self.collectionView setContentOffset:CGPointMake(self.totalItemsCount / 2 * self.collectionView.frame.size.width, 0.f) animated:NO];
    } else {
        [self.collectionView setContentOffset:CGPointMake(0.f, self.totalItemsCount / 2 * self.collectionView.frame.size.height) animated:NO];
    }
    self.pageControl.currentPage = self.currentIndex % self.itemArray.count;
    [self startCycleScrollTimer];
}

属性解释:

// 自定义page control
@property (nonatomic, strong) LBPageControl *pageControl;
// 数据源
@property (nonatomic, strong) NSArray *itemArray;
// 将要注册给UICollectionView的UICollectionViewCell类
@property (nonatomic, strong) Class cellCls;
// 自动滚动的时间间隔,默认是5秒
@property (nonatomic) CGFloat scrollTimeInterval;
// page control 距离左或右边距的距离,默认是10.f
@property (nonatomic) CGFloat pageControlLeftOrRightMargin;
// page control 距离上或下边距的距离,默认是10.f
@property (nonatomic) CGFloat pageControlTopOrBottomMargin;
// page control 位置,默认是下方的左边
@property (nonatomic) LBCycleScrollViewPageControlAlignment pageControlAlignment;
// 滚动方向,默认是水平滚动
@property (nonatomic) LBCycleScrollViewScrollDirection scrollDirection;
// 循环滚动,默认开启
@property (nonatomic, getter=isCycleScrollEnabled) BOOL cycleScrollEnabled;
// 定时滚动,默认开启
@property (nonatomic, getter=isTimingScrollEnabled) BOOL timingScrollingEnabled;

方法解释:

// 实例化能无限滚动的对象,cls是注册给UICollectionView的类
+ (LBCycleScrollView *)cycleScrollViewWithFrame:(CGRect)frame cellClass:(Class)cls;
// 实例化不能无限滚动的对象,cls是注册给UICollectionView的类
+ (LBCycleScrollView *)nonCycleScrollViewWithFrame:(CGRect)frame cellClass:(Class)cls;

// 设置完数据源后重新加载
- (void)reloadData;

LBPageControl

LBPageControl 是在系统 UIPageControl 的基础上重写的类,多出的属性有:

// 正常状态的 page indicator 背景图
@property (nullable, nonatomic, strong) UIImage *pageIndicatorImage;
// 选中状态的 page indicator 背景图
@property (nullable, nonatomic, strong) UIImage *currentPageIndicatorImage;
// page control 的显示方向,默认是水平方向
@property (nonatomic) LBPageControlDirection pageControlDirection;
// page indicator 的间距
@property (nonatomic) CGFloat pageIndicatorSpacing;

UICollectionViewCell+LBCycleScrollView

UICollectionViewCell+LBCycleScrollView 显而易见是UICollectionViewCell 的一个分类,主要是添加了名为 cellItem 的属性和 assignmentValueToView 的函数。
1.cellItemcell 要显示的数据。
2.assignmentValueToView 函数是将数据添加到 cell 的各个 view 上。

简单示例


1.定义数据模型。

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface ExampleModel : NSObject

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *string;

@end
#import "ExampleModel.h"

@implementation ExampleModel

@end

2.定义 cell 类,导入 UICollectionViewCell+LBCycleScrollView

#import UICollectionViewCell+LBCycleScrollView.h
 
 @interface ExampleCell : UICollectionViewCell
 
 @property (nonatomic, strong) UILabel *titleLabel;
 
 @end

3.导入 cellItem 的数据模型类。 cell 类中自定义布局并赋值。

#import "ExampleCell.h"
#import "ExampleModel.h"

@interface ExampleCell ()

@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UILabel *label;

@end

@implementation ExampleCell

- (instancetype)initWithFrame:(CGRect)frame {
    
    if (self == [super initWithFrame:frame]) {
        self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
        [self.contentView addSubview:self.imageView];
        
        CGFloat labelX = 10.f;
        CGFloat labelH = 30.f;
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(labelX, frame.size.height - labelH, frame.size.width - labelX * 2, labelH)];
        self.label.textColor = [UIColor whiteColor];
        [self.contentView addSubview:self.label];
    }
    return self;
}

- (void)assignmentValueToView {
    
    if ([self.cellItem isKindOfClass:[ExampleModel class]]) {
        ExampleModel *model = (ExampleModel *)self.cellItem;
        self.imageView.image = model.image;
        self.label.text = model.string;
    }
}

4.ViewController 中使用 LBCycleScrollView 提供的类方法创建对象,(LBPageControl 对象选择性创建),赋值并加载显示。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    LBPageControl *control = [[LBPageControl alloc] init];
    control.pageIndicatorImage = [UIImage imageNamed:@"control1"];
    control.currentPageIndicatorImage = [UIImage imageNamed:@"control2"];
    
    LBCycleScrollView *scrollView = [LBCycleScrollView cycleScrollViewWithFrame:CGRectMake(0.f, 0.f, self.view.frame.size.width, 200.f) cellClass:[ExampleCell class]];
    scrollView.delegate = self;
    scrollView.pageControl = control;
    scrollView.pageControlAlignment = LBCycleScrollViewPageControlAlignmentRight | LBCycleScrollViewPageControlAlignmentBottom;
    [self.view addSubview:scrollView];
    
    ExampleModel *model1 = [ExampleModel new];
    model1.image = [UIImage imageNamed:@"img1"];
    model1.string = @"Bei Jing";
    
    ExampleModel *model2 = [ExampleModel new];
    model2.image = [UIImage imageNamed:@"img2"];
    model2.string = @"Hong Kong";
    
    ExampleModel *model3 = [ExampleModel new];
    model3.image = [UIImage imageNamed:@"img3"];
    model3.string = @"New York";
    
    ExampleModel *model4 = [ExampleModel new];
    model4.image = [UIImage imageNamed:@"img4"];
    model4.string = @"Paris";
    
    scrollView.itemArray = @[model1, model2, model3, model4];
    [scrollView reloadData];
}

效果

LBCycleScrollView
LBCycleScrollView

使用方式


CocoaPods

1.在 Podfile 中添加 pod 'LBCycleScrollView'。
2.执行 pod install 或 pod update。

手动添加

1.下载 LBCycleScrollView 文件夹内的所有内容。
2.将 LBCycleScrollView 内的源文件添加(拖放)到你的工程

完善LBCycleScrollView


欢迎加入QQ群 541648808 讨论 LBCycleScrollView,交流问题、提出问题和解决问题。

如有错误,请指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容