UIScrollView 小结

1 ScrollView实质

  1. scrollView.contentView才是其展现内容,对应的是contentSize,须要手动设置(相似frame)objective-c

  2. 在滑动时,实际改变的是scrollView.bounds.origin。浏览器

bounds是scrollView内部坐标系,boundsorigin,至关于原点的坐标值安全

2 contentOffset

拉列表,列表越长,contentOffset越大。 contentSize就是contentView的size。 contentSize、contentOffset和contentInset的图解辨别bash

Banner于TableViewapp

  • 能够放在Header中
  • 也能够做为子控件,而后设置contentOffset.y=-50。

3 一些属性

3.1 自动安全区域偏移相关

  • adjustContentInset,表示contentView.frame.origin偏移了scrollview.frame.origin多少;是系统计算得来的,计算方式由contentInsetAdjustmentBehavior决定。计算规则较复杂,iOS 11 安全区域适配总结

不但愿上面Inset中自动修改,iOS11以前设置Controller的automaticallyAdjustsScrollViewInsets为NO,iOS11以后动画

if ([scrollview respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {

   scrollview.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

}

复制代码
  • contentInset、scrollIndicatorInsets

做为controller.view第0个子视图时,会自动修改contentInset和scrollIndicatorInsets属性,避免导航栏、TabBar的遮挡。ui

3.2 其余

  • bounces

默认YES,即便用户滑到了头,仍是能够滑(可用于下拉刷新等),会显示背景色。spa

  • alwaysBounceVertical

依赖于bounces=YES3d

默认NO,设置成YES,即便内容小于bounds,也能够拉。代理

  • pagingEnabled

只能中止在bounds的倍数上,配合UIPageControl能够实现轮播页的效果

  • zoomScale相关

放缩用

  • dragging, tracking, decelerating

状态相关,拖曳、触碰、减速状态

3.3 refreshControl iOS10

UIRefreshControl

4 一些应用

4.1 悬停控件

原理:经过-scrollViewDidScroll:代理方法,跟踪contentOffset的的变化。不知足悬停条件时,hidden。

4.2 头部图片下拉放大

原理:

经过-scrollViewDidScroll:代理方法跟踪contentOffset的的变化,根据contentOffset动态设置图片的缩放比例

// 以"动态修改图片缩放比例于1倍和2倍之间"为例
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
   CGFloat scale = 1 - (scrollView.contentOffset.y / 100);
   scale = (scale >= 1) ? scale : 1;
   scale = (scale <= 2) ? scale : 2;
   imageView.transform = CGAffineTransformMakeScale(scale, scale);
}
复制代码

4.3 无限轮播

原理:

建立N+2个UIImageView

经过-scrollViewDidScroll:代理方法,跟踪contentOffset的的变化

在滑动到首尾两个图片处,设置contentOffset到真实图片处。

4.4 图片浏览器+图片放缩功能

通常是用 childVC + UIPageViewController 实现

4.5 滑动方向判断

下面最后两个与scrollview无关

  1. 利用拖曳位置: 开始位置 + 中止&中止滑动位置,contentOffset判断

  2. 若是实时性要求高,能够在didScroll里面,按照时间间隔来判断(基本不会用到)

  3. TableView、CollectionView 利用beginDragging + willDisplayCell:的contentOffset判断。

  4. 利用手势

  5. 利用touchesBegan:、touchesMoved:、touchesEnded:

5 经常使用代理方法

滚动

//contentOffset发生变化时调用(包括拖曳、减速过程、直接代码设置)

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;

复制代码

手指相关,一次拖曳,只调用一次。

//1 将要开始拖拽页面(非实时)

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;

//2 将要中止拖曳时(以velocity为初速度,直到targetContentOffset中止。可经过修改targetContentOffset,调整位置)

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset 

//3 手指离开时,若是decelerate为NO时,表示`滑动动画结束`。

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;

//4 判断中止动画,要配合2或3,才完备

- (void)scrollViewWillEndDecelerating:(UIScrollView *)scrollView;

复制代码

放缩

- (void)scrollViewDidZoom:(UIScrollView *)scrollView;

- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; // return a view that will be scaled. if delegate returns nil, nothing happens

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view NS_AVAILABLE_IOS(3_2); // called before the scroll view begins zooming its content

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale;

复制代码

状态栏

// 当scrollView已经滑动到顶部时调用(仅当点击状态栏让scrollView滑动到顶部才调用) 

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;

复制代码
// 当-setContentOffset:animated:/-scrollRectVisible:animated:方法动画结束时调用(仅当animated设置为YES时才调用) 

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;

复制代码

6 其余值得注意的地方

UIScrollView处理触摸事件原理

用户按下时,UIScrollView不知道用户的意图

在按下一瞬间,UIEvent传递完成后,不会马上响应,而是开始一个150ms的倒计时,并监听用户接下来的行为

  • 倒计时结束前,手指发生移动,滚动contentView,优先识别为手势。

  • 倒计时结束时,手指位置没改变,调用-touchesShouldBegin:withEvent:inContentView: 询问是否将事件的响应权交给子视图(NO则不传递,YES则传递,默认YES)

  • 事件传递给子视图后,手指位置又发生了移动,调用-touchesShouldCancelInContentView:询问是否取消已传递给子视图的事件

这里原文中写的是,ScrollView会拦截UIEvent不传给子视图,根据经验,若是ScrollView嵌套ScrollView,仍是子ScrollView先响应,所以,传递应该仍是会传递的,可是谁来响应,依据是手势 & 响应链中说的,手势>UIControl>UIResponder。

UIScrollView的详细使用介绍和实现原理分析[2018.06.20更新]

UIScrollView实战经验

只能横向/纵向滑动

只容许横向:

设置subview的frameY与scrollView的frameY相等,而后设置alwaysBounceVertical=No(默认就是No)

相关文章
相关标签/搜索