iOS开发之UIScrollView控件详解

一、UIScrollView控件是什么?

(1)移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限

(2)当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容

(3)普通的UIView不具备滚动功能,不能显⽰示过多的内容

(4)UIScrollView是一个能够滚动的视图控件,可以⽤用来展⽰示⼤大量的内容,并且可以通过滚 动查看所有的内容

(5)  举例:手机上的“设置”、其他⽰示例程序

二、UIScrollView的简单使用

(1)将需要展⽰的内容添加到UIScrollView中

(2)设置UIScrollView的contentSize属性,告诉UIScrollView所有内容的尺⼨寸,也就是告诉 它滚动的范围(能滚多远,滚到哪⾥里是尽头)

注: 本文中所说的"内容视图"在官方文档中称作"content view",表示UIScrollView中可以用来展示内容的部分

三、属性与方法

内容视图相关

// 内容视图的大小,默认为CGSizeZero
@property(nonatomic) CGSize contentSize;

// 为内容视图周围增加可滚动区域,默认为UIEdgeInsetsZero
@property(nonatomic) UIEdgeInsets contentInset;

// 内容视图的原点相对于scrollView的原点的偏移量(左上方向偏移为正数),默认为CGPointZero
@property(nonatomic) CGPoint contentOffset;

// 设置内容视图的原点相对于scrollView的原点的偏移量
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;

滑动相关

// 是否允许滑动,默认为YES
@property(nonatomic,getter=isScrollEnabled) BOOL scrollEnabled;

// 是否只允许同时滑动一个方向,默认为NO,如果设置为YES,用户在水平/竖直方向开始进行滑动,便禁止同时在竖直/水平方向滑动(注: 当用户在对角线方向开始进行滑动,则本次滑动可以同时在任何方向滑动)
@property(nonatomic, getter=isDirectionalLockEnabled) BOOL directionalLockEnabled;

// 是否允许点击状态栏让距离状态栏最近的scrollView滑动到顶部,默认为YES(注: 在iPhone中如果有多个将该属性设置为YES的scrollView,则该方法无效;在iPad中则将距离状态栏最近的scrollView滑动到顶部)
@property(nonatomic) BOOL scrollsToTop;

// 是否按页数进行滑动,默认为NO,如果设置为YES,则在滑动时只会停止在scrollView的bounds的倍数处
@property(nonatomic, getter=isPagingEnabled) BOOL pagingEnabled;

// 是否有触底反弹效果,默认为YES
@property(nonatomic) BOOL bounces;

// 是否总是有触底反弹效果(即使内容视图小于scrollView的大小),默认为NO(注: 生效的前提条件为bounces = YES)
@property(nonatomic) BOOL alwaysBounceHorizontal;
@property(nonatomic) BOOL alwaysBounceVertical;

// 指定用户手指离开屏幕后滑动减速的比率,默认为UIScrollViewDecelerationRateNormal(慢慢停止),其余可选项为UIScrollViewDecelerationRateFast(快速停止)
@property(nonatomic) CGFloat decelerationRate;

// 将指定区域滑动到刚好可见处(即距离边缘最近处)
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;

指示器相关

// 指示器样式,默认为UIScrollViewIndicatorStyleDefault(黑内容白边框,适用于任何背景),其余可选项为UIScrollViewIndicatorStyleBlack(全黑)和UIScrollViewIndicatorStyleWhite(全白)
@property(nonatomic) UIScrollViewIndicatorStyle indicatorStyle;

// 为指示器周围增加可滚动区域,默认为UIEdgeInsetsZero
@property(nonatomic) UIEdgeInsets scrollIndicatorInsets;

// 是否在滑动时指示器可见,默认为YES
@property(nonatomic) BOOL showsHorizontalScrollIndicator;
@property(nonatomic) BOOL showsVerticalScrollIndicator;

// 闪一下指示器(注: 建议在scrollView展示给用户时调用一下,以提醒用户该处可滑动)
- (void)flashScrollIndicators;

事件相关

UIScrollView处理触摸事件原理

当用户在UIScrollView的一个子视图上按下时,UIScrollView并不知道用户是想要滑动内容视图还是点击对应子视图,所以在按下的一瞬间,事件UIEvent从UIApplication传递到UIScrollView后,其会先将该事件拦截而不会立即传递给对应的子视图,同时开始一个150ms的倒计时,并监听用户接下来的行为

1、当倒计时结束前,如果用户的手指发生了移动,则直接滚动内容视图,不会将该事件传递给对应的子视图;

2、当倒计时结束时,如果用户的手指位置没有改变,则调用自身的-touchesShouldBegin:withEvent:inContentView:方法询问是否将事件传递给对应的子视图(如果返回NO,则该事件不会传递给对应的子视图,如果返回YES,则该事件会传递给对应的子视图,默认为YES)

3、当事件被传递给子视图后,如果手指位置又发生了移动,则调用自身的-touchesShouldCancelInContentView:方法询问是否取消已经传递给子视图的事件

// 返回是否用户已经触碰了内容视图准备进行滑动(注: 该值被设置为YES的时候可能用户只是触碰了内容视图,但是并没有开始进行滑动)
@property(nonatomic,readonly,getter=isTracking) BOOL tracking;

// 返回是否用户已经开始滑动内容视图(注: 该值被设置为YES之前可能需要先滑动一段时间或距离)
@property(nonatomic,readonly,getter=isDragging) BOOL dragging;

// 返回是否处于减速状态(即手指已经离开屏幕,但scrollView仍然处于滑动中)
@property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating;

// 是否延迟事件传递,默认为YES,如果设置为NO,scrollView会立即调用-touchesShouldBegin:withEvent:inContentView:方法以进行下一步操作
@property(nonatomic) BOOL delaysContentTouches;

// 是否可以取消内容视图被触摸,默认为YES,如果设置为NO,则一旦开始跟踪事件,即使手指进行移动也不会取消已经传递给子视图的事件
@property(nonatomic) BOOL canCancelContentTouches;

// 在UIScrollView的子类中重写该方法,用于返回是否将事件传递给对应的子视图,默认返回YES,如果返回NO,该事件不会传递给对应的子视图
- (BOOL)touchesShouldBegin:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view;

// 在UIScrollView的子类中重写该方法,用于返回是否取消已经传递给子视图的事件,默认当子视图是UIControl时返回NO,否则返回YES(注: 该方法被调用的前提是canCancelContentTouches = YES)
- (BOOL)touchesShouldCancelInContentView:(UIView *)view;

缩放相关

当用户使用两个手指进行缩放操作时,我们调整内容视图的偏移量和缩放比例(注: 用户两个手指操作结束后,有可能仍然有一个手指在操作,这时不会将事件传递给子视图)

// 最小缩放比例,默认为1.0
@property(nonatomic) CGFloat minimumZoomScale;

// 最大缩放比例,默认为1.0(必须大于minimumZoomScale才能正常工作)
@property(nonatomic) CGFloat maximumZoomScale;

// 缩放比例,默认为1.0
@property(nonatomic) CGFloat zoomScale;

// 设置缩放比例
- (void)setZoomScale:(CGFloat)scale animated:(BOOL)animated;

// 缩放到指定区域
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated;

// 是否允许触底反弹,默认为YES
@property(nonatomic) BOOL bouncesZoom;

// 返回是否正在缩放
@property(nonatomic,readonly,getter=isZooming) BOOL zooming;

// 返回是否正在触底反弹
@property(nonatomic,readonly,getter=isZoomBouncing) BOOL zoomBouncing;

键盘相关

// 隐藏键盘模式,默认为UIScrollViewKeyboardDismissModeNone(不隐藏键盘),其余可选项为UIScrollViewKeyboardDismissModeOnDrag(当拖拽scrollView时隐藏键盘)和UIScrollViewKeyboardDismissModeInteractive(当拖拽键盘上方时隐藏键盘)
@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode;

代理

滑动相关

// 当scrollView的contentOffset发生变化时调用
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;

// 将要开始拖拽时调用(注: 该方法可能需要先滑动一段时间或距离才会被调用)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;

// 当用户停止拖拽时调用(注: 应用程序可以通过修改targetContentOffset参数的值来调整内容视图content view停止的位置)
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset;

// 当用户停止拖拽时调用(注: 如果内容视图content view在停止拖拽后继续移动,则decelerate参数为YES)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;

// 将要开始减速时调用(仅当停止拖拽后继续移动时才会被调用)
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;

// 已经结束减速时调用(仅当停止拖拽后继续移动时才会被调用)
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

// 返回是否允许点击状态栏让scrollView滑动到顶部,如果未实现该方法,则默认为YES(仅当scrollsToTop属性为YES时才调用)
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;

// 当scrollView已经滑动到顶部时调用(仅当点击状态栏让scrollView滑动到顶部才调用)
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;

// 当-setContentOffset:animated:/-scrollRectVisible:animated:方法动画结束时调用(仅当animated设置为YES时才调用)
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;

缩放相关

// 当缩放比例更改时调用
- (void)scrollViewDidZoom:(UIScrollView *)scrollView;

// 参与缩放的子视图
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;

// 将要开始缩放时调用
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view;

// 已经结束缩放时调用
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale;

常见需求原理解析

导航栏半透明效果

原理解析:

默认情况下,在有UINavigationBar存在时,系统为了防止UIScrollView被遮挡,其contentInset和scrollIndicatorInsets属性都会被设置为UIEdgeInsetsMake(64, 0, 0, 0);在有UITabBar存在时,系统为了防止UIScrollView被遮挡,其contentInset和scrollIndicatorInsets属性都会被设置为UIEdgeInsetsMake(0, 0, 49, 0)

因此,为了使用此种半透明效果,可以直接将UIScrollView的frame设置为整个屏幕的大小

注1: 系统只在UIScrollView是控制器视图的第0个子视图时才会自动修改contentInset和scrollIndicatorInsets属性

注2: 如果不想让系统自动修改contentInset和scrollIndicatorInsets属性,可以设置self.automaticallyAdjustsScrollViewInsets = NO;

控件悬停

原理解析:

方式一: 在悬停位置放置一个与待悬停控件相同的控件,通过-scrollViewDidScroll:代理方法跟踪contentOffset的的变化,当不满足悬停条件时,将该控件hidden属性设置为YES;当满足悬停条件时,将该控件hidden属性设置为NO

方式二: 通过-scrollViewDidScroll:代理方法跟踪contentOffset的的变化,当不满足悬停条件时,待悬停控件属于UIScrollView的子视图,当满足悬停条件时,待悬停控件属于UIScrollView的父视图的子视图

// 以"方式二"为例
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
 if (scrollView.contentOffset.y >= 100)
 {
  CGRect rect = label.frame;
  rect.origin.y = 0;
  label.frame = rect;

  [self.view addSubview:label];
 }
 else
 {
  CGRect rect = label.frame;
  rect.origin.y = 100;
  label.frame = rect;

  [scrollView addSubview:label];
 }
}

下拉头部图片放大

原理解析:

通过-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);
}

图片无限轮播

原理解析:

在已知图片数组有N个元素前提下,在UIScrollView中创建N+2个UIImageView,其中第1个至第N个图片为真实内容,第0个与第N个一样,第N+1个与第1个一样,通过-scrollViewDidScroll:代理方法跟踪contentOffset的的变化,在滑动到首尾两个图片处直接设置contentOffset到真实图片处即可

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位iOS开发者们能有所帮助,如果有疑问大家可以留言交流。

(0)

相关推荐

  • iOS应用开发中UIScrollView滚动视图的基本用法总结

    在项目开发时遇到一个问题,我在UIViewController上面直接创建了一个UIScrollerView,把UIScrollerView作为一个子视图添加到了UIViewController, 又再UIScrollerView中添加了一个UISlider的组件,在手势滑动的过程中,很难滑动到UISlider这个控件,经常是滑动的时候UIScrollerView进行了滚动, 而UISlider这个控件没有滑动,让人很抓狂. 上网具体去了解了一下UIScrollerView的详解,终于彻底明白了

  • iOS开发中使用UIScrollView实现图片轮播和点击加载

    UIScrollView控件实现图片轮播 一.实现效果 实现图片的自动轮播 二.实现代码 storyboard中布局 代码: 复制代码 代码如下: #import "YYViewController.h" @interface YYViewController () <UIScrollViewDelegate> @property (weak, nonatomic) IBOutlet UIScrollView *scrollview; /**  *  页码  */ @pro

  • iOS开发中使用UIScrollView实现无限循环的图片浏览器

    一.概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授人以渔,这里会尽可能让大家明白其中的原理,找一些典型的控件进行说明,这样一来大家就可以触类旁通.今天我们主要来看一下UIScrollView的内容: UIView UIScrollView 实战--图片浏览器 二.UIView 在熟悉UIScrollView之前很有必要说一下UIView的内容.

  • iOS利用UIScrollView实现无限滚动效果

    前言 众所周知UIScrollView 的无限滚动主要应用在图片轮播器.欢迎界面等场景.它的原理是在要显示的图片前后各加一张图片即在第一张图片之前放最后一张图片,在最后一张图片之后放第一张图片,然后在滚动到边缘的时候,巧妙的过渡一下就可以"瞒天过海","以假乱真"的造成无限滚动的假象.网络上有很多只用三张或两张图片实现的方法,效率比这个方法高,但实现起来稍微麻烦一点,有兴趣的可以去深入研究. 实现步骤 1.根据需求准备几张图片,在网上找了5张图片,分别命名为 img

  • iOS开发之UIScrollView详解

    介绍:UIScrollView用于在一个小范围里显示很大的内容的控件.通过用户平滑.手捏手势,在这个小区域里查看不同内容.是UITableView和UITextView的父类.它是视图,但是比较特殊,可以看成把它看成2层的结构.上面是它的frame层,跟一般试图一样,是它的可见区域,下面层是contentView,可以滑动. 父类UIView方法 复制代码 代码如下: // autoresizingMask - 现在基本弃用,改用autoLayout typedef NS_OPTIONS(NSU

  • iOS应用开发中使用UIScrollView控件来实现图片缩放

    一.知识点简单介绍 1.UIScrollView控件是什么? (1)移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限 (2)当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容 (3)普通的UIView不具备滚动功能,不能显⽰示过多的内容 (4)UIScrollView是一个能够滚动的视图控件,可以⽤用来展⽰示⼤大量的内容,并且可以通过滚 动查看所有的内容 (5)  举例:手机上的"设置".其他⽰示例程序 2.UIScrollV

  • iOS UIScrollView滚动视图/无限循环滚动/自动滚动的实例代码

    我们都知道UIScrollView有一种很流畅的切换效果,结合UIPageControl的辅助展示效果,就可以完成一个很不错的产品介绍功能页面.下面给大家分享iOS UIScrollView滚动视图/无限循环滚动/自动滚动功能,具体代码如下所示: <UIScrollViewDelegate> #define WIDTH [[UIScreen mainScreen] bounds].size.width #define HEIGHT [[UIScreen mainScreen] bounds].

  • iOS基于UIScrollView实现滑动引导页

    上代码前,我们先来看下实现的效果图: WelcomeViewController.h #import <UIKit/UIKit.h> @interface WelcomeViewController : UIViewController @end WelcomeViewController.m #import "WelcomeViewController.h" #define IMAGECOUNT 3 @interface WelcomeViewController ()

  • iOS自定义UIScrollView的滚动条实例代码

    UIScrollView有自己默认的滚动条,可设置隐藏和显示,但是有时候这个默认的滚动条没办法满足我们的需求,那这时候只能通过自定义来实现了. 实现自定义滚动条需要解决的主要问题是: 在scrollview滚动的过程中如何改变滚动条的位置,进而确保滚动条和scrollView在相同时间内走完自己的位移,只要把这个问题解决好了,那我们就可以优雅的自定义滚动条了. 那如何解决这个滚动条的当前滚动位移呢?我们知道,UIScrollView有一个滚动范围,滚动条也有一个滚动范围,也就是说两者的最大的滚动

  • 通过UIKit坐标系来全面掌握iOS中的UIScrollView组件

    感谢UIKit的坐标系统特性,使我们之花了30几行代码就能重现UIScrollView的精华,当然真正的UIScrollView要比我们所做的复杂的多,反弹效果,动量滚动,放大试图,还有代理方法,这些特性我们没有在这里涉及到. 首先,让我们先来了解一下UIKit中的坐标系是怎么工作的.如果你只对滚动试图的代码实现感兴趣可以放心跳过下一小节.UIKit坐标系每一个View都定义了他自己的坐标系统.如下图所示,x轴指向右方,y轴指向下方: 注意这个逻辑坐标系并不关注包含在其中View的宽度和高度.整

随机推荐