iOS-XIB方式实现一个既能手动又能自动无限滚动的UIScrollView

一、 需求
1.实现一个既能手动又能自动无限滚动的scrollView,有页码,有按钮(点击按钮,scrollView消失)
2.每个界面出现时,五秒内用户不手动滑动界面,就会调用自动滑动界面的方法自动切换到下一张图片
3.当用户在5s内在屏幕上进行滑动时,检测滑动的距离,进行图片的切换,并重置计时器,使之重新开始计算时间即从当前时间开始算5s内用户再不滑动界面就再次实现切换图片。
二、思路以及实现
1.既能手动又能自动如何实现?
我的做法是默认是自动滚动的

#pragma mark -
#pragma mark - Timer part
- (void)shouldAutoShow:(BOOL)shouldStart
{
    // Turn on automatic page turning
    if (shouldStart) {
        if (!self.autoScrollTimer) {
            self.autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(autoShowNextImage) userInfo:nil repeats:YES];
        }

    }else {
        // Turn off automatic page turning
        if (self.autoScrollTimer.isValid) {
            [self.autoScrollTimer invalidate];
            self.autoScrollTimer = nil;
        }
    }
}
当检测到手指在屏幕上滑动时,捕获滑动距离,实现滚动画面的切换。同时重置自动滚动的计时器,重新开始计算时间。
// Automatically show the next page
- (void)autoShowNextImage
{
    self.currentPage ++;
    if (self.currentPage == imageCount) {
        self.currentPage = homePageIndex;
    }
    self.tvuPageControl.currentPage = self.currentPage;
    if (self.currentPage == imageCount - 1) {
        self.buttonTitle = [NSString stringWithFormat:@"%@ >>",NSLocalizedString(@"Close", nil)];
        [self.hideCarouselViewButton setTitle:self.buttonTitle forState:UIControlStateNormal];
    }else {
        self.buttonTitle = [NSString stringWithFormat:@"%@ >>",NSLocalizedString(@"Skip", nil)];
        [self.hideCarouselViewButton setTitle:self.buttonTitle forState:UIControlStateNormal];
    }

    [self changeImageViewWith:self.currentPage];
    self.tvuScrollView.contentOffset = CGPointMake(self.tvuScrollView.frame.size.width, self.tvuScrollView.frame.origin.y);
}
// 重启计时器,从当前时间开始计算5s内
- (void)restartAutoScrollTimer {

    if (self.autoScrollTimer.isValid) {
        [self.autoScrollTimer invalidate];
        self.autoScrollTimer = nil;
    }
    self.autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(autoShowNextImage) userInfo:nil repeats:YES];
}

2.用三个imageView实现图片的无限循环播放,即不停的根据当前页切换三个imageView上的图片
3.计算三个imageView要展示的图片的下摆哦公式是:
Left 取得图片的索引是 (index + array.count) % array.count
Middle 取得图片的索引是 (index + array.count - 1) % array.count
Right 取得图片的索引是 (index + array.count + 1) % array.count

#define CC_CYCLEINDEX_CALCULATE(x,y) (x+y)%y  // Calculate the cycle index
// Change the carousel picture
- (void)changeImageViewWith:(NSInteger)imageNumber
{
    self.middleImageView.image = self.imageArray[CC_CYCLEINDEX_CALCULATE(imageNumber,self.imageArray.count)];
    self.leftImageView.image = self.imageArray[CC_CYCLEINDEX_CALCULATE(imageNumber - 1,self.imageArray.count)];
    self.rightImageView.image = self.imageArray[CC_CYCLEINDEX_CALCULATE(imageNumber + 1,self.imageArray.count)];
}

4.手动滚动时,怎么根据偏移量切换图片

#pragma mark -
#pragma mark - scrollViewDelegate part
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    // Open the manual scroll
    self.tvuScrollView.scrollEnabled = YES;
    [self restartAutoScrollTimer];
    CGPoint offset = self.tvuScrollView.contentOffset;
    if (offset.x == 2 * self.tvuScrollView.frame.size.width) {// 后一张图片
        self.currentPage = CC_CYCLEINDEX_CALCULATE(self.currentPage  + 1,self.imageArray.count);
    } else if (offset.x == 0){// 前一张图片
        self.currentPage = CC_CYCLEINDEX_CALCULATE(self.currentPage  - 1,self.imageArray.count);
    }else{
        return;
    }
    self.tvuPageControl.currentPage = self.currentPage;
    [self changeImageViewWith:self.currentPage];
    self.tvuScrollView.contentOffset = CGPointMake(self.tvuScrollView.frame.size.width, self.tvuScrollView.frame.origin.y);

    if (self.currentPage == 3) {
        self.buttonTitle = [NSString stringWithFormat:@"%@ >>",NSLocalizedString(@"Close", nil)];
        [self.hideCarouselViewButton setTitle:self.buttonTitle forState:UIControlStateNormal];
    }else {
        self.buttonTitle = [NSString stringWithFormat:@"%@ >>",NSLocalizedString(@"Skip", nil)];
        [self.hideCarouselViewButton setTitle:self.buttonTitle forState:UIControlStateNormal];
    }    
}

5.XIB 创建scrollview时,需要通过代码重置frame以适配多种机型尺寸

#pragma mark -
#pragma mark - XIB layout part
- (void)updateViewConstraints{
    [super updateViewConstraints];
    self.tvuScrollView.frame = [UIScreen mainScreen].bounds;
    self.contentViewWidth.constant = CGRectGetWidth([UIScreen mainScreen].bounds) * imageViewCount;
    self.middleImageViewLeading.constant = CGRectGetWidth([UIScreen mainScreen].bounds) * (imageViewCount - 3);
    self.middleImageViewLeading.constant = CGRectGetWidth([UIScreen mainScreen].bounds) * (imageViewCount - 2);
    self.rightImageViewLeading.constant = CGRectGetWidth([UIScreen mainScreen].bounds) * (imageViewCount - 1);
    self.tvuScrollView.contentOffset = CGPointMake(CGRectGetWidth([UIScreen mainScreen].bounds), 0);
}

三 、 其他知识点
1.判断应用第一次打开或者升级后第一次打开

    NSString *currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSString *saveVersion  = [[NSUserDefaults standardUserDefaults] objectForKey:@"CFBundleShortVersionString"];
    if ([currentVersion floatValue] > [saveVersion floatValue]) {
        NSLog(@"用户是第一次安装或者升级后第一次打开");
    }

2.如何判断当前设备的语言环境

    NSArray *allLanguages = [TVUUserDefaults objectForKey:@"AppleLanguages"];
    NSString *preferredLang = [allLanguages objectAtIndex:0];
    if([preferredLang rangeOfString:@"zh-Hans"].location != NSNotFound) {

        NSLog(@"中文语言环境");
    }else {

        NSLog(@"英文或者其他语言环境");
    }

3.判断设备机型

+ (NSString*)deviceModelName
{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];

    //iPhone
    if ([deviceModel isEqualToString:@"iPhone8,1"])    return @"iPhone 6s";
    if ([deviceModel isEqualToString:@"iPhone8,2"])    return @"iPhone 6s Plus";
    if ([deviceModel isEqualToString:@"iPhone9,1"])    return @"iPhone 7 (CDMA)";
    if ([deviceModel isEqualToString:@"iPhone9,3"])    return @"iPhone 7 (GSM)";
    if ([deviceModel isEqualToString:@"iPhone9,2"])    return @"iPhone 7 Plus (CDMA)";
    if ([deviceModel isEqualToString:@"iPhone9,4"])    return @"iPhone 7 Plus (GSM)";

    if ([deviceModel isEqualToString:@"iPhone10,1"])    return @"iPhone 8";
    if ([deviceModel isEqualToString:@"iPhone10,4"])    return @"iPhone 8";
    if ([deviceModel isEqualToString:@"iPhone10,2"])    return @"iPhone 8 Plus";
    if ([deviceModel isEqualToString:@"iPhone10,5"])    return @"iPhone 8 Plus";

    if ([deviceModel isEqualToString:@"iPhone10,3"])    return @"iPhone X";
    if ([deviceModel isEqualToString:@"iPhone10,6"])    return @"iPhone X";

    if ([deviceModel isEqualToString:@"iPhone5,1"])    return @"iPhone 5";
    if ([deviceModel isEqualToString:@"iPhone5,2"])    return @"iPhone 5";
    if ([deviceModel isEqualToString:@"iPhone5,3"])    return @"iPhone 5C";
    if ([deviceModel isEqualToString:@"iPhone5,4"])    return @"iPhone 5C";
    if ([deviceModel isEqualToString:@"iPhone6,1"])    return @"iPhone 5S";
    if ([deviceModel isEqualToString:@"iPhone6,2"])    return @"iPhone 5S";
    if ([deviceModel isEqualToString:@"iPhone7,1"])    return @"iPhone 6 Plus";
    if ([deviceModel isEqualToString:@"iPhone7,2"])    return @"iPhone 6";

    //iPod
    if ([deviceModel isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";
    if ([deviceModel isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";
    if ([deviceModel isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";
    if ([deviceModel isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";
    if ([deviceModel isEqualToString:@"iPod5,1"])      return @"iPod Touch 5G";

    //iPad
    if ([deviceModel isEqualToString:@"iPad1,1"])      return @"iPad";
    if ([deviceModel isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";
    if ([deviceModel isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";
    if ([deviceModel isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
    if ([deviceModel isEqualToString:@"iPad2,4"])      return @"iPad 2 (32nm)";
    if ([deviceModel isEqualToString:@"iPad2,5"])      return @"iPad mini (WiFi)";
    if ([deviceModel isEqualToString:@"iPad2,6"])      return @"iPad mini (GSM)";
    if ([deviceModel isEqualToString:@"iPad2,7"])      return @"iPad mini (CDMA)";

    if ([deviceModel isEqualToString:@"iPad3,1"])      return @"iPad 3(WiFi)";
    if ([deviceModel isEqualToString:@"iPad3,2"])      return @"iPad 3(CDMA)";
    if ([deviceModel isEqualToString:@"iPad3,3"])      return @"iPad 3(4G)";
    if ([deviceModel isEqualToString:@"iPad3,4"])      return @"iPad 4 (WiFi)";
    if ([deviceModel isEqualToString:@"iPad3,5"])      return @"iPad 4 (4G)";
    if ([deviceModel isEqualToString:@"iPad3,6"])      return @"iPad 4 (CDMA)";

    if ([deviceModel isEqualToString:@"iPad4,1"])      return @"iPad Air";
    if ([deviceModel isEqualToString:@"iPad4,2"])      return @"iPad Air";
    if ([deviceModel isEqualToString:@"iPad4,3"])      return @"iPad Air";
    if ([deviceModel isEqualToString:@"iPad5,3"])      return @"iPad Air 2";
    if ([deviceModel isEqualToString:@"iPad5,4"])      return @"iPad Air 2";
    if ([deviceModel isEqualToString:@"iPad6,3"])      return @"iPad Pro 9.7";
    if ([deviceModel isEqualToString:@"iPad6,4"])      return @"iPad Pro 9.7";
    if ([deviceModel isEqualToString:@"iPad6,7"])      return @"iPad Pro 12.9";
    if ([deviceModel isEqualToString:@"iPad6,8"])      return @"iPad Pro 12.9";
    if ([deviceModel isEqualToString:@"iPad6,11"])     return @"iPad Pro 9.7 5Gen";
    if ([deviceModel isEqualToString:@"iPad6,12"])     return @"iPad Pro 9.7 5Gen";
    if ([deviceModel isEqualToString:@"iPad7,1"])      return @"iPad Pro 12.9 2Gen";
    if ([deviceModel isEqualToString:@"iPad7,2"])      return @"iPad Pro 12.9 2Gen";
    if ([deviceModel isEqualToString:@"iPad7,3"])      return @"iPad Pro 10.5";
    if ([deviceModel isEqualToString:@"iPad7,4"])      return @"iPad Pro 10.5";

    if ([deviceModel isEqualToString:@"i386"])         return @"Simulator";
    if ([deviceModel isEqualToString:@"x86_64"])       return @"Simulator";

    if ([deviceModel isEqualToString:@"iPad4,4"]
        ||[deviceModel isEqualToString:@"iPad4,5"]
        ||[deviceModel isEqualToString:@"iPad4,6"])      return @"iPad mini 2";

    if ([deviceModel isEqualToString:@"iPad4,7"]
        ||[deviceModel isEqualToString:@"iPad4,8"]
        ||[deviceModel isEqualToString:@"iPad4,9"])      return @"iPad mini 3";

    if ([deviceModel isEqualToString:@"iPad5,1"] || [deviceModel isEqualToString:@"iPad5,2"])      return @"iPad mini 4";

    return deviceModel;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值