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

