如何遍历MFMessageComposeViewController的视图层级以获取消息输入UITextField并禁用其编辑功能?
遍历MFMessageComposeViewController视图层级禁用输入框编辑
首先得提醒你一句:MFMessageComposeViewController是系统私有视图控制器,它的内部视图结构可能会随着iOS版本更新发生变化,所以这个方案可能在未来系统版本里失效,得做好兼容准备。
要实现你的需求,核心是在控制器完全present之后再遍历视图层级——因为你在present前调用messageVC.view.subviews的时候,视图还没完成加载,根本拿不到完整的子视图结构。
下面是修改后的代码,我给你加了递归遍历视图的方法:
@IBAction func sendSmsClick(_ sender: AnyObject) { guard MFMessageComposeViewController.canSendText() else { return } let messageVC = MFMessageComposeViewController() messageVC.body = "Enter a message" messageVC.recipients = ["Enter tel-nr"] messageVC.messageComposeDelegate = self // 关键:在present完成的闭包里执行遍历,此时视图已完全加载 self.present(messageVC, animated: false) { self.disableMessageTextField(in: messageVC.view) } } // 递归遍历视图层级,找到目标UITextField并禁用编辑 private func disableMessageTextField(in view: UIView) { for subview in view.subviews { // 判断是否是UITextField if let textField = subview as? UITextField { // 禁用用户交互,直接阻止编辑;也可以用textField.isEditable = false textField.isUserInteractionEnabled = false // 如果需要更精准匹配,比如根据placeholder或者位置,还可以加额外判断 // if textField.placeholder == "输入消息" { ... } } else { // 递归遍历子视图 disableMessageTextField(in: subview) } } } func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) { switch result { case .cancelled: print("Message was cancelled") case .failed: print("Message failed") case .sent: print("Message was sent") @unknown default: break } self.dismiss(animated: true) }
补充说明:
- 为什么要在present的completion里执行?因为系统控制器的视图是在present过程中才完成加载和布局的,提前调用遍历拿不到目标输入框。
- 如果担心误禁用其他UITextField(比如收件人输入框),可以加额外判断条件,比如根据输入框的
placeholder、frame大小或者父视图类型来精准匹配消息内容输入框。 - 因为是依赖系统私有视图结构,建议在不同iOS版本上做测试,避免版本更新后失效。
内容的提问来源于stack exchange,提问作者user16780334
相关产品推荐
相关产品推荐

