当前位置:首页 > 芯闻号 > 充电吧
[导读]图片加载使用 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


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

2024年第十七届国际太阳能光伏与智慧能源(上海)大会暨展览会(SNEC 2024)首日,一个由全球最大光伏电站开发商阳光新能源发布的新品——iHomePow阳光家庭能源破圈了。

关键字: AI 智能家居

2024年6月11日,2024第十二届阿拉丁论坛「AI+智能健康照明创新大会」在广州光亚展A展区6.1馆盛大举办现场拉开帷幕。智谋纪创始人&CEO朱东亮先生受邀出席论坛,带来题为《AI+ Multi LED,打开人类健康...

关键字: AI LED

南京2024年6月17日 /美通社/ -- 当智能遇见制造,当创新冲破边界…6月14日,一场颠覆想象的行业沙龙在南京举行。这不仅是一次汇聚前沿洞见与科技的智变之旅,还掀起了一场关于汽车零部件制造业智能化升级的深度对话与思...

关键字: 汽车零部件 智能工厂 智能化 智能制造

深圳2024年6月17日 /美通社/ -- 全球工业物联网领导厂商研华公司 (TWSE:2395)与全球PCB领导厂商臻鼎科技集团(TWSE:4958)在深圳鹏鼎时代大厦签署战略合作协议,双方将建立全面战略性合作伙伴关系...

关键字: PCB AI SE 能源管理

构建智能分析解决方案ChatBI 加速旅游行业数智化升级 北京2024年6月17日 /美通社/ -- 亚马逊云科技宣布,全球领先的旅游产品网络营销系统设计及分销技术服务公司德比软件(上海)有限公司(以下简称"德比软件"...

关键字: 亚马逊 软件 AI技术 生成式AI

电池卓越制造平台 (Battery MXP)有望降低电池制造成本,缩短生产启动周期,并在启动阶段[1]减少60%的材料浪费 美国得克萨斯州休斯敦2024年6月17日 /美通社/ -- 霍尼韦尔(纳斯达克代码:HON)近...

关键字: 模电 电池 霍尼韦尔 自动化软件

深圳2024年6月17日 /美通社/ -- 日前,科学碳目标倡议组织(Science Based Targets initiative,SBTi)宣布成立审定委员会(Vali...

关键字: TI 可持续发展 SCIENCE TARGET

英格兰牛津2024年6月17日 /美通社/ -- 总部位于牛津的分析公司Equine Match Ltd.正式发布其突破性的云端软件平台,将先进的机器学习和人工智能应用于价值数千亿美元的全球纯种马行业。 Equine...

关键字: MATCH UI 人工智能 数据驱动

研究表明,由于云计算和AI的需求激增,马来西亚数据中心行业快速发展,未来将成为东南亚地区以及亚洲的数据中心强国。

关键字: 亚洲数据中心 马来西亚 AI算力

2024年6月9日,第29届广州国际照明展览会(GILE)在广州中国进出口商品交易会展馆盛大开幕。AI照明领域的引领者品牌——智谋纪AI照明,携核心前沿技术“场景识别子系统(AIscene)”再度亮相智能馆9.2馆B26...

关键字: AI 智能家居
关闭
关闭