I created my custom context menu using UIView. Im trying to change the corner radius when the context menu is active, but I have no idea how. I tried masks, layer whatsoever, but nothing worked. The provided current code is not rounding the corners. When I tried to set the background color to clear, then in between the fuzzy color and the content appeared a color that is the background color. Any idea?
Here is the undesired behavior (you can see the distinct corner rounding):
import SwiftUI
struct CustomContextMenu<Content: View>: View {
var content: Content
var menu: UIMenu?
var previewBackgroundColor: UIColor
init(
@ViewBuilder content: @escaping ()->Content,
actions: @escaping ()-> UIMenu?,
previewBackgroundColor: UIColor
) {
self.content = content()
self.menu = actions()
self.previewBackgroundColor = previewBackgroundColor
}
var body: some View {
content
.hidden()
.overlay(
ContextMenuHelper(content: content, actions: menu, previewBackgroundColor: previewBackgroundColor)
)
}
}
struct ContextMenuHelper<Content: View>: UIViewRepresentable
{
var content: Content
var actions: UIMenu?
var previewBackgroundColor: UIColor
init(content: Content, actions: UIMenu?, previewBackgroundColor: UIColor) {
self.content = content
self.actions = actions
self.previewBackgroundColor = previewBackgroundColor
}
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self )
}
func makeUIView(context: Context) -> UIView {
// uiview
let view = UIView()
view.backgroundColor = UIColor.clear
view.layer.cornerRadius = 20
// host view
let hostView = UIHostingController(rootView: content)
hostView.view.translatesAutoresizingMaskIntoConstraints = false
hostView.view.backgroundColor = .clear
view.addSubview(hostView.view) // add subview
view.addConstraints( // add constraints
[
hostView.view.topAnchor.constraint(equalTo: view.topAnchor),
hostView.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostView.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
hostView.view.widthAnchor.constraint(equalTo: view.widthAnchor),
hostView.view.heightAnchor.constraint(equalTo: view.heightAnchor)
]
)
if self.actions != nil { // if any menu item has been loaded
// interaction
let interaction = UIContextMenuInteraction(delegate: context.coordinator)
view.addInteraction(interaction)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
class Coordinator: NSObject, UIContextMenuInteractionDelegate {
var parent: ContextMenuHelper
init(parent: ContextMenuHelper) {
self.parent = parent
}
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
interaction.view?.layer.cornerRadius = 30
guard let viewFrame = interaction.view?.frame else { return nil } // obtain child view size
return UIContextMenuConfiguration(identifier: nil) {
let previewController = UIHostingController(rootView: self.parent.content)
previewController.view.backgroundColor = self.parent.previewBackgroundColor
previewController.preferredContentSize = CGSize(width: viewFrame.width, height: viewFrame.height)
return previewController
} actionProvider: { items in
return self.parent.actions
}
}
}
}
EDIT:
When Im wrapping the view into another view it changes the inner view, not the outer view:
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
interaction.view?.layer.cornerRadius = 30
guard let viewFrame = interaction.view?.frame else { return nil } // obtain child view size
return UIContextMenuConfiguration(identifier: nil) {
let previewView = self.parent.content
.background(Color(self.parent.previewBackgroundColor).edgesIgnoringSafeArea(.all))
.cornerRadius(30)
let previewController = UIHostingController(rootView: previewView)
previewController.preferredContentSize = CGSize(width: viewFrame.width, height: viewFrame.height)
return previewController
} actionProvider: { items in
return self.parent.actions
}
}
2
Answers
So I resolved the issue by changing contextMenuInteraction method contents and by rounding view which wraps host view.
Since you’re already using a
UIHostingController
to create the preview content, ensure that the SwiftUI view you’re providing has the desired corner radius and background color.If the first approach doesn’t work due to the specific composition of your view, consider wrapping your content in another SwiftUI view that applies a background and corner radius before being passed to
UIHostingController
. This can provide a more controllable context for styling: