You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swift中一次性禁用所有TableView/CollectionView的滚动指示器?

一次性禁用所有UITableView/UICollectionView滚动指示器的最简方案

如果项目里有几十上百个TableView、CollectionView,不想逐个设置showsHorizontalScrollIndicator和showsVerticalScrollIndicator,也不想改Storyboard,下面两种方法可以实现一处修改全局生效:

方法1:给UIScrollView写扩展,覆盖初始化逻辑

因为UITableView和UICollectionView都是UIScrollView的子类,直接给父类做扩展,所有子类都会自动继承这个设置:

extension UIScrollView {
    override open func awakeFromNib() {
        super.awakeFromNib()
        hideScrollIndicators()
    }
    
    override public init(frame: CGRect) {
        super.init(frame: frame)
        hideScrollIndicators()
    }
    
    required public init?(coder: NSCoder) {
        super.init(coder: coder)
        hideScrollIndicators()
    }
    
    private func hideScrollIndicators() {
        showsHorizontalScrollIndicator = false
        showsVerticalScrollIndicator = false
    }
}

不管是代码里创建的实例,还是从Storyboard/XIB加载的,初始化时都会自动执行hideScrollIndicators(),完全不用修改原有代码。

方法2:用Runtime方法交换(Method Swizzling)

如果不想重写初始化方法,可以用Swift的Runtime特性替换系统的初始化方法,注入隐藏指示器的逻辑:

import UIKit
import ObjectiveC

extension UIScrollView {
    static let swizzleScrollIndicators: Void = {
        // 交换frame初始化方法
        let originalFrameInit = #selector(UIScrollView.init(frame:))
        let swizzledFrameInit = #selector(UIScrollView.swizzled_frameInit(frame:))
        
        guard let originalMethod = class_getInstanceMethod(Self.self, originalFrameInit),
              let swizzledMethod = class_getInstanceMethod(Self.self, swizzledFrameInit) else {
            return
        }
        method_exchangeImplementations(originalMethod, swizzledMethod)
        
        // 交换coder初始化方法(处理XIB/Storyboard)
        let originalCoderInit = #selector(UIScrollView.init(coder:))
        let swizzledCoderInit = #selector(UIScrollView.swizzled_coderInit(coder:))
        
        guard let originalCoderMethod = class_getInstanceMethod(Self.self, originalCoderInit),
              let swizzledCoderMethod = class_getInstanceMethod(Self.self, swizzledCoderInit) else {
            return
        }
        method_exchangeImplementations(originalCoderMethod, swizzledCoderMethod)
    }()
    
    @objc private func swizzled_frameInit(frame: CGRect) {
        // 先调用原方法完成初始化
        self.swizzled_frameInit(frame: frame)
        hideScrollIndicators()
    }
    
    @objc private func swizzled_coderInit(coder: NSCoder) {
        guard self.swizzled_coderInit(coder: coder) != nil else { return }
        hideScrollIndicators()
    }
    
    private func hideScrollIndicators() {
        showsHorizontalScrollIndicator = false
        showsVerticalScrollIndicator = false
    }
}

// 在App启动时触发方法交换(只执行一次)
extension UIApplication {
    override open var next: UIResponder? {
        UIScrollView.swizzleScrollIndicators
        return super.next
    }
}

关于你问的几个问题

  1. Swift里的钩子函数:没有像JS那样的原型钩子,但可以通过重写awakeFromNib、初始化方法,或者用Runtime方法交换来实现“实例化时自动执行代码”的效果。
  2. 类似JS原型修改的方案:上面的方法交换就相当于修改了UIScrollView的“原型”逻辑,所有实例都会生效。性能损耗几乎可以忽略——只有第一次调用交换后的方法时会有极微小的开销,后续执行和原生方法效率完全一致。而方法1的扩展重写方式则完全没有额外性能损耗。

内容的提问来源于stack exchange,提问作者tanmoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 09:15:43