I am trying to add UIKit context menu to a SwiftUI view because SwiftUI context menu is pretty limited. I managed to do it, but UIViewControllerRepresentable takes more space than it needs. How can I resize it to fit the content inside it? Here is my code.
SwiftUI code
struct TrackerCard: View {
var tracker: Tracker
var body: some View {
HStack {
HStack {
...
}
.padding()
.background(Color("Wrapper"))
.cornerRadius(15)
}
.padding(.horizontal)
}
}
struct TrackerCardView: View {
var tracker: Tracker
var body: some View {
ContextMenuView(card: TrackerCard(tracker: tracker))
}
}
UIKit code
class ContextMenuController : UIViewController, UIContextMenuInteractionDelegate {
var card: TrackerCard?
var hostingViewController: UIHostingController<TrackerCard>?
func setViewController(_ controller : UIHostingController<TrackerCard>) {
hostingViewController = controller
self.addChild(controller)
controller.view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .init(white: 1, alpha: 1)
view.addSubview(controller.view)
controller.didMove(toParent: self)
controller.view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
}
func setInteraction() {
let interaction = UIContextMenuInteraction(delegate: self)
hostingViewController?.view.addInteraction(interaction)
}
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
return ...
}
struct ContextMenuView: UIViewControllerRepresentable {
typealias UIViewControllerType = ContextMenuController
var card: TrackerCard
var controller : UIViewControllerType? = nil
func makeUIViewController(context: Context) -> ContextMenuController {
let contextMenuController = controller ?? ContextMenuController()
contextMenuController.card = card
return contextMenuController
}
func updateUIViewController(_ contextMenuController: ContextMenuController, context: Context) {
contextMenuController.setViewController(UIHostingController(rootView: card))
contextMenuController.setInteraction()
}
}
Try this. First, add
.fixedSize
to your SwiftUI view:With that, the view should be unconstrained horizontally but only take up as much space as it needs vertically, based on its preferred size.
But you might notice that with the current layout, the height gets squished (all the way to 0).
To fix that, we need to set the
preferredContentSize
like this in theUIViewController
:See the blog post Self-sizing Child Views for more details about that.
But the height might still get set to 0. In my case, I had to add a constraint for the height for the preferred height to be calculated as desired (not 0).
Hope that helps. If not, it would be good if you edited your answer to include a minimal working example with a preview that shows the problem.