SwiftUI中FamilyActivityPicker导航栏按钮不显示及双导航栏问题
解决SwiftUI中FamilyActivityPicker的取消/完成按钮问题
核心问题原因
.navigationBarItems在iOS 16+已被废弃,且无法作用于FamilyActivityPickerViewController(UIKit原生控制器),导致按钮不显示。- 外层嵌套SwiftUI的
NavigationStack会与FamilyActivityPicker自身的UIKit导航栏冲突,出现双导航栏。
正确实现方式
通过UIViewControllerRepresentable封装FamilyActivityPicker时,直接使用UIKit的导航控制器自定义按钮,避免与SwiftUI导航组件冲突:
1. 封装带自定义导航按钮的FamilyActivityPicker
import SwiftUI import ScreenTime struct FamilyActivityPickerView: UIViewControllerRepresentable { @Binding var isPresented: Bool let onSelectionConfirmed: ([ActivitySelectionItem]) -> Void func makeUIViewController(context: Context) -> UINavigationController { let picker = FamilyActivityPickerViewController() picker.delegate = context.coordinator // 添加取消按钮 picker.navigationItem.leftBarButtonItem = UIBarButtonItem( barButtonSystemItem: .cancel, target: context.coordinator, action: #selector(context.coordinator.onCancelTapped) ) // 添加完成按钮 picker.navigationItem.rightBarButtonItem = UIBarButtonItem( barButtonSystemItem: .done, target: context.coordinator, action: #selector(context.coordinator.onDoneTapped) ) // 用UIKit导航控制器承载picker,确保导航栏正常显示 return UINavigationController(rootViewController: picker) } func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, FamilyActivityPickerViewControllerDelegate { private let parent: FamilyActivityPickerView init(parent: FamilyActivityPickerView) { self.parent = parent } @objc func onCancelTapped() { parent.isPresented = false } @objc func onDoneTapped() { guard let picker = parent.makeUIViewController(context: Context()).topViewController as? FamilyActivityPickerViewController else { parent.isPresented = false return } parent.onSelectionConfirmed(picker.selectedItems ?? []) parent.isPresented = false } // 实现picker代理的默认方法(可选兜底) func familyActivityPickerViewControllerDidFinish(_ controller: FamilyActivityPickerViewController) { parent.isPresented = false } func familyActivityPickerViewControllerDidCancel(_ controller: FamilyActivityPickerViewController) { parent.isPresented = false } } }
2. 在SwiftUI视图中调用封装好的Picker
直接用.sheet或.fullScreenCover展示,无需嵌套SwiftUI的NavigationStack:
struct MainView: View { @State private var showActivityPicker = false @State private var selectedActivities: [ActivitySelectionItem] = [] var body: some View { VStack(spacing: 20) { Button("选择限制活动") { showActivityPicker = true } if !selectedActivities.isEmpty { Text("已选中\(selectedActivities.count)项活动") } } .sheet(isPresented: $showActivityPicker) { FamilyActivityPickerView( isPresented: $showActivityPicker, onSelectionConfirmed: { items in selectedActivities = items } ) } } }
关键说明
- 用UIKit的
UINavigationController承载FamilyActivityPickerViewController,确保导航栏属于同一层级,避免双栏冲突。 - 直接通过
UIBarButtonItem添加按钮,绑定到Coordinator的方法处理取消/完成逻辑,同时利用FamilyActivityPicker的代理方法做兜底。
内容的提问来源于stack exchange,提问作者sudoExclamationExclamation
相关产品推荐
相关产品推荐

