scrollView自动布局技巧
- 步骤:
1. sb中拖scrollView
2. 设置scrollView上下左右为0
4. 拖一个UIView"yellowView"到scrollView中(不是imageView)
5. 设置yellowView的自动布局上下左右为0(此时报错,实际缺少尺寸"无法算出contentSize")
6. 设置yellowView和scrollView等宽等高
7. 更新frame,并运行
- 此时无法滚动,因为contentSize和scrollView的size一样大
8.设置yellowView宽约束的是scrollView宽的2倍,并运行
- 此时 可以滚动了,因为yellowView的宽大于scrollView自身的宽
9. 设置yellowView顶部约束为64,并运行,会影响它的contentSize
10. 给yellowView上的添加按钮,并设置约束,演示分页属性,并运行
- 实验小结:
1. 设置scrollView中内容的距离scrollView四边边距值,会影响contentSize即滚动范围,上下间距
会影响contentSize的Hieght"垂直滚动范围",左右间距会影响水平滚动范围(不常用,了解装逼使用)
2. 如果用AutoLayout约束scrollView中的内容时只设置四边间距约束是不够的,还要设置view宽高
3. 除了UIImageView可以不用直接设置宽高,因为它里面如果设置了图片,imageView的size会根据图片
自适应,对应设置 scrollView的contentSize
4. 切记scrollView在实用自动布局时比较特殊
5. 建议:如果一个scrollView中有很多小控件可以把小控件添加一个容器视图 view,设置容器view的尺
寸为contentSize
scrollView-代理方法
- scrollViewDidScroll: 滚动视图滚动时使用
- scrollViewDidEndDecelerating: 滚动视图停止滚动时使用
- viewForZoomingInScrollView: 缩放视图时使用
- 滚动相关方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(@"%@", @"scrollview视图开始滚动");
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
NSLog(@"%@", @"将要减速 - 在释放开手之后调用");
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(@"%@", @"完成减速 - 完全静止后调用");
}
- 缩放相关方法
实现缩放的两个步骤
- 需要设置最小缩放比例(minimumZoomScale)和最大缩放比例(maximumZoomScale)都为1时无法缩放
- 需要实现 “viewForZoomingInScrollView” 方法 告诉 scrollView 缩放的视图
( 只要缩放就会调用 )
// 告诉滚动视图缩放的视图
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
// @param scrollView 滚动视图
// @param view 缩放的视图
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {
NSLog(@"%@", @"缩放开始时调用");
}
/// @param scrollView 滚动视图
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
NSLog(@"%@",@"正在缩放时调用");
}
/// @param scrollView 滚动视图
/// @param view 缩放的视图
/// @param scale 缩放的比例
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {
NSLog(@"%@",@" 缩放结束后调用");
}
- 拖拽相关方法
/// @param scrollView 滚动视图
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(@"%@", @"将要开始拖拽");
}
/// @param scrollView 滚动视图
/// @param velocity 速度
/// @param targetContentOffset 目标偏移位置
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
NSLog(@"%@", @"将要结束拖拽");
}
/// @param scrollView 滚动视图
/// @param decelerate 是否减速
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(@"%@ %d", @"完成拖拽方法,手指放开后调用", decelerate);
}
- 状态栏相关方法
结合 self.scrollView.scrollsToTop = YES;使用要告诉它点了状态栏对那个scrollView进行滚动
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
NSLog(@"%@", @"将要滚动到顶部,点击状态栏时调用");
return YES;
}
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
NSLog(@"%@", @"已经滚动到状态栏");
}
- 动画相关方法
/**
The scroll view calls this method at the end of its implementations of the setContentOffset:animated: and scrollRectToVisible:animated: methods, but only if animations are requested.
滚动视图会在实现了 setContentOffset:animated: & scrollRectToVisible:animated: 方法之后
调用此方法
同时必须在上述两个方法中允许动画
*/
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
NSLog(@"%@", @"调用动画结束");
}
关于代理设计模式
- 自己想干一件事,但是自己不能主动完成/不能完成,要找一个对象帮自己完成
scrollView知道被滚动了,但是不知道被滚动以后将要做什么
手写代理步骤
- 找人做事情的人
- 协议
- 协议中的方法
- 代理对象属性
- 在需要做事情的’时候’,通过代理对象,执行协议中的方法
- 做事情的人
- 遵守协议
- 设置代理对象
- 实现代理方法,在代理方法中做事情
- 找人做事情的人
ScrollView-属性
- contentSize: 内容大小,设置了才可以滚动
- contentOffset: 内容偏移位置
- contentInset: 内容间距
- pagingEnabled: 是否允许分页
- bounces: 是否允许弹簧效果
- showsHorizontalScrollIndicator: 是否允许显示水平指示器(滚动条)
- showsVerticalScrollIndicator: 是否允许显示垂直指示器(滚动条)
- 滚动内容属性
// 内容偏移位置
@property(nonatomic) CGPoint contentOffset; // default CGPointZero
// 内容大小,设置了才可以滚动
@property(nonatomic) CGSize contentSize; // default CGSizeZero
// 内容间距
@property(nonatomic) UIEdgeInsets contentInset;
- 委托属性
@property(nullable,nonatomic,weak) id<UIScrollViewDelegate> delegate;
要想监听滚动视图的滚动 / 拖拽 / 缩放 / 状态栏交互
需要设置 delegate
实现相关协议方法
- 弹簧效果属性
// 允许弹簧效果
@property(nonatomic) BOOL bounces; // default YES. if YES, bounces past edge of content and back again
// 始终允许垂直弹
@property(nonatomic) BOOL alwaysBounceVertical; // default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag vertically
// 始终允许水平弹
@property(nonatomic) BOOL alwaysBounceHorizontal;
- 分页属性
// 允许分页
@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled __TVOS_PROHIBITED;// default NO. if YES, stop on multiples of view bounds
- 指示器属性
// 显示水平指示器
@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
// 指示器样式
@property(nonatomic) UIScrollViewIndicatorStyle indicatorStyle; // default is UIScrollViewIndicatorStyleDefault
在 scrollView 中指示器本质上就是 UIImageView
通过查看视图层次结构可以看到
- 缩放属性
// 最小缩放比例
@property(nonatomic) CGFloat minimumZoomScale; // default is 1.0
// 最大缩放比例
@property(nonatomic) CGFloat maximumZoomScale; // default is 1.0. must be > minimum zoom scale to enable zooming
要允许缩放
必须设置以上两个属性
同时遵守协议
实现协议方法 -viewForZoomingInScrollView:
- 状态栏属性
// 点击状态栏滚动到顶部
// default is YES. TVOS上此属性禁用,
@property(nonatomic) BOOL scrollsToTop __TVOS_PROHIBITED;
一个视图中,如果有多个 scrollView
只有唯一一个 scrollView 的 scrollsToTop 属性设置为 YES,才支持点击状态栏滚动到顶部
虽然此属性默认值即为YES不过还要要设置,不然不知道点了状态栏要对那个scrollView进行滚动
- 键盘属性
// 键盘解除模式
@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode NS_AVAILABLE_IOS(7_0); // default is UIScrollViewKeyboardDismissModeNone
如果是 UITextView,通常需要将 alwaysBounceVertical 属性设置为 YES
typedef NS_ENUM(NSInteger, UIScrollViewKeyboardDismissMode) {
// 无
UIScrollViewKeyboardDismissModeNone,
// 拖拽关闭键盘
UIScrollViewKeyboardDismissModeOnDrag, // dismisses the keyboard when a drag begins
// 必须要拖拽到键盘才可以关闭键盘,很少使用
UIScrollViewKeyboardDismissModeInteractive, // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
} NS_ENUM_AVAILABLE_IOS(7_0);
- 常用方法
// 动画设置偏移位置
- (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
- 三种图像填充模式
- scale的意思是:缩放,在contentMode中出现的话,就是要改变图形的大小了。
- aspect的意思是纵横的比例,在contentMode中的意思是保持图形的纵横比,保持图片不变形。
scale to fill:缩放图片,使图片充满容器。因为没有aspect,所以是不保持纵横比的。图片不是按比例缩放的。
scale aspect fit: 在保持纵横比(aspect)的前提下,缩放图片(scale),使图片在容器内都显示出来(fit)。
保证图片完整显示,但不保证能充满容器。
scale aspect fill:在保持纵横比(aspect)的前提下,缩放图片(scale),使图片充满容器(fill)。保证图片能
充满容器,不保证图片能完整显示。
新特性视图规则
新特性视图
- 自动布局的选择?
- 如果是全屏的直接bounds,如果不是考虑使用自动布局
- 并不是每次都需要现实新特性界面,所以留个后路,以后再改
- 创建控件时调用init或initWithFrame方法最后都会去调用对象父类的initWithFrame方法
隐藏状态栏
- 隐藏状态来这些不属于显示也不属于数据,所以应该再C中找.
- -(BOOL)prefersStatusBarHidden
传递数据思路对比
- View直接写数据?(1)
- 控制器传递给View?(2)
- 可能面临到视图移植的问题,也就说,如果我另外一个项目也需要同样的需求,那么:
- 如果使用第一种方式,需要做的工作.
- 拷贝文件,更改view内部中的图片名称.
- 如果使用第二种方式,需要做的工作.
- 拷贝文件,在控制器重新写数据,传入view.
- 如果使用第一种方式,需要做的工作.
- 视图只负责现实,控制器负责调度.
- 两种方式,没有对不对,只有合不合适.
将新特性数组传递给新特性
- 新建一个装满imageName的数组传递给视图
设置scrollView的frame
- 创建scrollView并设置frame
ZFBGuideView *guideView = [[ZFBGuideView alloc] initWithFrame:self.view.bounds];
ZFBGuideView *guideView = [[ZFBGuideView alloc] init];
guideView.frame = self.view.bounds;
- 两种写法都会调用initWithFrame
- 重写了initWithFrame并且同时重写了init的方法,第一种形式的方法不会再调用init
- 设置子控件的frame应该使用layoutSubviews
- layoutSubviews一定要重写父方法
- 约束的代码不能写在layoutSubviews方法中,此方法会多次调用
scrollView显示图片并设置属性
- setImageNames方法中添加imageView到scrollView中
- 并且设置图像和contentSize
- 分页
- 水平和垂直指示器(方便使用subviews)
- 禁用弹性
设置更多按钮的自动布局
- 添加到imageView上
- 开启用户交互
- userInteractionEnabled(bool)
添加按钮监听/新特性移除动画
- 通过transform和透明度做动画
- 移除整个新特性视图
使用代码创建pageControl
- 应该添加到新特性视图上,如果添加到scrollView上会跟着滚动
- 禁用分页的用户交互
pageControl位置/设置总页数
- 自动布局设置pageControl位置
- 总页数应该根据图片数量来,所以写在setImageNames方法中
设置pageControl当前页数
- 在结束滚动的代理方法中,根据offset和scrollView的宽度进行计算
- 或者
- 在正在滚动的代理方法中,根据offset和scrollView的宽度进行计算(加0.4999再强转)
拖拽细节/隐藏pageControl
- 需求的最右可以拖拽,思考怎么样增加?
- 根据页数进行pageControl的隐藏和现实.