UIMenuController仅保留Copy和Share功能异常求助
先来说说你的两个问题的根源,以及对应的修复方案:
问题1:仅显示Share按钮,Copy不出现
原因分析
- 自定义长按手势干扰默认文本选择:你给UITextView加了自定义的
UILongPressGestureRecognizer,但UITextView本身自带长按选中文本的交互逻辑,自定义手势会抢占响应,导致系统检测不到文本被选中——而Copy按钮只有在存在选中内容时才会激活显示。 - 错误的Selector写法:你用了
Selector("_copy:")和Selector("_share:")这类私有API写法,正确的系统公开选择器应该是#selector(copy(_:))(对应Copy)和#selector(UIResponderStandardEditActions.share(_:))(对应Share)。 - 多余的UIScrollView扩展:UIScrollView并不是第一响应者(第一响应者是UITextView),给它重写
canPerformAction完全没必要,还可能引发逻辑冲突。
修复步骤
- 删掉自定义的长按手势相关代码(包括
viewDidLoad里的手势创建、添加,以及longPressHandler方法)。 - 修正UITextView的
canPerformAction扩展,用正确的选择器,同时确保Copy仅在有文本选中时才允许:
extension UITextView { override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { // 只有选中文本时才允许Copy let allowCopy = action == #selector(copy(_:)) && self.selectedRange.length > 0 let allowShare = action == #selector(UIResponderStandardEditActions.share(_:)) return allowCopy || allowShare } }
问题2:Share按钮显示在屏幕中心而非选中文本位置
原因分析
你之前通过自定义长按手势设置setTargetRect(senderView.frame, in: superView),这里的senderView.frame是整个UITextView的范围,而非选中文本的区域,所以菜单会显示在整个TextView的位置,看起来像是屏幕中心。
修复步骤
既然我们移除了自定义长按手势,现在依赖UITextView的默认文本选择交互,系统会自动处理菜单位置。如果需要更精准的控制,可以重写UITextView的menuTargetRect(for:)方法指定菜单目标区域:
extension UITextView { override open func menuTargetRect(for configuration: UIContextMenuConfiguration) -> CGRect { guard let selectedRange = self.selectedTextRange else { return super.menuTargetRect(for: configuration) } // 获取选中文本的第一个矩形区域 let textRect = self.firstRect(for: selectedRange) // 转换到当前视图坐标系 return self.convert(textRect, from: self.textInputView) } }
完整修正后的代码
import UIKit class DetailViewController: UIViewController { var selectedStory : URL! @IBOutlet weak var textView: UITextView! @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var textSlider: UISlider! { didSet { configureSlider() } } override func viewDidLoad() { super.viewDidLoad() let storyText = try? String(contentsOf: selectedStory) textView.text = storyText textView.isUserInteractionEnabled = true textView.isSelectable = true // 确保文本可选中,即使不需要编辑 // 移除了自定义长按手势 } override var canBecomeFirstResponder: Bool { return true } // 你的滑块配置方法 func configureSlider() { // 这里放滑块的配置逻辑 } } extension UITextView { override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { let allowCopy = action == #selector(copy(_:)) && self.selectedRange.length > 0 let allowShare = action == #selector(UIResponderStandardEditActions.share(_:)) return allowCopy || allowShare } override open func menuTargetRect(for configuration: UIContextMenuConfiguration) -> CGRect { guard let selectedRange = self.selectedTextRange else { return super.menuTargetRect(for: configuration) } let textRect = self.firstRect(for: selectedRange) return self.convert(textRect, from: self.textInputView) } }
额外提醒
如果不需要文本编辑功能,可以设置textView.isEditable = false,只要isSelectable = true,依然可以选中文本并显示菜单。
内容的提问来源于stack exchange,提问作者bobcat
相关产品推荐
相关产品推荐

