鍾彬 發表於 2020-6-28 09:43:00

iOS开发之UIScrollView控件详解

<div class="summary">UIScrollView是一个非常重要的控件,其可以展示比设备屏幕更大区域的内容,我们可以通过手指滑动来查看内容视图的每一部分内容,也可以通过手指捏合来对内容视图进行缩放操作,我们每天开发中都不断显式或隐式地与UIScrollView打交道,下面给大家详细介绍UIScrollView控件。</div>
<div class="lbd clearfix">&nbsp;</div>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>一、UIScrollView控件是什么?</strong></span></p>
<p>&nbsp;&nbsp;&nbsp; (1)移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限</p>
<p>&nbsp;&nbsp;&nbsp; (2)当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;(3)普通的UIView不具备滚动功能,不能显⽰示过多的内容</p>
<p>&nbsp;&nbsp;&nbsp; (4)UIScrollView是一个能够滚动的视图控件,可以⽤用来展⽰示⼤大量的内容,并且可以通过滚 动查看所有的内容</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;(5)&nbsp; 举例:手机上的“设置”、其他⽰示例程序</p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>二、UIScrollView的简单使用</strong></span></p>
<p>(1)将需要展⽰的内容添加到UIScrollView中</p>
<p>(2)设置UIScrollView的contentSize属性,告诉UIScrollView所有内容的尺⼨寸,也就是告诉 它滚动的范围(能滚多远,滚到哪⾥里是尽头)</p>
<p><span style="color: rgba(128, 0, 0, 1)"><strong>注: 本文中所说的"内容视图"在官方文档中称作"content view",表示UIScrollView中可以用来展示内容的部分</strong><br>
</span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>三、属性与方法</strong><br>
</span></p>
<p><strong>内容视图相关</strong><br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_820358" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 内容视图的大小,默认为CGSizeZero</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">@property(nonatomic) CGSize contentSize;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 为内容视图周围增加可滚动区域,默认为UIEdgeInsetsZero</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">@property(nonatomic) UIEdgeInsets contentInset;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 内容视图的原点相对于scrollView的原点的偏移量(左上方向偏移为正数),默认为CGPointZero</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">@property(nonatomic) CGPoint contentOffset;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp comments">// 设置内容视图的原点相对于scrollView的原点的偏移量</code></div>
<div class="line number11 index10 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)setContentOffset:(CGPoint)contentOffset animated:(</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)animated;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>滑动相关</strong><br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_104847" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>
<div class="line number24 index23 alt1">24</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 是否允许滑动,默认为YES</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">@property(nonatomic,getter=isScrollEnabled) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">scrollEnabled;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 是否只允许同时滑动一个方向,默认为NO,如果设置为YES,用户在水平/竖直方向开始进行滑动,便禁止同时在竖直/水平方向滑动(注: 当用户在对角线方向开始进行滑动,则本次滑动可以同时在任何方向滑动)</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">@property(nonatomic, getter=isDirectionalLockEnabled) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">directionalLockEnabled;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 是否允许点击状态栏让距离状态栏最近的scrollView滑动到顶部,默认为YES(注: 在iPhone中如果有多个将该属性设置为YES的scrollView,则该方法无效;在iPad中则将距离状态栏最近的scrollView滑动到顶部)</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">scrollsToTop;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp comments">// 是否按页数进行滑动,默认为NO,如果设置为YES,则在滑动时只会停止在scrollView的bounds的倍数处</code></div>
<div class="line number11 index10 alt2"><code class="cpp plain">@property(nonatomic, getter=isPagingEnabled) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">pagingEnabled;</code></div>
<div class="line number12 index11 alt1">&nbsp;</div>
<div class="line number13 index12 alt2"><code class="cpp comments">// 是否有触底反弹效果,默认为YES</code></div>
<div class="line number14 index13 alt1"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">bounces;</code></div>
<div class="line number15 index14 alt2">&nbsp;</div>
<div class="line number16 index15 alt1"><code class="cpp comments">// 是否总是有触底反弹效果(即使内容视图小于scrollView的大小),默认为NO(注: 生效的前提条件为bounces = YES)</code></div>
<div class="line number17 index16 alt2"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">alwaysBounceHorizontal;</code></div>
<div class="line number18 index17 alt1"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">alwaysBounceVertical;</code></div>
<div class="line number19 index18 alt2">&nbsp;</div>
<div class="line number20 index19 alt1"><code class="cpp comments">// 指定用户手指离开屏幕后滑动减速的比率,默认为UIScrollViewDecelerationRateNormal(慢慢停止),其余可选项为UIScrollViewDecelerationRateFast(快速停止)</code></div>
<div class="line number21 index20 alt2"><code class="cpp plain">@property(nonatomic) CGFloat decelerationRate;</code></div>
<div class="line number22 index21 alt1">&nbsp;</div>
<div class="line number23 index22 alt2"><code class="cpp comments">// 将指定区域滑动到刚好可见处(即距离边缘最近处)</code></div>
<div class="line number24 index23 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollRectToVisible:(CGRect)rect animated:(</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)animated;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>指示器相关</strong><br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_568145" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 指示器样式,默认为UIScrollViewIndicatorStyleDefault(黑内容白边框,适用于任何背景),其余可选项为UIScrollViewIndicatorStyleBlack(全黑)和UIScrollViewIndicatorStyleWhite(全白)</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">@property(nonatomic) UIScrollViewIndicatorStyle indicatorStyle;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 为指示器周围增加可滚动区域,默认为UIEdgeInsetsZero</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">@property(nonatomic) UIEdgeInsets scrollIndicatorInsets;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 是否在滑动时指示器可见,默认为YES</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">showsHorizontalScrollIndicator;</code></div>
<div class="line number9 index8 alt2"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">showsVerticalScrollIndicator;</code></div>
<div class="line number10 index9 alt1">&nbsp;</div>
<div class="line number11 index10 alt2"><code class="cpp comments">// 闪一下指示器(注: 建议在scrollView展示给用户时调用一下,以提醒用户该处可滑动)</code></div>
<div class="line number12 index11 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)flashScrollIndicators;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>事件相关</strong><br>
</p>
<p>UIScrollView处理触摸事件原理</p>
<p>当用户在UIScrollView的一个子视图上按下时,UIScrollView并不知道用户是想要滑动内容视图还是点击对应子视图,所以在按下的一瞬间,事件UIEvent从UIApplication传递到UIScrollView后,其会先将该事件拦截而不会立即传递给对应的子视图,同时开始一个150ms的倒计时,并监听用户接下来的行为</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 1、当倒计时结束前,如果用户的手指发生了移动,则直接滚动内容视图,不会将该事件传递给对应的子视图;<br>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 2、当倒计时结束时,如果用户的手指位置没有改变,则调用自身的<code>-touchesShouldBegin:withEvent:inContentView:</code>方法询问是否将事件传递给对应的子视图(如果返回NO,则该事件不会传递给对应的子视图,如果返回YES,则该事件会传递给对应的子视图,默认为YES)<br>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 3、当事件被传递给子视图后,如果手指位置又发生了移动,则调用自身的<code>-touchesShouldCancelInContentView:</code>方法询问是否取消已经传递给子视图的事件<br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_327395" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 返回是否用户已经触碰了内容视图准备进行滑动(注: 该值被设置为YES的时候可能用户只是触碰了内容视图,但是并没有开始进行滑动)</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">@property(nonatomic,readonly,getter=isTracking) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">tracking;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 返回是否用户已经开始滑动内容视图(注: 该值被设置为YES之前可能需要先滑动一段时间或距离)</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">@property(nonatomic,readonly,getter=isDragging) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">dragging;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 返回是否处于减速状态(即手指已经离开屏幕,但scrollView仍然处于滑动中)</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">@property(nonatomic,readonly,getter=isDecelerating) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">decelerating;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp comments">// 是否延迟事件传递,默认为YES,如果设置为NO,scrollView会立即调用-touchesShouldBegin:withEvent:inContentView:方法以进行下一步操作</code></div>
<div class="line number11 index10 alt2"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">delaysContentTouches;</code></div>
<div class="line number12 index11 alt1">&nbsp;</div>
<div class="line number13 index12 alt2"><code class="cpp comments">// 是否可以取消内容视图被触摸,默认为YES,如果设置为NO,则一旦开始跟踪事件,即使手指进行移动也不会取消已经传递给子视图的事件</code></div>
<div class="line number14 index13 alt1"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">canCancelContentTouches;</code></div>
<div class="line number15 index14 alt2">&nbsp;</div>
<div class="line number16 index15 alt1"><code class="cpp comments">// 在UIScrollView的子类中重写该方法,用于返回是否将事件传递给对应的子视图,默认返回YES,如果返回NO,该事件不会传递给对应的子视图</code></div>
<div class="line number17 index16 alt2"><code class="cpp plain">- (</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)touchesShouldBegin:(NSSet&lt;UITouch *&gt; *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view;</code></div>
<div class="line number18 index17 alt1">&nbsp;</div>
<div class="line number19 index18 alt2"><code class="cpp comments">// 在UIScrollView的子类中重写该方法,用于返回是否取消已经传递给子视图的事件,默认当子视图是UIControl时返回NO,否则返回YES(注: 该方法被调用的前提是canCancelContentTouches = YES)</code></div>
<div class="line number20 index19 alt1"><code class="cpp plain">- (</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)touchesShouldCancelInContentView:(UIView *)view;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>缩放相关</strong><br>
</p>
<p>当用户使用两个手指进行缩放操作时,我们调整内容视图的偏移量和缩放比例(注: 用户两个手指操作结束后,有可能仍然有一个手指在操作,这时不会将事件传递给子视图)</p>
<div class="jb51code">
<div>
<div id="highlighter_154818" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 最小缩放比例,默认为1.0</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">@property(nonatomic) CGFloat minimumZoomScale;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 最大缩放比例,默认为1.0(必须大于minimumZoomScale才能正常工作)</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">@property(nonatomic) CGFloat maximumZoomScale;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 缩放比例,默认为1.0</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">@property(nonatomic) CGFloat zoomScale;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp comments">// 设置缩放比例</code></div>
<div class="line number11 index10 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)setZoomScale:(CGFloat)scale animated:(</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)animated;</code></div>
<div class="line number12 index11 alt1">&nbsp;</div>
<div class="line number13 index12 alt2"><code class="cpp comments">// 缩放到指定区域</code></div>
<div class="line number14 index13 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)zoomToRect:(CGRect)rect animated:(</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)animated;</code></div>
<div class="line number15 index14 alt2">&nbsp;</div>
<div class="line number16 index15 alt1"><code class="cpp comments">// 是否允许触底反弹,默认为YES</code></div>
<div class="line number17 index16 alt2"><code class="cpp plain">@property(nonatomic) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">bouncesZoom;</code></div>
<div class="line number18 index17 alt1">&nbsp;</div>
<div class="line number19 index18 alt2"><code class="cpp comments">// 返回是否正在缩放</code></div>
<div class="line number20 index19 alt1"><code class="cpp plain">@property(nonatomic,readonly,getter=isZooming) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">zooming;</code></div>
<div class="line number21 index20 alt2">&nbsp;</div>
<div class="line number22 index21 alt1"><code class="cpp comments">// 返回是否正在触底反弹</code></div>
<div class="line number23 index22 alt2"><code class="cpp plain">@property(nonatomic,readonly,getter=isZoomBouncing) </code><code class="cpp color1 bold">BOOL</code> <code class="cpp plain">zoomBouncing;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>键盘相关</strong><br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_370058" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 隐藏键盘模式,默认为UIScrollViewKeyboardDismissModeNone(不隐藏键盘),其余可选项为UIScrollViewKeyboardDismissModeOnDrag(当拖拽scrollView时隐藏键盘)和UIScrollViewKeyboardDismissModeInteractive(当拖拽键盘上方时隐藏键盘)</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><span style="color: rgba(51, 102, 255, 1)"><strong>代理<br>
</strong></span></p>
<p><strong>滑动相关</strong><br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_726377" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>
<div class="line number24 index23 alt1">24</div>
<div class="line number25 index24 alt2">25</div>
<div class="line number26 index25 alt1">26</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 当scrollView的contentOffset发生变化时调用</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidScroll:(UIScrollView *)scrollView;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 将要开始拖拽时调用(注: 该方法可能需要先滑动一段时间或距离才会被调用)</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewWillBeginDragging:(UIScrollView *)scrollView;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 当用户停止拖拽时调用(注: 应用程序可以通过修改targetContentOffset参数的值来调整内容视图content view停止的位置)</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp comments">// 当用户停止拖拽时调用(注: 如果内容视图content view在停止拖拽后继续移动,则decelerate参数为YES)</code></div>
<div class="line number11 index10 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)decelerate;</code></div>
<div class="line number12 index11 alt1">&nbsp;</div>
<div class="line number13 index12 alt2"><code class="cpp comments">// 将要开始减速时调用(仅当停止拖拽后继续移动时才会被调用)</code></div>
<div class="line number14 index13 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;</code></div>
<div class="line number15 index14 alt2">&nbsp;</div>
<div class="line number16 index15 alt1"><code class="cpp comments">// 已经结束减速时调用(仅当停止拖拽后继续移动时才会被调用)</code></div>
<div class="line number17 index16 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;</code></div>
<div class="line number18 index17 alt1">&nbsp;</div>
<div class="line number19 index18 alt2"><code class="cpp comments">// 返回是否允许点击状态栏让scrollView滑动到顶部,如果未实现该方法,则默认为YES(仅当scrollsToTop属性为YES时才调用)</code></div>
<div class="line number20 index19 alt1"><code class="cpp plain">- (</code><code class="cpp color1 bold">BOOL</code><code class="cpp plain">)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;</code></div>
<div class="line number21 index20 alt2">&nbsp;</div>
<div class="line number22 index21 alt1"><code class="cpp comments">// 当scrollView已经滑动到顶部时调用(仅当点击状态栏让scrollView滑动到顶部才调用)</code></div>
<div class="line number23 index22 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidScrollToTop:(UIScrollView *)scrollView;</code></div>
<div class="line number24 index23 alt1">&nbsp;</div>
<div class="line number25 index24 alt2"><code class="cpp comments">// 当-setContentOffset:animated:/-scrollRectVisible:animated:方法动画结束时调用(仅当animated设置为YES时才调用)</code></div>
<div class="line number26 index25 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>缩放相关</strong><br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_36520" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 当缩放比例更改时调用</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidZoom:(UIScrollView *)scrollView;</code></div>
<div class="line number3 index2 alt2">&nbsp;</div>
<div class="line number4 index3 alt1"><code class="cpp comments">// 参与缩放的子视图</code></div>
<div class="line number5 index4 alt2"><code class="cpp plain">- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;</code></div>
<div class="line number6 index5 alt1">&nbsp;</div>
<div class="line number7 index6 alt2"><code class="cpp comments">// 将要开始缩放时调用</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp comments">// 已经结束缩放时调用</code></div>
<div class="line number11 index10 alt2"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale;</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><strong>常见需求原理解析</strong><br>
</p>
<p><span style="color: rgba(51, 102, 255, 1)"><strong>导航栏半透明效果</strong></span></p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/556239/202006/556239-20200628094024993-1923726142.gif"><br>
</p>
<p><strong>原理解析:</strong></p>
<p>默认情况下,在有UINavigationBar存在时,系统为了防止UIScrollView被遮挡,其contentInset和scrollIndicatorInsets属性都会被设置为<code>UIEdgeInsetsMake(64, 0, 0, 0);</code>在有UITabBar存在时,系统为了防止UIScrollView被遮挡,其contentInset和scrollIndicatorInsets属性都会被设置为<code>UIEdgeInsetsMake(0, 0, 49, 0)</code></p>
<p>因此,为了使用此种半透明效果,可以直接将UIScrollView的frame设置为整个屏幕的大小</p>
<p>&nbsp;&nbsp;&nbsp; 注1: 系统只在UIScrollView是控制器视图的第0个子视图时才会自动修改contentInset和scrollIndicatorInsets属性</p>
<p>&nbsp;&nbsp;&nbsp; 注2: 如果不想让系统自动修改contentInset和scrollIndicatorInsets属性,可以设置<code>self.automaticallyAdjustsScrollViewInsets = NO;<br>
</code></p>
<p><strong><span style="color: rgba(51, 102, 255, 1)">控件悬停</span></strong></p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/556239/202006/556239-20200628094115888-753910020.gif"><br>
</p>
<p><strong>原理解析:</strong></p>
<p>&nbsp;&nbsp;&nbsp; 方式一: 在悬停位置放置一个与待悬停控件相同的控件,通过<code>-scrollViewDidScroll:</code>代理方法跟踪contentOffset的的变化,当不满足悬停条件时,将该控件hidden属性设置为YES;当满足悬停条件时,将该控件hidden属性设置为NO</p>
<p>&nbsp;&nbsp;&nbsp; 方式二: 通过<code>-scrollViewDidScroll:</code>代理方法跟踪contentOffset的的变化,当不满足悬停条件时,待悬停控件属于UIScrollView的子视图,当满足悬停条件时,待悬停控件属于UIScrollView的父视图的子视图</p>
<div class="jb51code">
<div>
<div id="highlighter_230797" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 以"方式二"为例</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidScroll:(UIScrollView *)scrollView</code></div>
<div class="line number3 index2 alt2"><code class="cpp plain">{</code></div>
<div class="line number4 index3 alt1"><code class="cpp spaces">&nbsp;</code><code class="cpp keyword bold">if</code> <code class="cpp plain">(scrollView.contentOffset.y &gt;= 100)</code></div>
<div class="line number5 index4 alt2"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">{</code></div>
<div class="line number6 index5 alt1"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">CGRect rect = label.frame;</code></div>
<div class="line number7 index6 alt2"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">rect.origin.y = 0;</code></div>
<div class="line number8 index7 alt1"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">label.frame = rect;</code></div>
<div class="line number9 index8 alt2">&nbsp;</div>
<div class="line number10 index9 alt1"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">;</code></div>
<div class="line number11 index10 alt2"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">}</code></div>
<div class="line number12 index11 alt1"><code class="cpp spaces">&nbsp;</code><code class="cpp keyword bold">else</code></div>
<div class="line number13 index12 alt2"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">{</code></div>
<div class="line number14 index13 alt1"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">CGRect rect = label.frame;</code></div>
<div class="line number15 index14 alt2"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">rect.origin.y = 100;</code></div>
<div class="line number16 index15 alt1"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">label.frame = rect;</code></div>
<div class="line number17 index16 alt2">&nbsp;</div>
<div class="line number18 index17 alt1"><code class="cpp spaces">&nbsp;&nbsp;</code><code class="cpp plain">;</code></div>
<div class="line number19 index18 alt2"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">}</code></div>
<div class="line number20 index19 alt1"><code class="cpp plain">}</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><span style="color: rgba(51, 102, 255, 1)"><strong>下拉头部图片放大</strong></span></p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/556239/202006/556239-20200628094148198-192548923.gif"><br>
</p>
<p><strong>原理解析:</strong></p>
<p>通过<code>-scrollViewDidScroll:</code>代理方法跟踪contentOffset的的变化,根据contentOffset动态设置图片的缩放比例<br>
</p>
<div class="jb51code">
<div>
<div id="highlighter_511610" class="syntaxhighlightercpp">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>

</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="cpp comments">// 以"动态修改图片缩放比例于1倍和2倍之间"为例</code></div>
<div class="line number2 index1 alt1"><code class="cpp plain">- (</code><code class="cpp keyword bold">void</code><code class="cpp plain">)scrollViewDidScroll:(UIScrollView *)scrollView</code></div>
<div class="line number3 index2 alt2"><code class="cpp plain">{</code></div>
<div class="line number4 index3 alt1"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">CGFloat scale = 1 - (scrollView.contentOffset.y / 100);</code></div>
<div class="line number5 index4 alt2"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">scale = (scale &gt;= 1) ? scale : 1;</code></div>
<div class="line number6 index5 alt1"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">scale = (scale &lt;= 2) ? scale : 2;</code></div>
<div class="line number7 index6 alt2"><code class="cpp spaces">&nbsp;</code><code class="cpp plain">imageView.transform = CGAffineTransformMakeScale(scale, scale);</code></div>
<div class="line number8 index7 alt1"><code class="cpp plain">}</code></div>

</div>

</td>

</tr>

</tbody>

</table>

</div>

</div>


</div>
<p><span style="color: rgba(51, 102, 255, 1)"><strong>图片无限轮播</strong></span></p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/556239/202006/556239-20200628094222786-864495255.gif"><br>
</p>
<p><strong>原理解析:</strong></p>
<p>在已知图片数组有N个元素前提下,在UIScrollView中创建N+2个UIImageView,其中第1个至第N个图片为真实内容,第0个与第N个一样,第N+1个与第1个一样,通过<code>-scrollViewDidScroll:</code>代理方法跟踪contentOffset的的变化,在滑动到首尾两个图片处直接设置contentOffset到真实图片处即可<br>
</p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/556239/202006/556239-20200628094256418-1595002785.jpg"></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>总结</strong></span></p>
<p>以上就是这篇文章的全部内容了,希望本文的内容对各位iOS开发者们能有所帮助,如果有疑问大家可以留言交流。</p><br><br>
来源:https://www.cnblogs.com/Free-Thinker/p/13201301.html
頁: [1]
查看完整版本: iOS开发之UIScrollView控件详解