iOS开发基础8-UIScrollView
在 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 的基本用法、事件监听、图片缩放以及实现图片轮播器,我们可以创建出流畅且具有丰富交互的应用界面。这些技术和技巧在实际项目中非常实用,可以大大提升用户体验和开发效率。
将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。

浙公网安备 33010602011771号