如何让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
相关产品推荐
相关产品推荐

