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

SwiftUI隐藏导航栏后,如何调整Refresh Control避免被自定义导航栏遮挡?

问题:自定义导航栏遮挡List的Refresh Control,如何调整位置?

隐藏系统导航栏后,自定义导航栏遮挡了List的Refresh Control,请问该如何调整Refresh Control的位置?

相关代码

ContentView代码

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            HomeNavigationBarView {
                List {
                    NavigationLink {
                        EmptyView()
                    } label: {
                        Text("Hello, world!")
                    }
                }
                .listStyle(.insetGrouped)
                .refreshable {
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

自定义导航栏代码

struct HomeNavigationBarView<Content: View>: View {
    let content: () -> Content
    var body: some View {
        ZStack(alignment: .top) {
            content()
            HStack {
                Image("logo")
                    .resizable()
                    .frame(width: 44, height: 44)
            }
            .frame(height: insetTop(), alignment: .bottom)
            .frame(maxWidth: .infinity)
            .background(.red.opacity(0.1))
        }
        .navigationBarHidden(true)
    }
}

private func insetTop() -> CGFloat {
    let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
    let window = windowScene?.windows.first
    return window?.safeAreaInsets.top ?? 0       // 20或47
}

问题截图

问题截图


解决方法

问题根源是自定义导航栏通过ZStack叠加在List上方,且导航栏背景覆盖了系统安全区顶部(safeAreaTop),而List的Refresh Control默认显示在该区域,导致被遮挡。以下是两种可行的解决方案:

方案一:调整导航栏布局,避免覆盖安全区顶部

修改自定义导航栏的布局,让导航栏背景仅覆盖自身内容区域,不占用安全区顶部空间。这样Refresh Control可以正常显示在安全区顶部,不会被遮挡。

修改后的自定义导航栏代码:

struct HomeNavigationBarView<Content: View>: View {
    let content: () -> Content
    var body: some View {
        ZStack(alignment: .top) {
            content()
            HStack {
                Image("logo")
                    .resizable()
                    .frame(width: 44, height: 44)
            }
            .frame(height: 44) // 固定导航栏内容高度为44
            .frame(maxWidth: .infinity)
            .background(.red.opacity(0.1))
            .padding(.top, insetTop()) // 将导航栏内容下移至安全区顶部下方
        }
        .navigationBarHidden(true)
    }
}

private func insetTop() -> CGFloat {
    let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
    let window = windowScene?.windows.first
    return window?.safeAreaInsets.top ?? 0
}

方案二:给List添加顶部内边距,避开导航栏区域

通过给List添加顶部内边距,让滚动内容下移至导航栏下方,下拉时Refresh Control会显示在导航栏下方的区域,避免被遮挡。

修改后的自定义导航栏代码:

struct HomeNavigationBarView<Content: View>: View {
    let content: () -> Content
    var body: some View {
        ZStack(alignment: .top) {
            content()
                .padding(.top, navigationBarTotalHeight()) // 添加顶部内边距,避开导航栏
            HStack {
                Image("logo")
                    .resizable()
                    .frame(width: 44, height: 44)
            }
            .frame(height: insetTop(), alignment: .bottom)
            .frame(maxWidth: .infinity)
            .background(.red.opacity(0.1))
        }
        .navigationBarHidden(true)
    }
    
    private func navigationBarTotalHeight() -> CGFloat {
        insetTop() + 44 // 导航栏总高度 = 安全区顶部高度 + 内容高度
    }
}

private func insetTop() -> CGFloat {
    let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
    let window = windowScene?.windows.first
    return window?.safeAreaInsets.top ?? 0
}

推荐方案一,因为它保留了系统默认的Refresh Control位置逻辑,用户交互更符合iOS设计规范。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 15:40:28