当前位置:首页 > 芯闻号 > 充电吧
[导读]图片加载使用 SDWebImage 第三方库。 WTCycleRollView.h #import @interface WTCycleRollView : UIView @property

图片加载使用 SDWebImage 第三方库。


WTCycleRollView.h

#import 

@interface WTCycleRollView : UIView

@property (nonatomic, assign) NSTimeInterval rollTimeInterval;

/**
 返回 WTCycleRollView 对象
 @param frame 位置尺寸
 @return WTCycleRollView 对象
 */
+ (instancetype)cycleRollViewWithFrame:(CGRect)frame;

/**
 设置图片源、是否自动滚动、点击图片的回调
 @param imgUrls 图片源
 @param autoCycleRoll 是否自动滚动
 @param clickImgBlock 点击图片的回调
 */
- (void)setImgUrls:(NSArray *)imgUrls autoCycleRoll:(BOOL)autoCycleRoll clickImgBlock:(void(^)(NSInteger selectedIndex))clickImgBlock;

/** 暂停自动滚动 */
- (void)pauseCycleRoll;
/** 开始自动滚动【在暂停的状态下】 */
- (void)startCycleRoll;

@end

WTCycleRollView.m

#import "WTCycleRollView.h"
#import "UIImageView+WebCache.h"

typedef void(^ClickImgBlock) (NSInteger);

@interface WTCycleRollView () 

@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIPageControl *pageControl;

@property (nonatomic, strong) UIImageView *leftImgView;
@property (nonatomic, strong) UIImageView *middleImgView;
@property (nonatomic, strong) UIImageView *rightImgView;
/** 图片源 */
@property (nonatomic, strong) NSArray *imgUrls;
/** 当前显示的图片的 Index */
@property (nonatomic, assign) NSInteger showIndex;
/** 点击图片的回调 Block */
@property (nonatomic, strong) ClickImgBlock clickImgBlock;
/** 自动滚动的计时器 */
@property (nonatomic, strong) NSTimer *cycleRollTimer;
/** 是否手动滑动 */
@property (nonatomic, assign) BOOL manual;

@end

@implementation WTCycleRollView
/** 默认循环滚动的时间间隔(s) */
static NSTimeInterval const DefaultRollTimeInterval = 4;

#pragma mark - 懒加载
- (UIImageView *)leftImgView {
    if (!_leftImgView) {
        _leftImgView = [[UIImageView alloc] initWithFrame:self.bounds];
    }
    return _leftImgView;
}

- (UIImageView *)middleImgView {
    if (!_middleImgView) {
        _middleImgView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds), 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
        /** 为中间正在显示的 ImgView 添加点击事件 */
        UITapGestureRecognizer *tapGr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickImgView)];
        [_middleImgView setUserInteractionEnabled:YES];
        [_middleImgView addGestureRecognizer:tapGr];
    }
    return _middleImgView;
}

- (UIImageView *)rightImgView {
    if (!_rightImgView) {
        _rightImgView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) * 2, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
    }
    return _rightImgView;
}

- (UIScrollView *)scrollView {
    if (!_scrollView) {
        _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
        _scrollView.delegate = self;
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.pagingEnabled = YES;
    }
    return _scrollView;
}

- (UIPageControl *)pageControl {
    if (!_pageControl) {
        _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.bounds) - 20, CGRectGetWidth(self.bounds), 20)];
        _pageControl.layer.shadowOpacity = 0.3;
        _pageControl.layer.shadowOffset = CGSizeMake(0, 0);
    }
    return _pageControl;
}

#pragma mark - 初始化
- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self addSubview:self.scrollView];
        [_scrollView addSubview:self.leftImgView];
        [_scrollView addSubview:self.middleImgView];
        [_scrollView addSubview:self.rightImgView];
        [self addSubview:self.pageControl];
    }
    return self;
}

#pragma mark - 类方法 返回 WTCycleRollView
+ (instancetype)cycleRollViewWithFrame:(CGRect)frame {
    return [[self alloc] initWithFrame:frame];
}

#pragma mark - 设置图片显示,自动滚动
- (void)setImgUrls:(NSArray *)imgUrls autoCycleRoll:(BOOL)autoCycleRoll clickImgBlock:(void (^)(NSInteger))clickImgBlock {
    _clickImgBlock = clickImgBlock;
    _imgUrls = imgUrls;
    _pageControl.numberOfPages = [imgUrls count];
    _pageControl.currentPage = 0;
    if ([_imgUrls count] > 1) {
        [_leftImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls lastObject]]];
        [_middleImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls firstObject]]];
        [_rightImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls objectAtIndex:1]]];
        _scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds) * 3, 0);
        [_scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.bounds), 0)];
        if (autoCycleRoll) {
            [self stopTimer];
            _cycleRollTimer = [NSTimer scheduledTimerWithTimeInterval:DefaultRollTimeInterval target:self selector:@selector(cycleRoll) userInfo:nil repeats:YES];
        } else {
            [self stopTimer];
        }
    } else {
        _scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds), 0);
        [_leftImgView removeFromSuperview];
        [_rightImgView removeFromSuperview];
        if ([imgUrls count]) {
            [_middleImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls firstObject]]];
            _middleImgView.frame = self.bounds;
        }
    }
}

#pragma mark - 自动滚动的事件
- (void)cycleRoll {
    // 当手动滚动的时候,跳过此次循环
    if (_manual) {
        _manual = NO;
    } else {
        [_scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.bounds) * 2, 0) animated:YES];
    }
}

- (void)clickImgView {
    !_clickImgBlock ? : _clickImgBlock(_showIndex);
}

#pragma mark - UIScrollView Delegate
/** ScrollView 滑动减速停止回调【这里根据 ScrollView 的偏移量来判断是向左滑还是向右滑】 */
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    if ([_imgUrls count]) {
        CGFloat offsetX = scrollView.contentOffset.x;
        if (offsetX <= 0) {
            // 向右滑,即将显示上一张图片(若当前显示的是第一张,则上一张为最后一张)
            self.showIndex = (_showIndex + [_imgUrls count] - 1) % [_imgUrls count];
        } else if (offsetX >= CGRectGetWidth(self.bounds) * 2) {
            // 向右滑,即将显示下一张图片(若当前显示的是最后一张,则下一张为第一张)
            self.showIndex = (_showIndex + 1) % [_imgUrls count];
        }
    }
}
/** 自动滑动【即代码设置的滚动(setContentOffset:animated:)】,不会直接调用上述方法(滑动减速停止回调),但会调用此方法,在此方法再调用上述方法便可 */
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    [self scrollViewDidEndDecelerating:_scrollView];
}
/** 手动滑动手指触摸屏幕的回调,暂停计时器 */
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    [self pauseCycleRoll];
}
/** 手动滑动手指离开屏幕的回调,开启计时器 */
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    _manual = YES;  // 这里开启计时器会立即调用循环滚动的方法,用户体验不好,所以设置此参数,让其跳过这次循环滚动事件
    [self startCycleRoll];
}
/** 根据 ScrollView 偏移量设置 PageControl 的当前页 */
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if ([_imgUrls count]) {
        CGFloat offsetX = scrollView.contentOffset.x;
        if (offsetX <= CGRectGetWidth(self.bounds) * 0.5) {
            _pageControl.currentPage = (_showIndex + [_imgUrls count] - 1) % [_imgUrls count];
        } else if (offsetX >= CGRectGetWidth(self.bounds) * 1.5) {
            _pageControl.currentPage = (_showIndex + 1) % [_imgUrls count];
        } else {
            _pageControl.currentPage = _showIndex;
        }
    }
}

#pragma mark - 设置当前显示的图片
- (void)setShowIndex:(NSInteger)showIndex {
    _showIndex = showIndex;
    // 不管向左滑还是向右滑,这里立即将将要显示的图片展示在中间的 ImgView 上,然后马上将 ScrollView 偏移量设置到显示中间的 ImgView
    // 由于代码执行及屏幕显示渲染非常快,肉眼几乎看不出,所以这样就达到了效果
    [_leftImgView sd_setImageWithURL:[NSURL URLWithString:_imgUrls[(_showIndex + [_imgUrls count] - 1) % [_imgUrls count]]]];
    [_middleImgView sd_setImageWithURL:[NSURL URLWithString:_imgUrls[showIndex]]];
    [_rightImgView sd_setImageWithURL:[NSURL URLWithString:_imgUrls[(showIndex + 1) % [_imgUrls count]]]];
    // 切记,这里设置 ScrollView 偏移量不能用动画
    [_scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.bounds), 0)];
}
#pragma mark - 自动滚动时,计时器的暂停与启动
/** 暂停计时器 */
- (void)pauseCycleRoll {
    if (_cycleRollTimer) {
        [_cycleRollTimer setFireDate:[NSDate distantFuture]];
    }
}
/** 启动定时器【在计时器暂停状态下】 */
- (void)startCycleRoll {
    if (_cycleRollTimer) {
        [_cycleRollTimer setFireDate:[NSDate distantPast]];
    }
}

#pragma mark - 停止计时器,并释放
- (void)stopTimer {
    if (_cycleRollTimer) {
        [_cycleRollTimer invalidate];
        _cycleRollTimer = nil;
    }
}
#pragma mark - WTCycleRollView 释放的时候 停止计时器,并释放,否则会造成内存泄漏
- (void)dealloc {
    [self stopTimer];
}

@end


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭