iOS动态轮播滚动的实现
2018-08-08 本文已影响53人
朝阳小麦
适用人群:iOS开发人员。
本文内容:实现消息的竖直方向循环轮播。读者也可以做相关改动,实现常用的图片左右轮播。
备注:
UIScrollView中总共只有三个子view,不管要添加多少数据,都只有三个子view,显示和滚动通过更新数据实现。
比如说,每次都显示第二个view,动态滚动到第三个view后,通过代码实现把当前显示数据更新为第二个view,用户是看不到该操作的。
目前没有时间,先把代码和使用方式粘贴出来,以后再整理吧。
1.都封装在一个自定义View里。VerticalCycleScrollView视图。
VerticalCycleScrollView.h代码如下:
#import <UIKit/UIKit.h>
@interface VerticalCycleScrollView : UIView
@property (nonatomic , strong) UIScrollView *verticalScrollView;
/**
* 初始化
*
* @param frame frame
* @param animationDuration 自动滚动的间隔时长。如果<=0,不自动滚动。
*
* @return instance
*/
- (id)initWithFrame:(CGRect)frame animationDuration:(NSTimeInterval)animationDuration;
/**
数据源:获取总的page个数
**/
@property (nonatomic , copy) NSInteger (^totalPagesCount)(void);
/**
数据源:获取第pageIndex个位置的contentView
**/
@property (nonatomic , copy) NSString *(^fetchContentTextAtIndex)(NSInteger pageIndex);
/**
当点击的时候,执行的block
**/
@property (nonatomic , copy) void (^TapActionBlock)(NSInteger pageIndex);
@end
2.VerticalCycleScrollView.m代码如下:
#import "VerticalCycleScrollView.h"
#import "NSTimer+Addition.h"
@interface VerticalCycleScrollView () <UIScrollViewDelegate>
@property (nonatomic , assign) NSInteger currentPageIndex;
@property (nonatomic , assign) NSInteger totalPageCount;
@property (nonatomic , strong) NSMutableArray *contentTexts;
@property (nonatomic , strong) NSTimer *animationTimer;
@property (nonatomic , assign) NSTimeInterval animationDuration;
@end
@implementation VerticalCycleScrollView
- (void)setTotalPagesCount:(NSInteger (^)(void))totalPagesCount {
_totalPageCount = totalPagesCount();
if (_totalPageCount > 0) {
[self configContentViews];
[self.animationTimer resumeTimerAfterTimeInterval:self.animationDuration];
}
}
- (id)initWithFrame:(CGRect)frame animationDuration:(NSTimeInterval)animationDuration {
self = [self initWithFrame:frame];
if (animationDuration > 0.0) {
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:(self.animationDuration = animationDuration)
target:self
selector:@selector(animationTimerDidFired:)
userInfo:nil
repeats:YES];
[self.animationTimer pauseTimer];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.autoresizesSubviews = YES;
self.verticalScrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
self.verticalScrollView.scrollEnabled = NO;
self.verticalScrollView.autoresizingMask = 0xFF;
self.verticalScrollView.contentMode = UIViewContentModeCenter;
self.verticalScrollView.contentSize = CGSizeMake( CGRectGetWidth(self.verticalScrollView.frame), CGRectGetHeight(self.verticalScrollView.frame)*3);
self.verticalScrollView.delegate = self;
self.verticalScrollView.contentOffset = CGPointMake(0,CGRectGetWidth(self.verticalScrollView.frame));
self.verticalScrollView.pagingEnabled = YES;
[self addSubview:self.verticalScrollView];
self.currentPageIndex = 0;
}
return self;
}
#pragma mark -
#pragma mark - 私有函数
- (void)configContentViews {
[self.verticalScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self setScrollViewContentDataSource];
NSInteger counter = 0;
for (NSString *text in self.contentTexts) {
UILabel *contentLabel = [[UILabel alloc] init];
contentLabel.frame = self.verticalScrollView.frame;
contentLabel.font = [UIFont contentFont];
contentLabel.textColor = [UIColor contentColor];
contentLabel.text = text;
contentLabel.userInteractionEnabled = YES;
CGRect rightRect = contentLabel.frame;
rightRect.origin = CGPointMake(0, CGRectGetHeight(self.verticalScrollView.frame) * (counter ++));
contentLabel.frame = rightRect;
[self.verticalScrollView addSubview:contentLabel];
}
[self.verticalScrollView setContentOffset:CGPointMake(0, self.verticalScrollView.frame.size.height)];
}
/**
* 设置scrollView的content数据源,即contentViews
*/
- (void)setScrollViewContentDataSource {
NSInteger previousPageIndex = [self getValidNextPageIndexWithPageIndex:self.currentPageIndex - 1];
NSInteger rearPageIndex = [self getValidNextPageIndexWithPageIndex:self.currentPageIndex + 1];
if (self.contentTexts == nil) {
self.contentTexts = [@[] mutableCopy];
}
[self.contentTexts removeAllObjects];
if (self.fetchContentTextAtIndex) {
[self.contentTexts addObject:self.fetchContentTextAtIndex(previousPageIndex)];
[self.contentTexts addObject:self.fetchContentTextAtIndex(_currentPageIndex)];
[self.contentTexts addObject:self.fetchContentTextAtIndex(rearPageIndex)];
}
}
- (NSInteger)getValidNextPageIndexWithPageIndex:(NSInteger)currentPageIndex; {
if(currentPageIndex == -1) {
return self.totalPageCount - 1;
} else if (currentPageIndex == self.totalPageCount) {
return 0;
} else {
return currentPageIndex;
}
}
#pragma mark -
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self.animationTimer pauseTimer];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
[self.animationTimer resumeTimerAfterTimeInterval:self.animationDuration];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
int contentOffsetX = scrollView.contentOffset.y;
if(contentOffsetX >= (2 * CGRectGetHeight(scrollView.frame))) {
self.currentPageIndex = [self getValidNextPageIndexWithPageIndex:self.currentPageIndex + 1];
[self configContentViews];
}
if(contentOffsetX <= 0) {
self.currentPageIndex = [self getValidNextPageIndexWithPageIndex:self.currentPageIndex - 1];
[self configContentViews];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[scrollView setContentOffset:CGPointMake(CGRectGetWidth(scrollView.frame), 0) animated:YES];
}
#pragma mark -
#pragma mark - 响应事件
- (void)animationTimerDidFired:(NSTimer *)timer {
CGPoint newOffset = CGPointMake(0,self.verticalScrollView.contentOffset.y + CGRectGetHeight(self.verticalScrollView.frame));
[self.verticalScrollView setContentOffset:newOffset animated:YES];
}
- (void)contentViewTapAction:(UITapGestureRecognizer *)tap {
if (self.TapActionBlock) {
self.TapActionBlock(self.currentPageIndex);
}
}
3.代码中定时器部分引用了一个类别:"NSTimer+Addition.h"。关于定时器,读者可以采用其他写法替换。这里把这个类别代码粘贴出来。
NSTimer+Addition.h代码如下:
#import <Foundation/Foundation.h>
@interface NSTimer (Addition)
- (void)pauseTimer;
- (void)resumeTimer;
- (void)resumeTimerAfterTimeInterval:(NSTimeInterval)interval;
@end
4.NSTimer+Addition.m代码如下:
#import "NSTimer+Addition.h"
@implementation NSTimer (Addition)
- (void)pauseTimer {
if (![self isValid]) {
return ;
}
[self setFireDate:[NSDate distantFuture]];
}
- (void)resumeTimer {
if (![self isValid]) {
return ;
}
[self setFireDate:[NSDate date]];
}
- (void)resumeTimerAfterTimeInterval:(NSTimeInterval)interval {
if (![self isValid]) {
return ;
}
[self setFireDate:[NSDate dateWithTimeIntervalSinceNow:interval]];
}
@end
5.完成。
如何使用呢?举例如下:
NSString *strings = @[@"1lalala", @"2lalala", @"3lalala", @"4lalala"];
CGRect rect = CGRectMake(100, 100, 250, 50);
VerticalCycleScrollView *scrollView = [[VerticalCycleScrollView alloc] initWithFrame:rect animationDuration:4.0];
[self.view addSubview:scrollView];
scrollView.fetchContentTextAtIndex = ^NSString *(NSInteger pageIndex) {
return strings[pageIndex];
};
scrollView.totalPagesCount = ^NSInteger(void) {
return strings.count;
};
[scrollView addTapActionWithBlock:^(UIGestureRecognizer *gestureRecoginzer) {
//点击事件执行代码
}];
6.娱乐部分。
这里给大家提个问题,可以随手答一答,是个很容易被忽视的,一不小心就会造成bug。
问题:同一个view,被父view执行了addSubview三次,那这个父view有几个子view?
A:1个
B:3个
C:n个
很简单,欢迎评论回答交流哦 *_< 。