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

SwiftUI获取List滚动方向实现UIKit导航栏显隐(适配iOS13)

兼容iOS13的实现方案

实现思路

  • iOS13中SwiftUI的List底层本质是封装的UITableView(继承自UIScrollView),我们可以通过遍历视图层级拿到内部的UIScrollView实例
  • 采用代理转发的方式监听滚动事件,不会覆盖List原有代理实现,避免影响原生功能
  • 通过UIPanGestureRecognizer的位移判断滚动方向,完全对齐你原有UIKit的实现逻辑

完整实现代码

第一步:实现ScrollView捕获和代理转发工具

import SwiftUI
import UIKit

struct ScrollViewCapture: UIViewRepresentable {
    let onScrollViewFound: (UIScrollView) -> Void
    
    func makeUIView(context: Context) -> UIView {
        return UIView(frame: .zero)
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        DispatchQueue.main.async {
            var superview = uiView.superview
            while superview != nil {
                if let scrollView = superview as? UIScrollView {
                    onScrollViewFound(scrollView)
                    break
                }
                superview = superview?.superview
            }
        }
    }
}

class ScrollViewDelegateForwarder: NSObject, UIScrollViewDelegate {
    weak var originalDelegate: UIScrollViewDelegate?
    let onScroll: (UIScrollView) -> Void
    
    init(onScroll: @escaping (UIScrollView) -> Void) {
        self.onScroll = onScroll
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        originalDelegate?.scrollViewDidScroll?(scrollView)
        onScroll(scrollView)
    }
    
    override func responds(to aSelector: Selector!) -> Bool {
        if aSelector == #selector(scrollViewDidScroll(_:)) {
            return true
        }
        return originalDelegate?.responds(to: aSelector) ?? false
    }
    
    override func forwardingTarget(for aSelector: Selector!) -> Any? {
        if originalDelegate?.responds(to: aSelector) == true {
            return originalDelegate
        }
        return super.forwardingTarget(for: aSelector)
    }
}

第二步:给SwiftUI List添加滚动监听

struct ContentListView: View {
    // 滚动方向回调:参数为true代表向下滚动,false代表向上滚动
    var onScrollDirectionUpdate: (Bool) -> Void
    @State private var scrollDelegate: ScrollViewDelegateForwarder?
    
    var body: some View {
        List {
            // 替换为你自己的List业务内容
            ForEach(0..<100) { index in
                Text("测试行 \(index)")
                    .frame(height: 60)
            }
        }
        .background(ScrollViewCapture(onScrollViewFound: { scrollView in
            guard scrollDelegate == nil else { return }
            let forwarder = ScrollViewDelegateForwarder { scrollView in
                let translationY = scrollView.panGestureRecognizer.translation(in: scrollView).y
                onScrollDirectionUpdate(translationY < 0)
            }
            forwarder.originalDelegate = scrollView.delegate
            scrollView.delegate = forwarder
            scrollDelegate = forwarder
        }))
    }
}

第三步:在UIHostingController中实现导航栏控制

class CustomHostingController: UIHostingController<ContentListView> {
    init() {
        let listView = ContentListView { [weak self] shouldHide in
            self?.navigationController?.setNavigationBarHidden(shouldHide, animated: true)
        }
        super.init(rootView: listView)
    }
    
    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

注意事项

  • 该方案完全基于iOS13支持的API实现,无任何高版本依赖
  • 代理转发逻辑保证了List原有的滑动、点击、编辑等原生功能不受影响
  • 若List存在多层嵌套滚动视图的场景,调整ScrollViewCapture中的遍历逻辑匹配你自己的视图层级即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:06:03