scrollView结合pageControl视图切换

(一)开篇描述

(1)本blog中的实例是参考ScrollViewLoop,增加自己对demo中代码的理解;

(2)实例中运用到了runtime的创建属性的方法objc_setAssociatedObject和获取创建属性的方法objc_getAssociatedObject;

(3)NSObject cancelPreviousPerformRequestsWithTarget,取消performSelector方法注册的函数。


(二)实例以及代码解析

#import <UIKit/UIKit.h>


@protocol bnnerTViewDelegate <NSObject>

- (void) Log;

@end

@interface bnnerTView : UIView <UIScrollViewDelegate>
{
    BOOL _isAutoPlay;
}

@property (nonatomic ,assign) id<bnnerTViewDelegate> delegate;

- (instancetype)initWithFrame:(CGRect)frame delegate:(id<bnnerTViewDelegate>)delegate ItemsName:(NSArray *)Items isAuto:(BOOL)isAuto;

- (void)scrollToIndex:(int)aIndex;
@end
#import "bnnerTView.h"
#import <objc/runtime.h>

@interface bnnerTView ()
{
    UIScrollView *scroller;
    UIPageControl *pageControl;
}

@end

@implementation bnnerTView

static NSString *SG_FOCUS_ITEM_ASS_KEY = @"loopScrollview";
static CGFloat SWITCH_FOCUS_PICTURE_INTERVAL = 3.0; //每隔三秒切换一次

//自定义的init函数,主要是传递必要的参数,此函数可以继续完善;如可以开放设置自动切换的时间间隔的值SWITCH_FOCUS_PICTURE_INTERVAL; - (instancetype)initWithFrame:(CGRect)frame delegate:(id<bnnerTViewDelegate>)delegate ItemsName:(NSArray *)Items isAuto:(BOOL)isAuto Interval:(NSTimeInterval *)times
- (instancetype)initWithFrame:(CGRect)frame delegate:(id<bnnerTViewDelegate>)delegate ItemsName:(NSArray *)Items isAuto:(BOOL)isAuto

{
    self = [super initWithFrame:frame];
    
    if (self) {
        
        NSMutableArray *ItemsArray = [NSMutableArray arrayWithArray:Items];
        
        objc_setAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY, ItemsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        _isAutoPlay = isAuto;
        
        [self initViews];
    }
    
    return self;
}


//初始化view,创建scrollView,pageControl,并设置其属性,scrollView开始执行自动切换的操作
//设置scrollView的Subview和contentSize
//设置pageControl的numberOfPages
- (void)initViews {
    
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    
    scroller = [[UIScrollView alloc] initWithFrame:self.bounds];
    scroller.scrollsToTop = NO;
    scroller.pagingEnabled = YES;
    scroller.delegate = self;
    
    
    pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.frame.size.height - 16 - 10, self.bounds.size.width, 10)];
    pageControl.userInteractionEnabled = NO;
    pageControl.numberOfPages = ItemsArray.count > 1 ? ItemsArray.count - 2 : ItemsArray.count;
    
    
    [self addSubview:scroller];
    [self addSubview:pageControl];
    
    for (int i = 0; i < ItemsArray.count; i ++) {
        
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(i * scroller.frame.size.width, 0, scroller.frame.size.width, scroller.frame.size.height)];
        
        imageView.backgroundColor = i % 2 ? [UIColor redColor] : [UIColor blueColor];
        
        [scroller addSubview:imageView];
    }
    
    scroller.contentSize = CGSizeMake(scroller.frame.size.width * ItemsArray.count, scroller.frame.size.height);
    
    if (ItemsArray.count > 1)
    {
        [scroller setContentOffset:CGPointMake(scroller.frame.size.width, 0) animated:NO];
        if (_isAutoPlay)
        {
            [self performSelector:@selector(changeCurrentItems) withObject:nil afterDelay:SWITCH_FOCUS_PICTURE_INTERVAL];
        }
    }
}


//定义scrollView自动切换的函数
//解释cancelPreviousPerformRequestsWithTarget:取消performSelector方法注册的函数
//changeCurrentItems使用的方法就是,先取消注册performSelector方法,最后又注册performSelector方法。
//scroller.frame.size.width表示每切换一次所增加的contentOffset.x的距离
- (void)changeCurrentItems {
    
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(changeCurrentItems) object:nil];
    
    int targetX = scroller.contentOffset.x + scroller.frame.size.width;
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    targetX = (targetX / scroller.frame.size.width) * scroller.frame.size.width;
    
    [self moveToTargetPosition:targetX];
    
    if (ItemsArray.count > 1 && _isAutoPlay) {
        
        [self performSelector:@selector(changeCurrentItems) withObject:nil afterDelay:SWITCH_FOCUS_PICTURE_INTERVAL];
    }
}


//在滑动scroller的时候会触发此委托函数,因此在此委托函数中进行页码的计算以及scroller的contentOffset的计算
//contentOffset计算的方法:获取滑动scroller的contentOffset.x,并进行比较(scroller.frame.size.width * (ItemsArray.count - 1)滑动到了最后一页,就将scroller的contentOffset设置成首页的位置;反之,将contentOffset设置成最后一页的位置,即contentOffset.x <= 0)
//page计算的方法:(scrollView.contentOffset.x + scroller.frame.size.width / 2.0) / scroller.frame.size.width;其中scroller.frame.size.width表示每滑动一次的距离。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    float targetX = scrollView.contentOffset.x;
    
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    
    if (ItemsArray.count >= 3) {
        
        //当前显示的是最后一张图片
        if (targetX >= scroller.frame.size.width * (ItemsArray.count - 1)) {
            
            targetX = scroller.frame.size.width;
            [scroller setContentOffset:CGPointMake(targetX, 0) animated:NO];
        }
        
        //当前显示的是第一张图片
        else if (targetX <= 0) {
            
            targetX = scroller.frame.size.width * (ItemsArray.count - 2);
            [scroller setContentOffset:CGPointMake(targetX, 0) animated:NO];
        }
    }
    
    
    int page = (scrollView.contentOffset.x + scroller.frame.size.width / 2.0) / scroller.frame.size.width;
    
    if (ItemsArray.count > 1)
    {
        page --;
        if (page >= pageControl.numberOfPages) { //向左滑动,页码从最后一页跳转至第一页
            
            page = 0;
        }
        else if(page < 0) { //向右滑动,页码从第一页跳转至最后一页
            
            page = (int)pageControl.numberOfPages - 1;
        }
    }
    
    pageControl.currentPage = page;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    
    if (!decelerate) {
        
        int targetX = scrollView.contentOffset.x + scroller.frame.size.width;
        
        targetX = (int)(targetX + scroller.frame.size.width) / scroller.frame.size.width;
        
        [self moveToTargetPosition:targetX];
    }
}


//设置scroller的contentOffset为targetX
- (void)moveToTargetPosition:(CGFloat)targetX {
    
    [scroller setContentOffset:CGPointMake(targetX, 0) animated:YES];
}


//可以设置scroller的起始页码
- (void)scrollToIndex:(int)aIndex {
    
    NSArray *ItemsArray = objc_getAssociatedObject(self, (__bridge const void *)SG_FOCUS_ITEM_ASS_KEY);
    
    if ([ItemsArray count] > 1) {
        
        if (aIndex >= (ItemsArray.count - 2)) {
            
            aIndex = (int)ItemsArray.count - 3;
        }
        
        [self moveToTargetPosition:scroller.frame.size.width * (aIndex + 1)];
    }
    else {
        
        [self moveToTargetPosition:0];
    }
    
    [self scrollViewDidScroll:scroller];
}
@end

代码的理解都写在了函数的开头处;本实例还有很多可完善的(完善delegate增加可操作性等)。

你可能感兴趣的:(scrollView结合pageControl视图切换)