iOS旅途

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个
很简单,欢迎评论回答交流哦 *_< 。

上一篇 下一篇

猜你喜欢

热点阅读