一、 需求
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;
}