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

如何让UIRefreshControl自定义子视图透明度与标题同步?

解决UIRefreshControl自定义子视图透明度随下拉距离变化的问题

要让自定义子视图的透明度和系统标题保持一致,有两种可靠的实现方式:

方式一:监听滚动视图偏移量计算进度

通过监听所属UIScrollView的contentOffset变化,手动计算下拉进度,同步自定义视图的透明度,逻辑和系统标题完全一致:

class CustomRefreshControl: UIRefreshControl {
    private let customView = MyCustomView()
    
    override init() {
        super.init()
        setupCustomView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupCustomView() {
        addSubview(customView)
        customView.translatesAutoresizingMaskIntoConstraints = false
        // 根据需求调整约束,示例为居中布局
        NSLayoutConstraint.activate([
            customView.centerYAnchor.constraint(equalTo: centerYAnchor),
            customView.centerXAnchor.constraint(equalTo: centerXAnchor),
            customView.widthAnchor.constraint(equalToConstant: 40),
            customView.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
    
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        // 监听滚动视图偏移量
        guard let scrollView = superview as? UIScrollView else { return }
        scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset), options: .new, context: nil)
    }
    
    override func willMoveFromSuperview(_ newSuperview: UIView?) {
        super.willMoveFromSuperview(newSuperview)
        // 移除监听避免内存泄漏
        guard let scrollView = superview as? UIScrollView else { return }
        scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset))
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard keyPath == #keyPath(UIScrollView.contentOffset), let scrollView = object as? UIScrollView else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
        
        // 计算下拉进度:下拉距离/刷新控件高度,最大为1
        let pullDistance = max(-scrollView.contentOffset.y, 0)
        let refreshHeight = frame.height
        let progress = min(pullDistance / refreshHeight, 1.0)
        customView.alpha = progress
    }
}

方式二:同步系统标题的透明度

在layoutSubviews中直接获取系统标题标签的透明度,同步给自定义视图,无需手动计算进度,完全跟随系统逻辑:

class CustomRefreshControl: UIRefreshControl {
    private let customView = MyCustomView()
    
    override init() {
        super.init()
        setupCustomView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupCustomView() {
        addSubview(customView)
        customView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            customView.centerYAnchor.constraint(equalTo: centerYAnchor),
            customView.centerXAnchor.constraint(equalTo: centerXAnchor),
            customView.widthAnchor.constraint(equalToConstant: 40),
            customView.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // 找到系统标题标签,同步其透明度
        if let titleLabel = subviews.first(where: { $0 is UILabel }) as? UILabel {
            customView.alpha = titleLabel.alpha
        }
    }
}

注意事项

  • 必须给自定义视图添加正确的Auto Layout约束,确保布局符合需求;
  • 方式一中要记得在控件移除时移除KVO监听,避免内存泄漏;
  • 方式二依赖系统标题的视图结构,目前iOS 13及以上版本均稳定可用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:17:42