您的位置:首页 > 产品设计 > UI/UE

UIScrollView 的基本使用

2017-03-13 11:50 645 查看

UIScrollView 基本使用

UIScrollView 的三个属性

contentSize
设置滚动区域,只有设置了滚动区域才能够滚动
contentOffset
设置滚动内容偏移,决定当前显示的内容
contentInset
设置滚动外框的偏移

UIScrollView 无法滚动原因

UIScrollView 设置弹簧效果 & 滚动指示器

常用属性演练

准备工作

新建项目
ViewController
中实现以下代码,添加
scrollView

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

[self setupUI];
}

#pragma mark - 设置界面
- (void)setupUI {

// 1. 创建 UIScrollView
UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.bounds];
sv.backgroundColor = [UIColor blueColor];
[self.view addSubview:sv];
}

@end

添加
imageView

// 2. 添加 imageView
UIImage *image = [UIImage imageNamed:@"002"];
// initWithImage 方法创建的 imageView 会根据 image 的大小自动调整大小
UIImageView *iv = [[UIImageView alloc] initWithImage:image];

// 将 图像视图 添加到 滚动视图上
[sv addSubview:iv];


运行程序,会发现不会滚动,那么如何滚动呢?

探索头文件

NS_CLASS_AVAILABLE_IOS(2_0) @interface UIScrollView : UIView <NSCoding>

/// The point at which the origin of the content view is offset from the origin of the scroll view.
/// 内容视图原点(origin)所在的偏移位置,相对于 scroll view 的 origin,默认是 CGPointZero
@property(nonatomic)         CGPoint                      contentOffset;                  // default CGPointZero
/// The size of the content view
/// 内容视图的大小,默认是 CGSizeZero
@property(nonatomic)         CGSize                       contentSize;                    // default CGSizeZero
/// The distance that the content view is inset from the enclosing scroll view.
/// 内容视图围绕(enclosing) scroll view 的距离,默认值是 UIEdgeInsetsZero
@property(nonatomic)         UIEdgeInsets                 contentInset;                   // default UIEdgeInsetsZero. add additional scroll area around content

定义属性,方便后续代码演练
@property (nonatomic, weak) UIScrollView *scrollView;
@property (nonatomic, weak) UIImageView *imageView;

setupUI
方法中使用成员变量记录局部变量
_scrollView = sv;
_imageView = iv;

新建
demoScrollView
方法并在
viewDidLoad
方法中调用
- (void)viewDidLoad {
[super viewDidLoad];

[self setupUI];
[self demoScrollView];
}

#pragma mark - 演练 scrollview
- (void)demoScrollView {

}

三个属性演练

contentSize
contentOffset
contentInset

contentSize

demoScrollView
中实现以下方法
- (void)demoScrollView {

// 1. 设置 contentSize
// 让 scrollView 的 contentSize 等于 图像视图的大小
// 设置了滚动视图的 contentSize 之后,滚动视图就能够滚动了
_scrollView.contentSize = _imageView.bounds.size;
}


结论

设置了滚动视图的 contentSize 之后,滚动视图就能够滚动了

没有
contentSize
,scrollView 就不知道要
滚多远


单独设置
contentSize
width

// contentSize 的 width 决定了水平方向能滚多远
_scrollView.contentSize = CGSizeMake(_imageView.bounds.size.width, 0);

单独设置
contentSize
height

// contentSize 的 height 决定了垂直方向能滚多远
_scrollView.contentSize = CGSizeMake(0, _imageView.bounds.size.height);


结论

scrollView 要滚动就必须设置了滚动视图的 contentSize
contentSize 的 width 决定了水平方向滚动距离
contentSize 的 height 决定了垂直方向滚动距离

方法名重构 —— 快捷键
cmd + shift + e

/// 演示 contentSize
///
/// 结论:
/// - scrollView 要滚动就必须设置了滚动视图的 contentSize
/// - contentSize 的 width 决定了水平方向滚动距离
/// - contentSize 的 height 决定了垂直方向滚动距离
- (void)demoContentSize {

// 1. 设置 contentSize
// 让 scrollView 的 contentSize 等于 图像视图的大小
// 设置了滚动视图的 contentSize 之后,滚动视图就能够滚动了
_scrollView.contentSize = _imageView.bounds.size;

// contentSize 的 width 决定了水平方向能滚多远
//    _scrollView.contentSize = CGSizeMake(_imageView.bounds.size.width, 0);

// contentSize 的 height 决定了垂直方向能滚多远
//    _scrollView.contentSize = CGSizeMake(0, _imageView.bounds.size.height);
}

contentOffset

新建方法
demoContentOffset
并在
viewDidLoad
调用
- (void)viewDidLoad {
[super viewDidLoad];

[self setupUI];
[self demoContentSize];
[self demoContentOffset];
}

#pragma mark - 演练 scrollview
/// 演示 contentOffset
- (void)demoContentOffset {

}

增加演示按钮
/// 演示 contentOffset
- (void)demoContentOffset {

// 1. 增加演示按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeInfoLight];
btn.center = self.view.center;
[self.view addSubview:btn];

[btn addTarget:self action:@selector(clickOffsetButton) forControlEvents:UIControlEventTouchUpInside];
}

/// 点击测试 offset 按钮
- (void)clickOffsetButton {

}

实现代码修改
contentOffset

/// 点击测试 offset 按钮
- (void)clickOffsetButton {

// 修改 scrollView 的 contentOffset
_scrollView.contentOffset = CGPointMake(50, 50);

// bounds 决定了内部控件布局的原点坐标
NSLog(@"%@", NSStringFromCGRect(_scrollView.bounds));
}

修改代码,递增
contentOffset
的变化
// 2> 递增 contentOffset
CGPoint p = _scrollView.contentOffset;
p.x += 50;
p.y += 50;
_scrollView.contentOffset = p;

修改 NSLog
// bounds 决定了内部控件布局的原点坐标
// scrollView 的 contentOffset 属性本质上就是 bounds 的原点
NSLog(@"%@ - %@", NSStringFromCGRect(_scrollView.bounds), NSStringFromCGPoint(_scrollView.contentOffset));


结论

scrollView 通过修改 contentOffset 调整内部视图的坐标位置,从而给用户产生一种视觉上的滚动的效果
contentOffset 的值本质上就是 bounds 的原点(origin) 值,苹果在为了方便程序员的理解,增加了这个属性

文档释义:contentOffset:内容视图原点(origin)所在的偏移位置,相对于 scroll view 的 origin,默认是 CGPointZero



contentOffset 相关方法

探索头文件
/// 以恒定速度动画移动到新的 offset
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;  // animate at constant velocity to new offset
/// 滚动到可见区域(靠近边缘-不会滚动到边缘外侧),如果当前区域完全可见,则什么也不做
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;         // scroll so rect is just visible (nearest edges). nothing if rect completely visible


苹果头文件的特点:越是重要的属性和方法就越靠上

新建测试方法
/// 测试 offset 相关方法
- (void)testSetOffsetMethod {

}

修改按钮监听方法
[btn addTarget:self action:@selector(testSetOffsetMethod) forControlEvents:UIControlEventTouchUpInside];

实现方法,测试
setContentOffset:animated:
方法
/// 测试 offset 相关方法
- (void)testSetOffsetMethod {

// 1. 测试 setContentOffset
CGFloat x = arc4random_uniform(_imageView.bounds.size.width);
CGFloat y = arc4random_uniform(_imageView.bounds.size.height);

// 利用系统默认的动画效果,动画时长不能修改
[_scrollView setContentOffset:CGPointMake(x, y) animated:YES];
}

自定义动画效果
// 2> 自定义动画效果
[UIView
animateWithDuration:1.0
delay:0 usingSpringWithDamping:0.8
initialSpringVelocity:0
options:0
animations:^{
_scrollView.contentOffset = CGPointMake(x, y);
} completion:nil];

新建方法
testScrollRectMethod

- (void)testScrollRectMethod {

// 传入当前完全可见区域,什么也不发生
[_scrollView scrollRectToVisible:_scrollView.bounds animated:YES];
}

随机区域
// 2> 随机区域
CGFloat x = arc4random_uniform(_imageView.bounds.size.width);
CGFloat y = arc4random_uniform(_imageView.bounds.size.height);
CGRect rect = CGRectMake(x, y, _scrollView.bounds.size.width, _scrollView.bounds.size.height);

[_scrollView scrollRectToVisible:rect animated:YES];

contentInset

/// 内容视图围绕(enclosing) scroll view 的距离,默认值是 UIEdgeInsetsZero
@property(nonatomic)         UIEdgeInsets                 contentInset;                   // default UIEdgeInsetsZero. add additional scroll area around content

新增方法
demoContentInset
并且在
viewDidLoad
调用
- (void)viewDidLoad {
[super viewDidLoad];

[self setupUI];
[self demoContentSize];
[self demoContentOffset];
[self demoContentInset];
}

#pragma mark - 演练 scrollview
/// 演示 contentInset
- (void)demoContentInset {
}

实现方法
demoContentInset

/// 演示 contentInset
- (void)demoContentInset {

UIEdgeInsets inset = UIEdgeInsetsMake(50, 50, 50, 50);

// 边距设置了,但是初始没有效果,需要拖拽一下才有效果
_scrollView.contentInset = inset;
}

利用
contentOffset
设置初始位置
// 设置 contentOffset 调整到边距对应位置
_scrollView.contentOffset = CGPointMake(-inset.left, -inset.top);


结论

scrollView 通过修改 contentInset 调整内部和边缘的偏移

设置边距之后,初始没有效果,需要拖拽一下才有效果

可以通过设置 contentOffset 调整初始位置

scrollView 与内容相关的三个属性示意图如下:



结论

scrollView 要滚动就必须设置了滚动视图的 contentSize

contentSize 的 width 决定了水平方向滚动距离
contentSize 的 height 决定了垂直方向滚动距离

scrollView 通过修改 contentOffset 调整内部视图的坐标位置,从而给用户产生一种视觉上的滚动的效果

contentOffset 的值本质上就是 bounds 的原点(origin) 值,苹果在为了方便程序员的理解,增加了这个属性

scrollView 通过修改 contentInset 调整内部和边缘的偏移

设置边距之后,初始没有效果,需要拖拽一下才有效果
可以通过设置 contentOffset 调整初始位置

设置弹簧效果 & 滚动指示器

探索头文件
/// 默认 YES
@property(nonatomic)         BOOL                         bounces;                        // default YES. if YES, bounces past edge of content and back again
/// 始终垂直弹,默认是 NO,如果设置成 YES,即使内容比区域小,同样允许垂直方向弹动
@property(nonatomic)         BOOL                         alwaysBounceVertical;           // default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag vertically
/// 始终水平弹,默认是 NO,如果设置成 YES,即使内容比区域小,同样允许水平方向弹动
@property(nonatomic)         BOOL                         alwaysBounceHorizontal;         // default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag horizontally

/// 是否允许滚动,默认是 YES,关闭之后禁止任何拖拽
@property(nonatomic,getter=isScrollEnabled) BOOL          scrollEnabled;                  // default YES. turn off any dragging temporarily
/// 显示水平滚动指示器
@property(nonatomic)         BOOL                         showsHorizontalScrollIndicator; // default YES. show indicator while we are tracking. fades out after tracking
/// 显示垂直滚动指示器
@property(nonatomic)         BOOL                         showsVerticalScrollIndicator;   // default YES. show indicator while we are tracking. fades out after tracking
/// 滚动指示器边距
@property(nonatomic)         UIEdgeInsets                 scrollIndicatorInsets;          // default is UIEdgeInsetsZero. adjust indicators inside of insets

新建方法,并且在 viewDidLoad 调用
- (void)viewDidLoad {
[super viewDidLoad];

[self setupUI];
[self demoContentSize];
[self demoContentOffset];
[self demoContentInset];

[self demoBounces];
}

#pragma mark - 演练 scrollview
/// 演示弹簧效果
- (void)demoBounces {

}

实现方法,禁止弹簧效果
/// 演示弹簧效果
- (void)demoBounces {
// 1. 禁止弹簧效果
_scrollView.bounces = NO;
}

测试始终弹动
// 2. 测试始终允许弹簧效果
// 取消 contentSize 无法滚动
_scrollView.contentSize = CGSizeZero;
_scrollView.alwaysBounceVertical = YES;
_scrollView.alwaysBounceHorizontal = YES;

测试禁止滚动属性
_scrollView.scrollEnabled = NO;


如果禁止滚动,弹簧效果同样失效

测试滚动指示器
// 3. 滚动指示器
// 1> 禁用垂直滚动指示器
_scrollView.showsVerticalScrollIndicator = NO;
// 1> 禁用水平滚动指示器
_scrollView.showsHorizontalScrollIndicator = NO;


查看视图层次结构会发现,禁用指示器之后,那两个 UIImageVi
9c22
ew 不见了

结论

苹果是用 imageView 实现的
水平
垂直
指示器
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: