功能:

在我们刚刚打开App时,一般首页会有一个广告展示的页面,能显示几张自动翻滚的图片,还能通过点击来跳转到对应页。
如下图:

实现

这是一个给项目中Controller类用的CustomView,需要在多个Controller中使用,可以单独写一个类,继承UIView,然后定义delegate和datasource,在Controller类里实现delegate和datasouce方法,来显示的具体内容。这个CustomView主要通过一个ScrollView+PageView实现。Scrolview上Add了三个SubViews:当前显示的View、显示View的前一个View、显示View的后一个View。

具体实现

1、创建控件并显示

自定义了一个CustomView,有两种方法来init:代码和xib文件。这时会调用CustomView的不同init方法。从代码创建时,调用initWithFrame;而从xib文件创建时,调用initWithCoder。

这边用代码来创建控件。首先会调用initwithframe方法来创建控件并设置控件frame。在这个方法里,创建了scrollview和pageview,并add到当前类的view中。_scrollview的contentoffset为frame的width,因为控件显示的是scrollview的中间页。
//创建控件,写在Controller类的loadview方法中
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        _scrollView.delegate = self;
        _scrollView.contentSize = CGSizeMake(self.frame.size.width * 3, self.frame.size.height);
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
        _scrollView.pagingEnabled = YES;
        [self addSubview:_scrollView];
        CGRect rect = CGRectMake(80, self.bounds.size.height - 20, 160, 20);
        _pageControl = [[UIPageControl alloc] initWithFrame:rect];
        _pageControl.userInteractionEnabled = NO;
        [self addSubview:_pageControl];
        //控件显示的页面
        _curPage = 0;
    }
    return self;
}
控件创建了,不过内容是空的。怎么添加具体内容呢?当然是在Controller类中实现delegate和datasource方法了。

在CustomView的.h文件中:

//内存管理方式是MRC
@property (nonatomic,assign,setter = setDataource:) id<XLCycleScrollViewDatasource> datasource;

@protocol XLCycleScrollViewDatasource <NSObject>
@required
- (NSInteger)numberOfPages;
- (UIView *)pageAtIndex:(NSInteger)index;

@end

在Controller类中,CustomView.dataSouce = self;程序就跑到CustomView的setDataource;方法中。在这个方法里,我们就可以设置显示的内容。

- (void)setDataource:(id<XLCycleScrollViewDatasource>)datasource
{
    _datasource = datasource;
    [self reloadData];
}

- (void)reloadData
{
    _totalPages = [_datasource numberOfPages];
    if (_totalPages == 0) {
        return;
    }
    _pageControl.numberOfPages = _totalPages;
    [self loadData];
}

- (void)loadData
{

    _pageControl.currentPage = _curPage;

    //从scrollView上移除所有的subview
    NSArray *subViews = [_scrollView subviews];
    if([subViews count] != 0) {
        [subViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    }
    //通过_curPage(当前显示的页面),来设置显示在Scrollview上的3个View(保存在_curViews中)
    [self getDisplayImagesWithCurpage:_curPage];

    for (int i = 0; i < 3; i++) {
        UIView *v = [_curViews objectAtIndex:i];
        v.userInteractionEnabled = YES;
        UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                    action:@selector(handleTap:)];
        [v addGestureRecognizer:singleTap];
        [singleTap release];
        v.frame = CGRectOffset(v.frame, v.frame.size.width * i, 0);
        [_scrollView addSubview:v];
    }
    //中间页为显示页
    [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0)];
}

在设置_datasource = datasource;后,就可以通过[_datasouce functionName];来调用Controller类中实现的datasouce方法了。_curViews是一个NSMutableArray类,通过_curPage具体设置其中的3个object。

/**
 *  获取需要显示的3个View
 *
 *  @param page 当前显示页
 */
- (void)getDisplayImagesWithCurpage:(int)page {

    int pre = [self validPageValue:_curPage-1];
    int last = [self validPageValue:_curPage+1];

    if (!_curViews) {
        _curViews = [[NSMutableArray alloc] init];
    }

    [_curViews removeAllObjects];
    [_curViews addObject:[_datasource pageAtIndex:pre]];
    [_curViews addObject:[_datasource pageAtIndex:page]];
    [_curViews addObject:[_datasource pageAtIndex:last]];
}

可以看到,在loadData方法中,为每个View添加了Tap手势,实现点击功能。

到这里,控件创建了并在Controller上显示了第一页。理一理,假设Controller类为A,CustomView为B。
[A loadView] -> [B initWithFrame] -> A类中B.dataSource = self;->[B setDataSouce:]

2、滑动控件,View切换

通过- (void)scrollViewDidScroll:要捕获ScrolView的滚动事件,可以获取当前ScrollView的contentOffSSet。

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
    int x = aScrollView.contentOffset.x;

    //往下翻一张
    if(x == (2*self.frame.size.width)) {
        _curPage = [self validPageValue:_curPage+1];
        [self loadData];
    }

    //往上翻
    if(x == 0) {
        _curPage = [self validPageValue:_curPage-1];
        [self loadData];
    }
}

因为设置了ScrollVeiw的pageEnabled属性未yes,ScrollView就会根据view来设置ContentOffSet,界面不会停留在某个view的中间。通过[self loadData]来重新设置ScrollView显示的内容。

结束了

到这儿,功能就实现了,还可以通过添加NSTimer来动态显示,就是可以每隔N秒,自动切换图片。
点击下载代码

我觉得有意思的一点:界面都是在代码运行完后显示的,就是说,一个关于界面的方法,在return后,界面才会更新(可以通过GCD来设置界面更新的顺序)。在- (void)scrollViewDidScroll:方法中,假如界面滑动到了下一个View,这个View替换了显示的View时,就调用了[self loadData]方法,这个方法里,又重新设置了ScrollView的内容,又刷新了ScrollView。就显示下一个内容来说,看着是很顺畅显示到了下个页面,中间的调用[self loadDta]页面的刷新,完全被覆盖了。神奇~


走路放慢脚步
107 声望3 粉丝

It is what you do that defines you