iOS自定义控件之滑动横幅

这里介绍的滑动横幅,即我们常说的Banner,也以广告插播、步骤引导、图文专题等形式存在于各种项目实战中,开发中也会经常碰到这种类型的控件,而苹果自带控件没有,为此有个可重用的类,通过实例化就能直接拿来用的,不需反复编写代码去实现对于程序员来说实在很有必要。本文的GYCBanner类就是为此需求而存在的干货,UIScrollView结合UIPageControl就可实现,只需向GYCBanner对象添加你想要展示出来的页面(包括文字、图片、控件等),GYCBanner按创建顺序生成相应页面,支持手指滑动、点击滑动以及自动播放模式。

----------------------------------------------------------------------------------我是分割线------------------------------------------------------------------------------

完成效果图


----------------------------------------------------------------------------------华丽分割线------------------------------------------------------------------------------

1. 创建GYCBanner类

  • 打开Xcode,新建一个类,命名为GYCBanner,父类为UIView,使用ARC
  • 打开GYCBanner.h文件,编写代码如下:
#import <UIKit/UIKit.h>

@interface GYCBanner : UIView

/**
 *  添加页面
 *
 *  @param view 视图
 */
- (void)addPageWithView:(UIView *)view;

/**
 *  启动自动向左播放模式
 *
 *  @param gap 时间间隔
 */
- (void)runAutomaticDisplayModeTowardsLeft:(NSTimeInterval)gap;

/**
 *  启动自动向右播放模式
 *
 *  @param gap 时间间隔
 */
- (void)runAutomaticDisplayModeTowardsRight:(NSTimeInterval)gap;

/**
 *  取消自动播放
 */
- (void)cancelAutomaticDisplayMode;

@end

  • 添加以下代码至GYCBanner.m文件中顶部
@interface GYCBanner () <UIScrollViewDelegate> {
    UIScrollView *slideView;
    UIPageControl *pageControl;
    BOOL isControlled;
    NSTimer *displayTimer;
}

@end

这里声明了4个变量,从上往下分别代表滑动视图、页面控制器、当前页面滑动是否由页面控制器发出指令(避免手指滑动与使用页面控制器滑动产生冲突)、当前展示页面的停留时间,接下来就开始对类GYCBanner的基本功能进行实现。

2. 开始实现

  • 预先设置好滑动视图和页面控制器,方法如下:
- (void)setupDefaultSlide {
    if (nil == slideView) {
        slideView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    }
    
    //根据slideView里子视图的个数和显示区长宽确定其背后内容的长宽
    slideView.contentSize = CGSizeMake(self.frame.size.width*slideView.subviews.count, slideView.frame.size.height);
    slideView.delegate = self;
    //设置slideView一次滚动一页
    slideView.pagingEnabled = YES;
    slideView.showsHorizontalScrollIndicator = NO;
    slideView.showsVerticalScrollIndicator = NO;
    
    if (![slideView isDescendantOfView:self]) {
        [self addSubview:slideView];
    }
}

- (void)setupDefaultPageControl {
    if (nil == pageControl) {
        pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.frame.size.height-37, self.frame.size.width, 37)];
    }
    
    pageControl.numberOfPages = slideView.subviews.count;
    pageControl.currentPage = 0;
    //使用pageControl滑动会调用changedToSlideBanner方法
    [pageControl addTarget:self action:@selector(changedToSlideBanner) forControlEvents:UIControlEventValueChanged];
    
    if (![pageControl isDescendantOfView:self]) {
        [self addSubview:pageControl];
    }
}

然后添加如下方法:
- (void)changedToSlideBanner {
    isControlled = YES;
    int page = pageControl.currentPage;
    
    CGRect frame = slideView.frame;
    frame.origin.x = frame.size.width * page;
    [slideView scrollRectToVisible:frame animated:YES];
}

  • 实现GYCBanner页面的添加方法:
- (void)addPageWithView:(UIView *)view {
    if (view != nil) {
        [slideView addSubview:view];
        
        [self setupDefaultSlide];
        [self setupDefaultPageControl];
    }
}

  • 实现滑动视图的委托:
#pragma mark - scroll view delegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat pageWidth = scrollView.frame.size.width;
    //得到当前滚动到的页数,第一页值为0
    int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    if (!isControlled) {
        pageControl.currentPage = page;
    }
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    isControlled = NO;
}

  • 添加自动播放,循环展示页面(暂不支持对页面进行循环滚动):
- (void)executeTheLeftSlideWithOnce {
    int page = pageControl.currentPage;
    page++;
    if (page >= slideView.subviews.count) {
        page = 0;
    }
    
    CGRect frame = slideView.frame;
    frame.origin.x = frame.size.width * page;
    [slideView scrollRectToVisible:frame animated:NO];
}

- (void)executeTheRightSlideWithOnce {
    int page = pageControl.currentPage;
    page--;
    if (page < 0) {
        page = slideView.subviews.count - 1;
    }
    
    CGRect frame = slideView.frame;
    frame.origin.x = frame.size.width * page;
    [slideView scrollRectToVisible:frame animated:NO];
}

- (void)runAutomaticDisplayModeTowardsLeft:(NSTimeInterval)gap {
    if (displayTimer.isValid) {
        [displayTimer invalidate];
    }
    displayTimer = [NSTimer scheduledTimerWithTimeInterval:gap target:self selector:@selector(executeTheRightSlideWithOnce) userInfo:nil repeats:YES];
}

- (void)runAutomaticDisplayModeTowardsRight:(NSTimeInterval)gap {
    if (displayTimer.isValid) {
        [displayTimer invalidate];
    }
    displayTimer = [NSTimer scheduledTimerWithTimeInterval:gap target:self selector:@selector(executeTheLeftSlideWithOnce) userInfo:nil repeats:YES];
}

- (void)cancelAutomaticDisplayMode {
    [displayTimer invalidate];
}

前两种方法向左向右是针对滑动视图上一个和下一个页面,紧随其后的两种方法只是起到重复调用上两种方法的作用,但是播放方向左右针对的是用户直观上的左右,与滑动方向恰好相反,所以调用的方法是截然相反的。取消自动播放,仅仅只需要将之前的NSTimer对象displayTime设置为无效即可。
  • 最后就是类的初始化方法:
- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    
    return self;
}

- (void)awakeFromNib {
    [self setup];
}

- (void)setup {
    [self setupDefaultSlide];
    [self setupDefaultPageControl];
}


3. 编译运行

完成以上内容后,我们既可以通过Interface Builder在xib文件完成GYCBanner的最初创建,也可使用代码来创建,值得注意的是实例化后记得使用addPageWithView来添加页面,切记不要用addSubview方法来向GYCBanner对象添加页面!
    //使用xib
    for (int i = 0; i < 5; i++) {
        CGRect frame = self.banner1.frame;
        UIView *page = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width * i, 0, frame.size.width, frame.size.height)];
        page.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:((5-i)*51)/255.0];
        //添加页面
        [self.banner1 addPageWithView:page];
    }
    
    //使用initWithFrame
    GYCBanner *banner2 = [[GYCBanner alloc] initWithFrame:CGRectMake(0, 0, 240, 160)];
    banner2.center = CGPointMake(CGRectGetMidX(self.view.bounds), 360);
    for (int i = 0; i < 3; i++) {
        CGRect frame = banner2.frame;
        UIView *page = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width * i, 0, frame.size.width, frame.size.height)];
        page.backgroundColor = [UIColor darkGrayColor];
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 30)];
        label.center = CGPointMake(CGRectGetMidX(banner2.bounds), CGRectGetMidY(banner2.bounds));
        label.backgroundColor = [UIColor clearColor];
        label.textColor = [UIColor whiteColor];
        label.textAlignment = NSTextAlignmentCenter;
        label.text = [NSString stringWithFormat:@"%d", i+1];
        [page addSubview:label];
        //添加页面
        [banner2 addPageWithView:page];
    }
    [self.view addSubview:banner2];

----------------------------------------------------------------------------------我想说的是------------------------------------------------------------------------------
读者可以在学习消化完后,对本部分的内容进行一些扩展,比如添加纵向的滑动、更多公开的接口、滚动动画等等......

源码下载地址: https://github.com/ganyuchuan/GYCBox,详见GYCBanner。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值