惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyberwarzone
Cyberwarzone
V
Vulnerabilities – Threatpost
T
Tenable Blog
Forbes - Security
Forbes - Security
Simon Willison's Weblog
Simon Willison's Weblog
AWS News Blog
AWS News Blog
G
GRAHAM CLULEY
Know Your Adversary
Know Your Adversary
S
Securelist
C
Cybersecurity and Infrastructure Security Agency CISA
Project Zero
Project Zero
C
CXSECURITY Database RSS Feed - CXSecurity.com
V
Visual Studio Blog
WordPress大学
WordPress大学
Latest news
Latest news
K
Kaspersky official blog
T
Tailwind CSS Blog
T
Threat Research - Cisco Blogs
B
Blog RSS Feed
C
Cisco Blogs
博客园 - 聂微东
Martin Fowler
Martin Fowler
T
The Blog of Author Tim Ferriss
小众软件
小众软件
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
L
LINUX DO - 热门话题
Stack Overflow Blog
Stack Overflow Blog
罗磊的独立博客
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Privacy International News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
S
SegmentFault 最新的问题
Security Latest
Security Latest
Y
Y Combinator Blog
爱范儿
爱范儿
aimingoo的专栏
aimingoo的专栏
P
Privacy & Cybersecurity Law Blog
L
LINUX DO - 最新话题
月光博客
月光博客
The GitHub Blog
The GitHub Blog
博客园 - 三生石上(FineUI控件)
S
Security Affairs
P
Proofpoint News Feed
D
DataBreaches.Net
有赞技术团队
有赞技术团队
云风的 BLOG
云风的 BLOG

博客园 - chaoguo1234

Plist 二进制格式 UIImageView 设置图片不生效的原因排查 Any metadata 的内存布局 Mach-O 文件结构 Block Copy 的内存布局详解 __block 变量内存布局详解 Block 内存布局详解 XNU Inside: iOS 模拟器 WebKit Insie: WebKit 调试(二) NSMutableDictionary 的内存布局 NSDictionary 内存布局 WebKit Inside: GPU 进程调试 WebKit Inside: 渲染树 WebKit Inside: px 与 pt WebKit Inside: CSS 的匹配原理 dyld: 神秘的 __dso_handle 一文搞懂 ARM 64 系列: ADD(立即数版) 一文搞懂 ARM 64: AUTIBSP 一文搞懂 ARM 64 系列: PACISB XCode 编译 PAG 源码 一文搞懂 ARM 64 系列: 一文搞懂 ARM 64 系列: 函数调用传参与返回值 一文搞懂 ARM 64 系列: 寄存器
如何自定义 UIScrollView 的减速系数
chaoguo1234 · 2026-07-15 · via 博客园 - chaoguo1234

decelerationRate属性用来定义用户滑动UIScrollView,手指离开UIScrollView后,UIScrollView减速所受到的阻力。

decelerationRate是一个浮点数类型,系统提供了预先定义的两个值:

  • UIScrollViewDecelerationRateNormal
  • UIScrollViewDecelerationRateFast

其中UIScrollViewDecelerationRateNormal是默认值。

1 Normal 和 Fast 的值

UIScrollViewDecelerationRateNormalUIScrollViewDecelerationRateFast的值,打印如下:

# UIScrollViewDecelerationRateNormal
(lldb) po @import UIKit
(lldb) p (UIScrollViewDecelerationRate)UIScrollViewDecelerationRateNormal
(UIScrollViewDecelerationRate) 0.998

# UIScrollViewDecelerationRateFast
(lldb) p (UIScrollViewDecelerationRate)UIScrollViewDecelerationRateFast
(UIScrollViewDecelerationRate) 0.98999999999999999

decelerationRate的数值越小,减速越快。

UIScrollViewDecelerationRateFast就是浮点数0.99

由于计算机对浮点数表示精度问题,显示为0.98999999999999999

2 decelerationRate setter 的实现

decelerationRate的设置函数代码比较短,直接贴出来:

UIKitCore`-[UIScrollView setDecelerationRate:]:
->  0x1a2a4998c <+0>:  adrp   x8, 5091
    // 1. 读取阈值到 d1
    0x1a2a49990 <+4>:  ldr    d1, [x8, #0x558]
    // 2. 将要设置的值与阈值比较
    0x1a2a49994 <+8>:  fcmp   d0, d1
    // 3. 如果要设置的值 < 阈值,w8 置为 1,否则,w8 置为 0
    0x1a2a49998 <+12>: cset   w8, lt
    0x1a2a4999c <+16>: adrp   x9, 5091
    // 4. x9 存储 UIScrollViewDecelerationRateNormal 和 UIScrollViewDecelerationRateFast 组成的数组首地址
    0x1a2a499a0 <+20>: add    x9, x9, #0x5a0            ; UIScrollTestParametersLengthAutomatic + 128
    // 5. 将 UIScrollViewDecelerationRateNormal 或者 UIScrollViewDecelerationRateFast 读取到 d0
    0x1a2a499a4 <+24>: ldr    d0, [x9, w8, uxtw #3]
    0x1a2a499a8 <+28>: adrp   x8, 416465
    0x1a2a499ac <+32>: ldrsw  x8, [x8, #0xf9c]
    0x1a2a499b0 <+36>: add    x8, x0, x8
    // 6. 存储 decelerationRate 到 UIScrollView 对象
    0x1a2a499b4 <+40>: stp    d0, d0, [x8]
    0x1a2a499b8 <+44>: ret 

注释1,读取阈值到寄存器d1

代码后面会将要设置的值与阈值比较。

打印阈值为:

(lldb) p $d1
(double) 0.99399999999999999

可以看到,阈值就是0.994

这个阈值,正好是UIScrollViewDecelerationRateNormalUIScrollViewDecelerationRateFast的中间值。

同样由于计算机浮点数精度问题,表示为0.99399999999999999

注释2,注释3,将要设置的值与阈值进行比较。

如果要设置的值比阈值小,那么寄存器w8被置为1,否则,w8被置为0

寄存器w8的值,后面会看到成为数组索引。

注释4,将UIScrollViewDecelerationRateNormalUIScrollViewDecelerationRateFast组成的数组首地址,读入寄存器x9

可以打印这个数组的内容:

(lldb) x/2fg $x9
0x1a3e2c5a0: 0.998
0x1a3e2c5a8: 0.98999999999999999

从打印内容可以看到,数组第一项,是UIScrollViewDecelerationRateNormal,数组第二项是UIScrollViewDecelerationRateFast

注释5,根据寄存器w8做索引,读入相应的值到寄存器d0

如果要设置的值比阈值大,那么就读入UIScrollViewDecelerationRateNormal,否则,读入UIScrollViewDecelerationRateFast

注释6,将最终的值存入到UIScrollView对象中。

存储decelerationRate的实例变量相对于UIScrollView首地址偏移量存储在寄存器x8,打印为:

(lldb) p/x $x8
(unsigned long) 0x0000000000000358

通过_ivarDescription方法打印UIScrollView的所有实例变量,经过尝试,可以发现,偏移量0x358处的实例变量为_decelerationFactor:

(lldb) po class_getInstanceVariable(UIScrollView.class, "_decelerationFactor")
0x000000020a6adbd8
(lldb) po ivar_getOffset(0x000000020a6adbd8)
0x0000000000000358

_decelerationFactor是一个结构体,存储这水平和垂直减速比例值:

_decelerationFactor (struct CGSize): {0.998, 0.998}

总结一下,如果设置UIScrollViewdecelerationRate属性,系统会将设置的值与阈值0.994进行比较:

如果设置的值大于阈值,那么系统会选择UIScrollViewDecelerationRateNormal;

如果设置的值小于阈值,那么系统会选择UIScrollViewDecelerationRateFast

也就是说,无论外界设置何种值,系统只会在UIScrollViewDecelerationRateNormalUIScrollViewDecelerationRateFast中进行选择。

3 decelerationRate getter 的实现

decelerationRategetter方法也很短,代码如下:

UIKitCore`-[UIScrollView decelerationRate]:
    0x1a3ba2354 <+0>:  adrp   x8, 412024
    0x1a3ba2358 <+4>:  ldrsw  x8, [x8, #0xf9c]
    // 1. 读取 _decelerationFactor 的水平值
->  0x1a3ba235c <+8>:  ldr    d0, [x0, x8]
    0x1a3ba2360 <+12>: ret  

注释1,寄存器x8存储这_decelerationFactor结构体相对于UIScrollView首地址的偏移量:

(lldb) p/x $x8
(unsigned long) 0x0000000000000358

这里将_decelerationFactor的水平值读取出来,作为结果返回。

4 _decelerationFactor 结构体

如果我们直接设置UIScrollViewdecelerationRate属性,系统始终会把设置的值调整为预定义的UIScrollViewDecelerationRateNormal或者UIScrollViewDecelerationRateFast

那么,我们能否直接设置_decelerationFactor结构体,从而使用不同的减速系数呢?

通过调用_methodDescription查看UIScrollView的所有方法,可以找到如下2个私有方法:

- (void) setHorizontalScrollDecelerationFactor:(double)arg1; (0x138bd7d00)
- (void) setVerticalScrollDecelerationFactor:(double)arg1; (0x138bd7d70)

这两个方法,这是设置_decelerationFactor结构体的水平值和垂直值。

我们先看setHorizontalScrollDecelerationFactor:方法的实现,垂直方法的实现类似:

UIKitCore`-[UIScrollView setHorizontalScrollDecelerationFactor:]:
->  0x1a3ba2378 <+0>:  adrp   x8, 412024
    0x1a3ba237c <+4>:  ldrsw  x8, [x8, #0xf9c]
    // 1. 将设置的值直接存入到 _decelerationFactor 结构体的水平分量
    0x1a3ba2380 <+8>:  str    d0, [x0, x8]
    0x1a3ba2384 <+12>: ret  

注释1,将设置的值直接存入到_decelerationFactor结构体的水平分量。

因此,通过上面两个私有方法,就可以设置decelerationRate的值为[0, 1)直接的值。

注意,不能通过上面2个私有方法,将decelerationRate的值设置为1.0,否则滚动时会发生崩溃。

比如如果我们调用setVerticalScrollDecelerationFactor:方法,将垂直减速系数设置为0.999999,那么就会发现拖动UIScrollView之后的减速非常缓慢。

ScreenRecording_07-14-2026 22-49-39_1

这里需要注意,如果设置了_decelerationFactor的垂直分量,最好一起设置水平分量,因为decelerationRategetter方法,只返回水平分量的值。