iOS如何自定义默认Contextual Menu?修改图标位置至左侧
需求:修改iOS系统默认Contextual Menu的布局,让菜单选项中的图标显示在文字左侧。尝试通过设置UIView.appearance().semanticContentAttribute = .forceRightToLeft实现,但未达到预期效果。
当前代码(基于UIKit,iOS15+):
import UIKit @available(iOS 14.0, *) class ViewController: UIViewController, UIContextMenuInteractionDelegate { @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() let interaction = UIContextMenuInteraction(delegate: self) imageView.addInteraction(interaction) imageView.isUserInteractionEnabled = true imageView.layer.cornerRadius = 25 } func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? { imageView.layer.borderWidth = 4 imageView.layer.cornerRadius = 25 imageView.layer.borderColor = CGColor.init(red: 256, green: 256, blue: 256, alpha: 1) return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ -> UIMenu? in return self.createContextMenu() } } func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) { self.imageView.layer.borderWidth = 0 } func createContextMenu() -> UIMenu { let shareAction = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up")) { _ in self.imageView.layer.borderWidth = 0 print("Share") } let copy = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in print("Copy") self.imageView.layer.borderWidth = 0 } let saveToPhotos = UIAction(title: "Add To Photos", image: UIImage(systemName: "photo")) { _ in print("Save to Photos") self.imageView.layer.borderWidth = 0 } UIView.appearance().semanticContentAttribute = .forceRightToLeft return UIMenu(title: "", children: [saveToPhotos, copy, shareAction]) } }
当前UI效果:菜单选项文字居左,图标居右。
期望UI效果:菜单选项图标居左,文字居右。
解决方案
方法1:针对菜单单元格设置语义方向(兼容iOS15+)
全局设置UIView.appearance()会影响所有视图,且无法精准作用于Contextual Menu的选项单元格。正确做法是针对菜单的私有单元格类UIContextMenuActionCell设置语义方向,仅修改菜单选项布局:
在createContextMenu()方法中,替换全局UIView外观设置,改为:
// 仅针对Contextual Menu的选项单元格设置语义方向 if let cellClass = NSClassFromString("UIContextMenuActionCell") as? UIView.Type { cellClass.appearance().semanticContentAttribute = .forceRightToLeft }
方法2:使用iOS16+原生属性(更优雅)
如果项目支持iOS16及以上,可直接给UIAction添加.imageLeading属性,无需修改语义方向:
let shareAction = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up"), attributes: .imageLeading) { _ in self.imageView.layer.borderWidth = 0 print("Share") } let copy = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc"), attributes: .imageLeading) { _ in print("Copy") self.imageView.layer.borderWidth = 0 } let saveToPhotos = UIAction(title: "Add To Photos", image: UIImage(systemName: "photo"), attributes: .imageLeading) { _ in print("Save to Photos") self.imageView.layer.borderWidth = 0 }
注意事项
- 方法1中使用的
UIContextMenuActionCell是私有类,当前iOS版本兼容,但后续苹果可能修改类名,需关注兼容性。 - 方法2的
.imageLeading属性为iOS16新增,若需兼容iOS15,建议使用方法1。
内容的提问来源于stack exchange,提问作者Pushkar Pandey
相关产品推荐
相关产品推荐

