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

SwiftUI中FamilyActivityPicker导航栏按钮不显示及双导航栏问题

解决SwiftUI中FamilyActivityPicker的取消/完成按钮问题

核心问题原因

  1. .navigationBarItems 在iOS 16+已被废弃,且无法作用于FamilyActivityPickerViewController(UIKit原生控制器),导致按钮不显示。
  2. 外层嵌套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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:13:21