iOS开发基础8-UIScrollView
1.iOS开发基础1-第一个iOS程序2.iOS开发基础2-基础控件3.iOS开发基础6-懒加载、Plist 文件操作、字典转模型、自定义 View 详解4.iOS开发基础5-UIButton5.iOS开发基础4-图像资源6.iOS开发基础3-UIImage7.iOS开发基础14-KVC的应用与底层逻辑8.iOS开发基础13-深入理解 UITableView(二)9.iOS开发基础12-深入理解UITableView(一)10.iOS开发基础11-屏幕适配、Autolayout及 Masonry 框架11.iOS开发基础10-UIButton内边距和图片拉伸模式12.iOS开发基础9-提示框(UIAlertController)
13.iOS开发基础8-UIScrollView
14.iOS开发基础7-自定义构造方法、layoutSubviews、Xib文件与自定义View15.iOS开发基础30-UITabBarController16.iOS开发基础29-触摸事件及手势识别17.iOS开发基础28-数据存储与沙盒机制18.iOS开发基础27-导航控制器入栈与出栈机制及微博个人详情页19.iOS开发基础26-空20.iOS开发基础25-ARC和MRC深入探析21.iOS开发基础24-UIPickerView、UITextField、KVC、UIDatePicker、控制器及导航控制器22.iOS开发基础23-iOS开发中的Info.plist、UIApplication及其Delegate、UIWindow详解23.iOS开发基础22-键盘通知在iOS开发中的应用24.iOS开发基础21-深入理解通知、代理、KVO和Block在iOS开发中的应用25.iOS开发基础20-UITableView的全局及局部刷新、左滑操作与批量删除26.iOS开发基础19-深入理解和实现不等高的 UITableViewCell27.iOS开发基础18-深入理解 Objective-C Runtime 机制28.iOS开发基础16-使用 `NSTimer` 时避免内存泄露的技巧和最佳实践29.iOS开发基础15-KVO的应用与底层逻辑30.iOS开发基础65-iPad 开发指南31.iOS开发基础64-二维码32.iOS开发基础63-AVFoundation/MediaPlayer33.iOS开发基础62-音频播放34.iOS开发基础61-通讯录35.iOS开发基础60-传感器36.iOS开发基础59-内存优化37.iOS开发基础58-支付宝集成指南38.iOS开发基础57-换肤功能与静态库开发指南39.iOS开发基础56-UIDynamic物理引擎40.iOS开发基础55-利用 UIWindow 实现快速滚动到界面顶部41.iOS开发基础54-CoreLocation42.iOS开发基础53-MapKit 框架43.iOS开发基础47-iOS键盘44.iOS开发基础46-数据安全与HTTPS保护详解45.iOS开发基础45-UIWebview46.iOS开发基础44-网络编程之NSURLSession&AFN47.iOS开发基础43-CocoaPods48.iOS开发基础42-网络编程之文件下载与处理49.iOS开发基础41-网络编程之JSON和XML50.iOS开发基础40-网络编程之NSURLConnection51.iOS开发基础39-RunLoop52.iOS开发基础38-多线程之多图片下载及缓存处理53.iOS开发基础37-多线程之NSOperation54.iOS开发基础36-多线程之GCD55.iOS开发基础35-多线程之NSThread56.iOS开发基础34-多线程57.iOS开发基础33-核心动画(二)58.iOS开发基础33-核心动画(一)59.iOS开发基础32-Quartz2D(二)60.iOS开发基础32-Quartz2D(一)61.iOS开发基础31-Modal 与 Push 详解62.iOS开发基础76-iOS 开发中的属性修饰符详解63.iOS开发基础75-iOS开发中的Block深度解析64.iOS开发基础74-Swift他来了65.iOS开发基础73-24种性能优化技巧66.iOS开发基础72-Xcode 7 升级后的问题与解决方案详解67.iOS开发基础71-应用中的 StatusBar 详解68.iOS开发基础70-TCP与UDP69.iOS开发基础69-应用开发中的 Controller 间通信模式70.iOS开发基础68-图片轮播71.iOS开发基础67-流水布局相册缩放72.iOS开发基础66-UISearchBar 控件指南73.iOS开发基础78-iOS 国际化在 iOS 开发中,UIScrollView 是一个非常重要的滚动视图控件。通过掌握其基本属性、代理方法及高级应用如图片轮播器,我们可以创建出表现力丰富、用户体验良好的应用界面。本文将详细介绍 UIScrollView 的基础用法、属性配置、事件监听、图片缩放,以及如何实现图片轮播器,并进行底层逻辑的分析。
一、UIScrollView 的基本用法
使用步骤
- 创建 UIScrollView。
- 将要展示的内容添加到 UIScrollView。
- 设置 UIScrollView 的滚动范围 (
contentSize
)。
示例代码
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// 添加子控件到 UIScrollView
UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
[self.scrollView addSubview:btn];
UISwitch *sw = [[UISwitch alloc] init];
CGRect tempFrame = sw.frame;
tempFrame.origin.y = 150;
sw.frame = tempFrame;
[self.scrollView addSubview:sw];
UIButton *customBtn = [[UIButton alloc] init];
customBtn.frame = CGRectMake(0, 0, 100, 100);
customBtn.backgroundColor = [UIColor redColor];
[customBtn setTitle:@"我是按钮" forState:UIControlStateNormal];
[self.scrollView addSubview:customBtn];
// 设置滚动范围
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width + 100, self.scrollView.frame.size.height + 100);
}
底层逻辑分析
- 滚动范围:
contentSize
决定了 UIScrollView 可以滚动的范围。如果不设置,默认不能滚动。 - 自动布局:UIScrollView 可以根据添加的子控件自动调整其内容尺寸,但需要手动调用
contentSize
进行微调。
二、UIScrollView 的基本属性
常见属性
scrollEnabled
:控制是否允许滚动,默认值是YES
。userInteractionEnabled
:控制是否允许用户交互,比如点击操作,默认是YES
。showsHorizontalScrollIndicator
和showsVerticalScrollIndicator
:是否显示水平或垂直滚动条。
示例
self.scrollView.scrollEnabled = NO;
self.scrollView.userInteractionEnabled = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.scrollView.bounces = YES;
// 设置是否可以回弹
self.scrollView.alwaysBounceVertical = YES;
self.scrollView.alwaysBounceHorizontal = YES;
底层逻辑分析
- 控制滚动:通过
scrollEnabled
属性可以灵活控制 UIScrollView 是否需要响应滚动操作。 - 用户交互:
userInteractionEnabled
能关闭一切用户交互,但不会影响内部逻辑。 - 滚动条与回弹:滚动条和回弹效果提升了用户体验,尤其在内容较多时。
三、 UIScrollView 事件监听
事件监听步骤
- 成为 UIScrollView 的代理。
- 遵守并实现 UIScrollView 的协议方法。
示例代码
@interface ViewController () <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *sc;
@end
- (void)viewDidLoad {
[super viewDidLoad];
self.sc.delegate = self;
}
#pragma mark - UIScrollViewDelegate
// 滚动时调用
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(@"%s", __func__);
}
// 开始拖拽时调用
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(@"%s", __func__);
}
// 停止拖拽时调用
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(@"%s", __func__);
if (!decelerate) {
[self scrollViewDidEndDecelerating:scrollView];
}
}
// 停止减速时调用
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(@"UIScrollView停止滚动了");
}
底层逻辑分析
- 代理机制:通过代理机制,控制器可以监听 UIScrollView 的一切变化,提供完全的控制权。
- 弱引用代理:防止循环引用,避免内存泄漏。
- 多样化回调:根据滚动状态不同,提供了多种回调方法,使得开发者可以在不同的时间点执行相应操作。
四、 缩放图片
配置缩放
- 设定最大和最小缩放比例。
- 通过代理方法告诉 UIScrollView 哪个控件需要缩放。
示例代码
self.sc.maximumZoomScale = 2.0;
self.sc.minimumZoomScale = 0.5;
self.sc.delegate = self;
#pragma mark - UIScrollViewDelegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.iv;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
NSLog(@"%s", __func__);
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
NSLog(@"%s", __func__);
}
底层逻辑分析
- 缩放策略:通过最大和最小缩放比例控制缩放范围。
- 指定缩放对象:代理方法明确指定需要缩放的子控件,避免混乱。
- 缩放回调:在缩放过程中提供持续的反馈,便于响应用户操作。
五、图片轮播器
通过 UIScrollView 实现图片轮播器是一个常见的需求。以下是实现过程:
基本思路
- 创建 UIScrollView 并添加子控件 UIImageView。
- 通过定时器实现图片的自动滚动。
- 添加 UIPageControl 以指示当前页码。
示例代码
XMGPageView 头文件
#import <UIKit/UIKit.h>
@interface XMGPageView : UIView
+ (instancetype)pageView;
@property (nonatomic, strong) NSArray *imageNames;
@end
XMGPageView 实现
#import "XMGPageView.h"
@interface XMGPageView () <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *sc;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
@property (weak, nonatomic) NSTimer *timer;
@end
@implementation XMGPageView
+ (instancetype)pageView {
return [[[NSBundle mainBundle] loadNibNamed:@"XMGPageView" owner:nil options:nil] lastObject];
}
- (void)awakeFromNib {
[super awakeFromNib];
self.sc.delegate = self;
self.sc.showsHorizontalScrollIndicator = NO;
self.sc.showsVerticalScrollIndicator = NO;
self.sc.bounces = NO;
self.sc.pagingEnabled = YES;
[self.pageControl addTarget:self action:@selector(pageControlClick:) forControlEvents:UIControlEventValueChanged];
[self.pageControl setValue:[UIImage imageNamed:@"current"] forKeyPath:@"_currentPageImage"];
[self.pageControl setValue:[UIImage imageNamed:@"other"] forKeyPath:@"_pageImage"];
[self startTimer];
}
- (IBAction)pageControlClick:(UIPageControl *)sender {
self.sc.contentOffset = CGPointMake(sender.currentPage * self.sc.frame.size.width, 0);
}
- (void)startTimer {
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextPage:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- (void)nextPage:(NSTimer *)timer {
NSUInteger page = self.pageControl.currentPage + 1;
if (page >= self.imageNames.count) {
self.pageControl.currentPage = 0;
} else {
self.pageControl.currentPage = page;
}
[self pageControlClick:self.pageControl];
}
- (void)stopTimer {
[self.timer invalidate];
}
- (void)setImageNames:(NSArray *)imageNames {
_imageNames = imageNames;
for (UIView *subView in self.sc.subviews) {
[subView removeFromSuperview];
}
for (int i = 0; i < _imageNames.count; i++) {
UIImageView *iv = [[UIImageView alloc] init];
iv.image = [UIImage imageNamed:_imageNames[i]];
[self.sc addSubview:iv];
}
self.pageControl.numberOfPages = _imageNames.count;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat width = self.sc.frame.size.width;
CGFloat height = self.sc.frame.size.height;
NSUInteger imageCount = self.imageNames.count;
for (int i = 0; i < imageCount; i++) {
UIImageView *iv = self.sc.subviews[i];
iv.frame = CGRectMake(i * width, 0, width, height);
}
self.sc.contentSize = CGSizeMake(imageCount * width, height);
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat page = scrollView.contentOffset.x / scrollView.frame.size.width;
int currentPage = page + 0.5;
self.pageControl.currentPage = currentPage;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self stopTimer];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
[self startTimer];
}
@end
底层逻辑分析
- 定时器控制:通过定时器实现自动翻页,并在用户操作时暂停和重启定时器。
- 分页控制:UIPageControl 与 UIScrollView 结合,实现手动和自动分页的同步展示。
- 界面更新:通过 set 方法和 layoutSubviews 方法确保界面的一致性和适应性。
结论
通过深入理解 UIScrollView 的基本用法、事件监听、图片缩放以及实现图片轮播器,我们可以创建出流畅且具有丰富交互的应用界面。这些技术和技巧在实际项目中非常实用,可以大大提升用户体验和开发效率。
将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库