gpt4 book ai didi

swiftui - 使 UIKit ContextMenu 预览提供程序框架适合 UIHostingControler 内的 SwiftUI View

转载 作者:行者123 更新时间:2023-12-04 17:23:27 33 4
gpt4 key购买 nike

我正在学习 Swift 和 SwiftUI 作为没有 UIKit 背景的业余爱好,所以我不确定这目前是否可行。我真的很想在 SwiftUI 中使用 UIKit 的上下文菜单(例如,实现子菜单、操作属性和自定义预览提供程序)。
我最初的想法是创建一个 LegacyContextMenuViewUIViewControllerRepresentable .然后我会使用 UIHostingController添加 SwiftUI View 作为 UIViewController 的子项ContainerViewController我要添加一个 UIContextMenuInteraction .
我当前的解决方案有点工作,但是当上下文菜单被激活时,“ContainerViewController” View 的预览框架不适合 UIHostingController 的大小看法。我不熟悉 UIKit 的布局系统,所以我想知道:

  • 是否可以在激活预览时添加此类约束?
  • 是否可以保留 clipShape预览提供程序中的底层 SwiftUI View ?

  • 代码:
    // MARK: - Describes a UIKit Context Menu
    struct LegacyContextMenu {
    let title: String
    let actions: [UIAction]
    var actionProvider: UIContextMenuActionProvider {
    { _ in
    UIMenu(title: title, children: actions)
    }
    }

    init(actions: [UIAction], title: String = "") {
    self.actions = actions
    self.title = title
    }
    }

    // MARK: - A View that brings UIKit context menus into the SwiftUI world
    struct LegacyContextMenuView<Content: View>: UIViewControllerRepresentable {
    let content: Content
    let menu: LegacyContextMenu

    func makeUIViewController(context: Context) -> UIViewController {
    let controller = ContainerViewController(rootView: content)

    let menuInteraction = UIContextMenuInteraction(delegate: context.coordinator)
    controller.view.addInteraction(menuInteraction)

    return controller
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }

    func makeCoordinator() -> Coordinator { Coordinator(parent: self) }

    class Coordinator: NSObject, UIContextMenuInteractionDelegate {
    let parent: LegacyContextMenuView

    init(parent: LegacyContextMenuView) { self.parent = parent }

    func contextMenuInteraction(
    _ interaction: UIContextMenuInteraction,
    configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration?
    {
    // previewProvider nil = using the default UIViewController: ContainerViewController
    UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: parent.menu.actionProvider)
    }
    }

    class ContainerViewController: UIViewController {
    let hostingController: UIHostingController<Content>

    init(rootView: Content) {
    self.hostingController = UIHostingController(rootView: rootView)
    super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    override func viewDidLoad() {
    super.viewDidLoad()
    setupHostingController()
    setupContraints()

    // Additional setup required?
    }

    func setupHostingController() {
    addChild(hostingController)
    view.addSubview(hostingController.view)
    hostingController.didMove(toParent: self)
    }

    // Not familiar with UIKit's layout system so unsure if this is the best approach
    func setupContraints() {
    hostingController.view.translatesAutoresizingMaskIntoConstraints = false
    view.addConstraints([
    hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
    hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
    hostingController.view.leftAnchor.constraint(equalTo: view.leftAnchor),
    hostingController.view.rightAnchor.constraint(equalTo: view.rightAnchor)
    ])
    }
    }
    }

    // MARK: - Simulate SwiftUI syntax
    extension View {
    func contextMenu(_ legacyContextMenu: LegacyContextMenu) -> some View {
    self.modifier(LegacyContextViewModifier(menu: legacyContextMenu))
    }
    }

    struct LegacyContextViewModifier: ViewModifier {
    let menu: LegacyContextMenu

    func body(content: Content) -> some View {
    LegacyContextMenuView(content: content, menu: menu)
    }
    }
    然后为了测试,我用这个:
    // MARK - A sample view with custom content shape and a dynamic frame
    struct SampleView: View {
    @State private var isLarge = false

    let viewClipShape = RoundedRectangle(cornerRadius: 50.0)

    var body: some View {
    ZStack {
    Color.blue
    Text(isLarge ? "Large" : "Small")
    .foregroundColor(.white)
    .font(.largeTitle)
    }
    .onTapGesture { isLarge.toggle() }
    .clipShape(viewClipShape)
    .contentShape(viewClipShape)
    .frame(height: isLarge ? 250 : 150)
    .animation(.easeInOut, value: isLarge)
    }
    }

    struct ContentView: View {
    var body: some View {
    SampleView()
    .contextMenu(LegacyContextMenu(actions: [sampleAction], title: "My Menu"))
    .padding(.horizontal)
    }

    let sampleAction = UIAction(
    title: "Remove",
    image: UIImage(systemName: "trash.fill"),
    identifier: nil,
    attributes: UIMenuElement.Attributes.destructive,
    handler: { _ in print("Pressed 'Remove'") })
    }
    长按时,上下文菜单缩放动画尊重 SampleView 的内容形状对于小尺寸和大尺寸,但预览弹出如下:
    Small
    Large

    最佳答案

    您必须设置 ViewController 的 preferredContentSize 以适合您想要的内容大小

    关于swiftui - 使 UIKit ContextMenu 预览提供程序框架适合 UIHostingControler 内的 SwiftUI View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64919548/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com