「iOS」UI——无限轮播图实现与UIPageControl运用

「OC」UI

文章目录

  • 「OC」UI
    • 无限轮播图的实现以及UIPageControl的实际运用
      • 明确要求
      • 简单滚动视图的实现
        • UIPageControl的实现
        • 设置NSTimer实现自动移动
        • 补充实现
    • 进行无限滚动视图的修改
      • 思路
      • 实现
    • 完整代码展示

无限轮播图的实现以及UIPageControl的实际运用

明确要求

我们要实现一个能够进行无限滚动播放的视图程序,首先需要实现的是一个简单的滚动图片视图,在视图之中添加相关的UIPageControl的控件,让我们能够知道我们当前图片是处在滚动页面的哪个位置上。在实现简单滚动视图的基础上进行修改,使其实现无限轮播的功能。

简单滚动视图的实现

提到滚动视图,我们就会想起刚刚学习的UIScrollView,使用UIImageVIew布局在UIScrollView之中,我们写给其写个函数将UIScrollView的框架封装起来

- (void)setupScrollView {//进行初始化操作self.scrollView = [[UIScrollView alloc] init];self.scrollView.frame = CGRectMake(0, 80, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 320);//设置整页滚动self.scrollView.pagingEnabled = YES;self.scrollView.scrollEnabled = YES;self.scrollView.delegate = self;//由于我们使用UIPageControl所以,self.scrollView.showsHorizontalScrollIndicator = NO;CGFloat h = [UIScreen mainScreen].bounds.size.height - 320;CGFloat w = [UIScreen mainScreen].bounds.size.width;self.scrollView.contentSize = CGSizeMake(w * 5, h); // 五个图片设置五个宽度for (int i = 0; i < 5; i++) {NSString *name = [NSString stringWithFormat:@"%d.jpg", i];UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:name]];imageView.frame = CGRectMake(i * w, 0, w, h);[self.scrollView addSubview:imageView];}[self.view addSubview:self.scrollView];
}
UIPageControl的实现

对于UIPageControl的实现十分简单,实现如下

- (void)setupPageControl {self.pageControl = [[UIPageControl alloc] init];//设置PageControl与滚动视图对齐self.pageControl.frame = CGRectMake(0, CGRectGetMaxY(self.scrollView.frame) - 20, CGRectGetWidth(self.scrollView.frame), 20);self.pageControl.numberOfPages = 5;//设置初始页面self.pageControl.currentPage = 0;self.pageControl.pageIndicatorTintColor = [UIColor redColor];self.pageControl.currentPageIndicatorTintColor = [UIColor blueColor];self.pageControl.userInteractionEnabled = NO;[self.view addSubview:self.pageControl];
}

那么对于当前位置的UIPageControl显示的变化,我们也要控制下面显示的变化,对于我们显示的变化,我们可以进行更深入的控制,,我们在当前偏移量添加半个视图宽度,这样当我们当前图片偏移量超过半个宽度之后,UIPageControl的位置就会发生变化,就会显得我们的显示更加智能,我们将代码写在scrollViewDidScroll:(UIScrollView *)scrollView之中,这个函数是当UIScrollView发生滚动就会调用。

(void)scrollViewDidScroll:(UIScrollView *)scrollView {CGFloat offSetX = scrollView.contentOffset.x;//求取当前页CGFloat pageWidth = scrollView.frame.size.width;int currentPage = floor((offSetX - pageWidth / 2) / pageWidth) + 1;//控制UIPageControl 的当前页self.pageControl.currentPage = currentPage;
}
设置NSTimer实现自动移动

我们可以设置一个定时器,使其不断进行视图的替换,我们设置间隔为2秒,每两秒调用翻页的方法,对滚动视图界面进行翻页,需要特殊判断的是,当移动到最后的时候,我们需要将其调到第一个视图。

- (void)setupTimer {//创建定时器_timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];}- (void)nextPage {NSInteger page = self.pageControl.currentPage;if (page == self.pageControl.numberOfPages - 1) {page = 0;} else {page++;}CGFloat offSetX = page * self.scrollView.frame.size.width;[self.scrollView setContentOffset:CGPointMake(offSetX, 0) animated:YES];}
补充实现

当我们在使用鼠标对滚动视图进行抓取移动时,由于定时器的存在,视图仍然会进行移动,因此,我们为了方便操作,我们可以在当鼠标进行点击时,将计时器取消,当鼠标结束拖拽时重新创建计时器,我们就需要用上两个函数。

  • -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView :当开始进行拖拽
  • -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate:当拖拽结束时

实现如下:

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {if ([self.timer isValid]) {[self.timer invalidate];self.timer = nil;}
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{if (![_timer isValid]) {_timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];}
}

Jun-19-2024 00-02-48

进行无限滚动视图的修改

思路

我们在对其进行无限滚动视图的修改,首先我们要了解无限滚动视图的如何进行实现的,我们需要在原本的滚动视图之中,左右各自添加一个新的视图。这是为什么呢?

我们将五张图片简化为三张图片,形状如下:

image-20240618235611013

通过观察我们的原理图,我们可以很清晰的了解我们需要实现的功能:当我们的滚动视图处于第二张视图的位置(第一张pic1的位置)时,向前滑动所展示的图片是png3;当处于倒数第二张视图的位置(第二张pic3)时,向后滚动要展现的图片是pic1。了解轮播图是这个结构之后,我们就要思考如何去实现这个功能,我们使用偏移量进行解决,当我们即将翻到从pic1翻到pic3(情况1)或者pic3直接翻到pic1(情况2)的时候,我们从偏移量之中读取这种情况,然后进行滚动视图的变化,当情况1出现时,就会将当前视图从pic1的位置直接跳到标红的pic3的位置:情况2同理视图就会从pic3跳转到标红的pic1。由于动画效果的存在,我们进行滑动的时候,并不会在显示之中发现视图变化的不自然。

实现

我们对以上的程序进行修改,由于是五张图片,那么我们在左右两边多添加两张图片,我们称第一张和最后一张图片为实现无限滚动视图的假图,我们对框架内的函数进行修改,此外我们还需要将滚动视图的定位定位至pic1处。

  • ScrollView
- (void)setupScrollView {self.scrollView = [[UIScrollView alloc] init];self.scrollView.frame = CGRectMake(0, 80, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 320);self.scrollView.pagingEnabled = YES;self.scrollView.scrollEnabled = YES;self.scrollView.delegate = self;self.scrollView.showsHorizontalScrollIndicator = NO;CGFloat h = [UIScreen mainScreen].bounds.size.height - 320;CGFloat w = [UIScreen mainScreen].bounds.size.width;self.scrollView.contentSize = CGSizeMake(w * 7, h); // 包括两个额外的页面for (int i = 0; i < 7; i++) {NSString *name;if (i == 0) {name = @"5.jpg"; // 第一页前面的假页} else if (i == 6) {name = @"1.jpg"; // 最后一页后面的假页} else {name = [NSString stringWithFormat:@"%d.jpg", i];}UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:name]];imageView.frame = CGRectMake(i * w, 0, w, h);[self.scrollView addSubview:imageView];}// 设置默认显示的页面(实际第一页)[self.scrollView setContentOffset:CGPointMake(w, 0) animated:NO];[self.view addSubview:self.scrollView];
}
  • scrollViewDidScroll:(UIScrollView *)scrollView在这个函数之中的内容就是我们实现无限滚动视图的关键,请看代码
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {CGFloat offsetX = scrollView.contentOffset.x;//滚动视图的显示宽度CGFloat pageWidth = scrollView.frame.size.width;//新添加的内容if (offsetX >= pageWidth * 6) {// 滚动到假的最后一页,瞬间跳到实际第一页[self.scrollView setContentOffset:CGPointMake(pageWidth, 0) animated:NO];} else if (offsetX <= 0) {// 滚动到假的第一页,瞬间跳到实际最后一页[self.scrollView setContentOffset:CGPointMake(pageWidth * 5, 0) animated:NO];}// 更新UIPageControl的当前页NSInteger currentPage = (scrollView.contentOffset.x + pageWidth / 2) / pageWidth;//当翻到假页时对pagecontrol进行修改,使其符合要求if (currentPage == 0) {self.pageControl.currentPage = 4;} else if (currentPage == 6) {self.pageControl.currentPage = 0;} else {self.pageControl.currentPage = currentPage - 1;}
}
  • 在我们使用翻页的方法也需要进行一点点的改变,我们要将page的偏移量加一。在这里还有一个小细节,由于无限滚动视图的实现,我们不再需要对最后一张视图进行特判,我们只需要在每次调用的时候然page++就可以了。
- (void)nextPage {NSInteger page = self.pageControl.currentPage;if (page == self.pageControl.numberOfPages - 1) {page = 0;} else {page++;}CGFloat offsetX = (page + 1) * self.scrollView.frame.size.width; // 偏移量加1,因为第1页是假的[self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
}

完整代码展示

#import "ViewController.h"@interface ViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIPageControl *pageControl;
@property (nonatomic, strong) NSTimer *timer;
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[self setupScrollView];[self setupPageControl];[self setupTimer];
}- (void)setupScrollView {self.scrollView = [[UIScrollView alloc] init];self.scrollView.frame = CGRectMake(0, 80, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 320);self.scrollView.pagingEnabled = YES;self.scrollView.scrollEnabled = YES;self.scrollView.delegate = self;self.scrollView.showsHorizontalScrollIndicator = NO;CGFloat h = [UIScreen mainScreen].bounds.size.height - 320;CGFloat w = [UIScreen mainScreen].bounds.size.width;self.scrollView.contentSize = CGSizeMake(w * 7, h); // 包括两个额外的页面for (int i = 0; i < 7; i++) {NSString *name;if (i == 0) {name = @"5.jpg"; // 第一页前面的假页} else if (i == 6) {name = @"1.jpg"; // 最后一页后面的假页} else {name = [NSString stringWithFormat:@"%d.jpg", i];}UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:name]];imageView.frame = CGRectMake(i * w, 0, w, h);[self.scrollView addSubview:imageView];}// 设置默认显示的页面(实际第一页)[self.scrollView setContentOffset:CGPointMake(w, 0) animated:NO];[self.view addSubview:self.scrollView];
}- (void)setupPageControl {self.pageControl = [[UIPageControl alloc] init];self.pageControl.frame = CGRectMake(0, CGRectGetMaxY(self.scrollView.frame) - 20, CGRectGetWidth(self.scrollView.frame), 20);self.pageControl.numberOfPages = 5;self.pageControl.currentPage = 0;self.pageControl.pageIndicatorTintColor = [UIColor redColor];self.pageControl.currentPageIndicatorTintColor = [UIColor blueColor];self.pageControl.userInteractionEnabled = NO;[self.view addSubview:self.pageControl];
}- (void)setupTimer {self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
}- (void)nextPage {NSInteger page = self.pageControl.currentPage;if (page == self.pageControl.numberOfPages - 1) {page = 0;} else {page++;}CGFloat offsetX = (page + 1) * self.scrollView.frame.size.width; // 偏移量加1,因为第1页是假的[self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
}- (void)scrollViewDidScroll:(UIScrollView *)scrollView {CGFloat offsetX = scrollView.contentOffset.x;CGFloat pageWidth = scrollView.frame.size.width;if (offsetX >= pageWidth * 6) {// 滚动到假的最后一页,瞬间跳到实际第一页[self.scrollView setContentOffset:CGPointMake(pageWidth, 0) animated:NO];} else if (offsetX <= 0) {// 滚动到假的第一页,瞬间跳到实际最后一页[self.scrollView setContentOffset:CGPointMake(pageWidth * 5, 0) animated:NO];}// 更新UIPageControl的当前页NSInteger currentPage = (scrollView.contentOffset.x + pageWidth / 2) / pageWidth;if (currentPage == 0) {self.pageControl.currentPage = 4;} else if (currentPage == 6) {self.pageControl.currentPage = 0;} else {self.pageControl.currentPage = currentPage - 1;}- (void)nextPage {NSInteger page = self.pageControl.currentPage;if (page == self.pageControl.numberOfPages - 1) {page = 0;} else {page++;}CGFloat offsetX = (page + 1) * self.scrollView.frame.size.width; // 偏移量加1,因为第1页是假的[self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
}- (void)scrollViewDidScroll:(UIScrollView *)scrollView {CGFloat offsetX = scrollView.contentOffset.x;CGFloat pageWidth = scrollView.frame.size.width;if (offsetX >= pageWidth * 6) {// 滚动到假的最后一页,瞬间跳到实际第一页[self.scrollView setContentOffset:CGPointMake(pageWidth, 0) animated:NO];} else if (offsetX <= 0) {// 滚动到假的第一页,瞬间跳到实际最后一页[self.scrollView setContentOffset:CGPointMake(pageWidth * 5, 0) animated:NO];}// 更新UIPageControl的当前页NSInteger currentPage = (scrollView.contentOffset.x + pageWidth / 2) / pageWidth;if (currentPage == 0) {self.pageControl.currentPage = 4;} else if (currentPage == 6) {self.pageControl.currentPage = 0;} else {self.pageControl.currentPage = currentPage - 1;}
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{if ([_timer isValid]) {[_timer invalidate];_timer = nil;}
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{if (![_timer isValid]) {_timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];}
}
@end

完整展示如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/29737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、C#类型转换

在C#中&#xff0c;类型转换是将一个数据类型的值转换为另一个数据类型的过程。 C#中的类型转换可以分为两种&#xff1a;隐式类型转换和显式类型转换&#xff08;也称为强制类型转换&#xff09;。 隐式类型转换 隐式转换是不需要编写代码来指定的转换&#xff0c;编译器会…

SSM旅游系统

摘要 旅游业正处于快速发展阶段&#xff0c;旅游系统的建设已经成为了旅游业发展的重要核心问题。在这样的背景下&#xff0c;SSM框架正逐步发展为一种主要的架构。但目前青海省旅游业信息化的发展仍面临诸多问题&#xff0c;包括系统功能不完善、用户体验不佳、数据管理不规范…

c语言中的字符函数

1.字符分类函数 c语言中有一系列函数是专门做字符分类的&#xff0c;也就是一个字符属于什么类型的字符。这些函数的使用需要包含一个头文件是ctype.h 可能你看这些感觉很懵&#xff0c;我以islower举例 #include<ctype.h> int main() {int retislower(A);printf("…

Apache Doris 之 Docker 部署篇

前言 在现代数据驱动的商业环境中&#xff0c;实时数据分析和高并发查询能力是企业成功的关键因素之一。传统的数据仓库和分析工具在面对大规模数据处理和实时分析需求时&#xff0c;往往力不从心。Apache Doris 作为一个现代的 MPP 数据库管理系统&#xff0c;凭借其强大的查…

uni微信小程序使用lottie

在uni插件市场找到 lottie-uni https://ext.dcloud.net.cn/plugin?id1044按照文档要求安装 HBuilderX 引入 下载或导入示例获取插件 import lottie from /common/lottie-miniprogram.jsindex.vue <template><uni-popupref"popup"type"center"ba…

俄罗斯ozon爆款推荐丨ozon学生受众产品

在俄罗斯电商平台OZON上&#xff0c;学生受众是一个庞大且活跃的群体。为了满足他们的需求&#xff0c;OZON平台上涌现出了一系列受学生欢迎的爆款产品。以下是一些针对学生受众的OZON爆款推荐&#xff1a; OZON选品工具&#xff1a;D。DDqbt。COM/74rD Top1 UNO纸牌游戏 俄语…

【OpenGL学习】OpenGL不同版本渲染管线汇总

文章目录 一、《OpenGL编程指南》第6版/第7版的渲染管线二、《OpenGL编程指南》第8版/第9版的渲染管线 一、《OpenGL编程指南》第6版/第7版的渲染管线 图1. OpenGL 2.1、OpenGL 3.0、OpenGL 3.1 等支持的渲染管线 二、《OpenGL编程指南》第8版/第9版的渲染管线 图2. OpenGL …

windows 下安装Nuclei 详细教程

一、软件介绍 Nuclei是一款基于YAML语法模板的开发的定制化快速漏洞扫描器。它使用Go语言开发&#xff0c;具有很强的可配置性、可扩展性和易用性。 二、下载安装 官网&#xff1a;https://docs.projectdiscovery.io/tools/nuclei/overview Nuclei项目地址&#xff1a;​​…

记一次 .NET某机械臂上位系统 卡死分析

一&#xff1a;背景 1. 讲故事 前些天有位朋友找到我&#xff0c;说他们的程序会偶发性的卡死一段时间&#xff0c;然后又好了&#xff0c;让我帮忙看下怎么回事&#xff1f;窗体类的程序解决起来相对来说比较简单&#xff0c;让朋友用procdump自动抓一个卡死时的dump&#x…

0. 云原生之基于乌班图远程开发

云原生专栏大纲 文章目录 安装乌班图配置静态IP重置root密码开启root远程登录开启远程SSH访问安装docker安装docker-compose安装Edge浏览器安装搜狗输入法安装TeamViewer安装虚拟显示器安装JDK安装maven安装vscodevscode插件安装VSCode配置maven、git、jdk、自动报错vscode快捷…

30v-180V降3.3V100mA恒压WT5107

30v-180V降3.3V100mA恒压WT5107 WT5107是一款恒压单片机供电芯片&#xff0c;它可以30V-180V直流电转换成稳定的3.3V直流电&#xff08;最大输出电流300mA&#xff09;&#xff0c;为各种单片机供电。WT5107的应用也非常广泛。它可以用于智能家居、LED照明、电子玩具等领域。比…

jupyter使用的一个奇怪bug——SyntaxError: invalid non-printable character U+00A0

bug来由&#xff1a;从其他部分例如kaggle里复制来的代码直接粘贴在jupyter notebook里&#xff0c;每一行代码都会出现&#xff1a; Cell In[5], line 1 warnings.filterwarnings(ignore) ^ SyntaxError: invalid non-printable character U00A0 单元格 In[5]&#xff0c;第 …

多网页登录Cookie免登通俗理解

背景&#xff0c;现在有A、B两个系统&#xff0c;其中B是乾坤框架的微前端&#xff0c;里面又有若干可以单独运行的系统C、D、E、F&#xff0c;现在的目标是&#xff0c;如果没有登录过其中任一系统&#xff0c;则需要跳转登录页登录&#xff0c;登录后&#xff0c;所有的A-F都…

Python 自动化测试入门有哪些内容?

自动化测试是软件测试领域中的一个重要技术&#xff0c;它利用脚本和工具来执行测试任务&#xff0c;减少了人工操作的工作量和时间消耗。Python 是一种功能强大且易于学习的编程语言&#xff0c;被广泛应用于自动化测试领域。本文将从0到1讲解如何使用 Python 进行自动化测试&…

网络编程(一)基本概念

文章目录 一、概念&#xff08;一&#xff09;网络发展阶段1. ARPAnet阶段2. TCP/IP两个协议阶段3. 网络体系结构和OSI开放系统互联模型4. TCP/IP协议簇体系结构&#xff08;1&#xff09; 应用层&#xff1a;&#xff08;2&#xff09;传输层&#xff1a;&#xff08;3&#x…

白名单在数据防篡改方面的优势与局限

白名单作为一种安全机制&#xff0c;其主要目的是通过预先设定受信任的程序、文件或用户列表&#xff0c;来限制系统资源的访问和执行权限。这种机制在防止未授权的程序或文件运行方面具有一定的效果&#xff0c;从而在一定程度上减少病毒入侵的机会。然而&#xff0c;当我们探…

读书笔记-《人人都是产品经理》

在开发工程师与产品经理的段子中&#xff0c;常看到“人人都是产品经理”这句话&#xff0c;用来调侃这个岗位似乎没有什么门槛。 很明显&#xff0c;这句话的出处&#xff0c;即本书作者想表达的是每个人都可以运用产品思维去解决问题。 01 产品 产品&#xff1a;用来解决某…

python中scrapy

安装环境 pip install scrapy 发现Twisted版本不匹配 卸载pip uninstall Twisted 安装 pip install Twisted22.10.0 新建scrapy项目 scrapy startproject 项目名 注意&#xff1a;项目名称不允许使用数字开头&#xff0c;也不能包含中文 eg: scrapy startproject scrapy_baidu_…

热重启(硬重启)获取Bitlocker密钥取证

计算机内存&#xff08;条&#xff09;在系统运行时存储了大量敏感信息&#xff0c;当断电后&#xff0c;内存中的数据荡然无存。反之&#xff0c;当一直通电的情况下&#xff0c;内存中的一些敏感数据一直存在。当然&#xff0c;正如某些人了解的&#xff0c;当断电后&#xf…

管道光电液位传感器应用在哪些设备

管道光电液位传感器在现代智能设备中扮演着至关重要的角色&#xff0c;特别是在需要检测水管缺水的应用场景中。与传统的浮球开关相比&#xff0c;这种传感器具有高可靠性、稳定性和不易卡死等优点。其先进的光学感应原理无需机械运动&#xff0c;确保了长久的寿命和稳定的性能…