前言
早在半年之前,做了一个O2O类型的iOS应用,当时我负责做一个走马灯的效果。需求是在首页添加一个广告位,有图片的轮播,并且还要配上标题文字,而且还有支持点击跳转到详情界面。很多app都有这种效果,其实走马灯效果这个称号是html开发中的叫法,对于iOS开发中的这种效果暂且还没有一个官方的称号,暂且在iOS中称这种效果为广播轮播吧,因为我觉得这个比较形象也通俗易懂,你要是说走马灯效果,估计很多iOS开发的工程师还不懂你的意思。
其实,一开始的时候并不怎么顺利,可能是半年之前水平有限吧,首先遇到的问题就是图片不能循环滑动,后来用了一个小小的算法,实现了能循环滑动。经过测试发现,如果网络比较慢,广告位会显示空白,后面就给图片加了一张默认图片,也就是占位图像。但是还是不完美,网络图片缓存到了本地,但是不会刷新,于是就加个来通知,当网络图片已经缓存到本地了,就通知广告位刷新,把占位图像换成网络图片,这是半年之前的解决办法。在这次的项目中,我又负责这个功能,其实有个已经很成熟的图片缓存框架了,就是SDWebImage,基本每个项目中都会用到,所以我这次做这个广告轮播的效果,就引入了这个类中的缓存图片的方法,一句代码就解决了。
基本的需求点:
1. 支持循环滚动;
2. 支持加定时器,自动滚动;
3. 支持自定义是否要显示标题;
4. 支持自定义pageControl的位置(左、中、右三种方式);
5. 支持自定义标题的位置(左、中、右三种方式);
6. 支付广告轮播图片的点击,可以点击跳转到你所指定的界面;
7.只有一张图片时,自动隐藏pageControl;
一、头文件中的声明
//
// YCAdView.h
// TestAdView
//
// Created by 袁灿 on 15/9/14.
// Copyright (c) 2015年 yuancan. All rights reserved.
//
#import <UIKit/UIKit.h>
//标题文字显示的方式
typedef NS_ENUM(NSInteger, AdViewTitleShowStyle)
{
AdViewTitleShowStyleNone,
AdViewTitleShowStyleLeft,
AdViewTitleShowStyleCenter,
AdViewTitleShowStyleRight,
};
//pageControl显示方式
typedef NS_ENUM(NSInteger, UIPageControlShowStyle)
{
UIPageControlShowStyleNone,
UIPageControlShowStyleLeft,
UIPageControlShowStyleCenter,
UIPageControlShowStyleRight,
};
@interface YCAdView : UIView <UIScrollViewDelegate>
@property (strong, nonatomic) UIScrollView *scrollView;
//点击图片的回调方法
@property (strong, nonatomic) void (^clickAdImage)(NSInteger index);
/**
* 自定义广告轮播视图
*
* @param frame 广告轮播视图位置及大小
* @param arrImage 轮播的图片
* @param arrTitle 轮播的标题(如不需要展示标题,传nil)
* @param placeholderImage 无网络图片时的默认图片
*
* @return 广告轮播视图
*/
+ (id)initAdViewWithFrame:(CGRect)frame
images:(NSArray *)arrImage
titles:(NSArray*)arrTitle
placeholderImage:(UIImage *)placeholderImage;
@end
二、m文件中的实现
#define kADView_Width _scrollView.bounds.size.width //广告的宽度
#define kADView_Height _scrollView.bounds.size.height //广告的高度
#define kTime 5.0f //轮播的时间
#import "YCAdView.h"
#import "UIImageView+WebCache.h"
@interface YCAdView ()
@property (retain,nonatomic) UIImageView *leftImageView;
@property (retain,nonatomic) UIImageView *centerImageView;
@property (retain,nonatomic) UIImageView *rightImageView;
@property (retain,nonatomic) UILabel *labTitle;
@property (retain,nonatomic) UIImage *placeHolderImage;
@property (retain,nonatomic) NSTimer *timer;
@property (retain,nonatomic) UIPageControl *pageControl;
@property (nonatomic,assign) NSUInteger centerImageIndex;
@property (nonatomic,assign) NSUInteger leftImageIndex;
@property (nonatomic,assign) NSUInteger rightImageIndex;
@property (nonatomic,assign) NSUInteger currentPage;
@property (nonatomic,strong) NSArray *arrAdTitle;
@property (nonatomic,strong) NSMutableArray *arrImgUrl;
@end
@implementation YCAdView
+ (id)initAdViewWithFrame:(CGRect)frame
images:(NSArray *)arrImage
titles:(NSArray*)arrTitle
placeholderImage:(UIImage *)placeholderImage
{
if (arrImage.count == 0) {
return nil;
}
YCAdView *ycAdview = [[YCAdView alloc] initWithFrame:frame];
[ycAdview setAdViewImage:arrImage];
[ycAdview setAdViewTitle:arrTitle withShowStyle:AdViewTitleShowStyleLeft];
[ycAdview setPageControlShowStyle:UIPageControlShowStyleRight];
ycAdview.placeHolderImage = placeholderImage;
return ycAdview;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_scrollView = [[UIScrollView alloc] initWithFrame:frame];
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
_scrollView.delegate = self;
_scrollView.contentOffset = CGPointMake(kADView_Width, 0);
_scrollView.contentSize = CGSizeMake(kADView_Width*3, kADView_Height);
_scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
_scrollView.pagingEnabled = YES;
_scrollView.bounces = NO;
[self addSubview:_scrollView];
_leftImageView = [[UIImageView alloc] initWithFrame:CGRectMake(kADView_Width*0, 0, kADView_Width, kADView_Height)];
_centerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(kADView_Width*1, 0, kADView_Width, kADView_Height)];
_rightImageView = [[UIImageView alloc] initWithFrame:CGRectMake(kADView_Width*2, 0, kADView_Width, kADView_Height)];
//添加图片点击事件
_centerImageView.userInteractionEnabled = YES;
[_centerImageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAdImage)]];
[_scrollView addSubview:_leftImageView];
[_scrollView addSubview:_centerImageView];
[_scrollView addSubview:_rightImageView];
}
return self;
}
//设置广告轮播的图片
- (void)setAdViewImage:(NSArray *)arrImage
{
_leftImageIndex = arrImage.count - 1;
_centerImageIndex = 0;
_rightImageIndex = 1;
if (arrImage.count == 1) {
_scrollView.scrollEnabled = NO;
_rightImageIndex = 0;
}
_arrImgUrl = [[NSMutableArray alloc] init];
for (int i=0; i<arrImage.count; i++) {
NSString *strImg = [arrImage objectAtIndex:i];
NSURL *urlImg = [NSURL URLWithString:strImg];
[_arrImgUrl addObject:urlImg];
}
[_leftImageView sd_setImageWithURL:_arrImgUrl[_leftImageIndex] placeholderImage:_placeHolderImage];
[_centerImageView sd_setImageWithURL:_arrImgUrl[_centerImageIndex] placeholderImage:_placeHolderImage];
[_rightImageView sd_setImageWithURL:_arrImgUrl[_rightImageIndex] placeholderImage:_placeHolderImage];
//添加定时器
_timer = [NSTimer scheduledTimerWithTimeInterval:kTime target:self selector:@selector(moveAdImage) userInfo:nil repeats:YES];
}
//设置广告轮播的标题
- (void)setAdViewTitle:(NSArray *)arrTitle withShowStyle:(AdViewTitleShowStyle)adViewTitleShowStyle
{
if (arrTitle.count == 0 || adViewTitleShowStyle == AdViewTitleShowStyleNone) {
return;
}
_arrAdTitle = [NSArray arrayWithArray:arrTitle];
//灰色遮罩层
UIView *grayView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_scrollView.frame)-30, kADView_Width, 30)];
grayView.backgroundColor = [UIColor blackColor];
grayView.alpha = 0.3;
[self addSubview:grayView];
_labTitle = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, grayView.frame.size.width-10, 30)];
[grayView addSubview:_labTitle];
_labTitle.textColor = [UIColor whiteColor];
_labTitle.text = arrTitle[_centerImageIndex];
if (adViewTitleShowStyle == AdViewTitleShowStyleLeft) {
_labTitle.textAlignment = NSTextAlignmentLeft;
} else if (adViewTitleShowStyle == AdViewTitleShowStyleCenter) {
_labTitle.textAlignment = NSTextAlignmentCenter;
} else if (adViewTitleShowStyle == AdViewTitleShowStyleRight) {
_labTitle.textAlignment = AdViewTitleShowStyleRight;
}
}
//创建pageControl,设置其样式
- (void)setPageControlShowStyle:(UIPageControlShowStyle)pageControlShowStyle
{
if (pageControlShowStyle == UIPageControlShowStyleNone || _arrImgUrl.count == 1) {
return;
}
_pageControl = [[UIPageControl alloc] init];
_pageControl.currentPage = 0;
_pageControl.numberOfPages = _arrImgUrl.count;
[self addSubview:_pageControl];
if (pageControlShowStyle == UIPageControlShowStyleLeft) {
_pageControl.frame = CGRectMake(0, kADView_Height-30, 20*_pageControl.numberOfPages, 30);
} else if (pageControlShowStyle == UIPageControlShowStyleCenter) {
_pageControl.frame = CGRectMake((kADView_Width-20*_pageControl.numberOfPages)/2, CGRectGetMaxY(_scrollView.frame)-30, 20*_pageControl.numberOfPages, 30);
} else if (pageControlShowStyle == UIPageControlShowStyleRight) {
_pageControl.frame = CGRectMake(kADView_Width-20*_pageControl.numberOfPages, CGRectGetMaxY(_scrollView.frame)-30, 20*_pageControl.numberOfPages, 30);
}
}
//定时器自动滚动视图
- (void)moveAdImage
{
_leftImageIndex = _leftImageIndex + 1;
_centerImageIndex = _centerImageIndex + 1;
_rightImageIndex = _rightImageIndex + 1;
if (_leftImageIndex == _arrImgUrl.count) {
_leftImageIndex = 0;
}
if (_centerImageIndex == _arrImgUrl.count) {
_centerImageIndex = 0;
}
if (_rightImageIndex == _arrImgUrl.count) {
_rightImageIndex = 0;
}
[_leftImageView sd_setImageWithURL:_arrImgUrl[_leftImageIndex] placeholderImage:_placeHolderImage];
[_centerImageView sd_setImageWithURL:_arrImgUrl[_centerImageIndex] placeholderImage:_placeHolderImage];
[_rightImageView sd_setImageWithURL:_arrImgUrl[_rightImageIndex] placeholderImage:_placeHolderImage];
_pageControl.currentPage = _centerImageIndex;
_labTitle.text = _arrAdTitle[_centerImageIndex];
_scrollView.contentOffset = CGPointMake(kADView_Width, 0);
}
//点击广告轮播的图片
- (void)tapAdImage
{
_clickAdImage(_centerImageIndex);
}
#pragma mark - UIScrollView Delegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
if (_scrollView.contentOffset.x == 0) {
_leftImageIndex = _leftImageIndex - 1;
_centerImageIndex = _centerImageIndex - 1;
_rightImageIndex = _rightImageIndex - 1;
if (_leftImageIndex == -1) {
_leftImageIndex = _arrImgUrl.count - 1;
}
if (_centerImageIndex == -1) {
_centerImageIndex = _arrImgUrl.count - 1;
}
if (_rightImageIndex == - 1) {
_rightImageIndex = _arrImgUrl.count - 1;
}
}else if (_scrollView.contentOffset.x == kADView_Width * 2) {
_leftImageIndex = _leftImageIndex + 1;
_centerImageIndex = _centerImageIndex + 1;
_rightImageIndex = _rightImageIndex + 1;
if (_leftImageIndex == _arrImgUrl.count) {
_leftImageIndex = 0;
}
if (_centerImageIndex == _arrImgUrl.count) {
_centerImageIndex = 0;
}
if (_rightImageIndex == _arrImgUrl.count) {
_rightImageIndex = 0;
}
}else {
return;
}
_pageControl.currentPage = _centerImageIndex;
if (_arrAdTitle.count > 0) {
_labTitle.text = _arrAdTitle[_centerImageIndex];
}
[_leftImageView sd_setImageWithURL:_arrImgUrl[_leftImageIndex] placeholderImage:_placeHolderImage];
[_centerImageView sd_setImageWithURL:_arrImgUrl[_centerImageIndex] placeholderImage:_placeHolderImage];
[_rightImageView sd_setImageWithURL:_arrImgUrl[_rightImageIndex] placeholderImage:_placeHolderImage];
_scrollView.contentOffset = CGPointMake(kADView_Width, 0);
}
@end
三.如何调用
#import "ViewController.h"
#import "YCAdView.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *arrTitle = @[@"1",@"2",@"3"];
NSArray *arrImage = @[@"http://krdong.weixinmob.com/static/uploads/adminapp/zhengce/1_plots.jpg",
@"http://krdong.weixinmob.com/static/uploads/adminapp/zhengce/758BDBD576E7FD8B65FA003353D2904E.jpg",
@"http://krdong.weixinmob.com/static/uploads/adminapp/zhengce/Hydrangeas.jpg"];
YCAdView *ycAdView = [YCAdView initAdViewWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 300)
images:arrImage
titles:arrTitle
placeholderImage:[UIImage imageNamed:@"123.jpeg"]];
ycAdView.clickAdImage = ^(NSInteger index)
{
NSLog(@"点击了第%ld图片",index);
};
[self.view addSubview:ycAdView];
}
@end
四. 需完善的地方
基本上满足了一般广告轮播的所有需求,但是我发现从产品角度出发需要完善一个细节,就是在手动滑动scrollView时,需要暂停定时器,此篇博客中没有对此做处理。另外,如果一个界面用了广告轮播的效果,如果还要在同一个控制器中开启另一个定时器,一定要注意,两个定时器在同一个控制器中使用,需要做处理,不然会引起另外一个定时器失效。