【问题标题】:How to disable UITextField editing but still accept touch?如何禁用 UITextField 编辑但仍接受触摸?
【发布时间】:2012-02-25 09:09:10
【问题描述】:

我正在制作一个UITextField,它的UIPickerViewinputView。一切都很好,除了我可以通过复制、粘贴、剪切和选择文本进行编辑,我不想要它。只有 Picker 应该修改文本字段。

我了解到我可以通过将setEnabledsetUserInteractionEnabled 设置为NO 来禁用编辑。好的,但是 TextField 停止响应触摸并且选择器不显示。

我可以做些什么来实现它?

【问题讨论】:

    标签: ios uitextfield uipickerview


    【解决方案1】:

    使用文本字段委托,有一个方法

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    

    从这里返回 NO,用户编辑文本的任何尝试都将被拒绝。

    这样您可以使该字段保持启用状态,但仍会阻止人们将文本粘贴到其中。

    【讨论】:

    • 如果您仍想响应触摸,请响应“touch down”而不是“touch up inside”。否则你的事件永远不会被调用。
    • @NickLockwood 有什么方法可以让 textField 成为第一响应者,但禁用用户交互并隐藏插入符号?
    • @entropy 我假设您希望能够选择内容以便用户可以复制它?如果您将 UITextField 子类化,您几乎可以覆盖任何行为 - 例如您可以强制该字段在用户触摸时始终全选,这将有效地隐藏插入符号。
    • @LoryLory 也一样,只是使用 Swift 语法代替委托方法。
    • 更准确地说,如果需要,我们可以使用“textFieldShouldBeginEditing”
    【解决方案2】:

    尼克的答案翻译成swift:

    P/S: Return false => textfields不能输入,用键盘编辑。它只是可以通过code.EX设置文本:textField.text = "My String Here"

    override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        return false
    }
    

    【讨论】:

    • 这对我不起作用。只需长按文本字段,直到出现缩放并出现 iOS 剪切/复制/粘贴菜单,我可以使用它来更改文本。
    • swift 4: `func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return false } `
    【解决方案3】:

    这是最简单的:

    在 viewDidLoad 中:(仅为不可编辑的文本字段设置委托。

    self.textfield.delegate=self;
    

    并插入这个委托函数:

    - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
    return NO;
    }
    

    就是这样!

    【讨论】:

    • 这会阻止显示选取器,因此无法解决所描述的问题
    • @MartinLockett 如果您从该委托方法触发UIPickerView 行为,则效果很好。
    • @AlbertBori 请问怎么做?
    【解决方案4】:

    在 swift 3+ 中:

    class MyViewController: UIViewController, UITextFieldDelegate {
    
       override func viewDidLoad() {
          self.myTextField.delegate     = self
       }
    
       func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
          if textField == myTextField {
             // code which you want to execute when the user touch myTextField
          }
          return false
       }
    }
    

    【讨论】:

      【解决方案5】:

      只需将 UIButton 准确地放置在整个 UITextField 上,没有标签文本,这使它“不可见”。此按钮可以代替 Textfield 接收和委托触摸,并且 TextField 的内容仍然可见。

      【讨论】:

        【解决方案6】:

        创建一个UITextField 的自定义子类会更优雅,它会为所有对canPerformAction:withSender: 的调用返回NO(或者至少在action@selector(cut)@selector(paste) 的地方),如@ 所述987654321@.

        此外,我还会实施 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 根据 Nick 的建议,禁用蓝牙键盘输入文本。

        【讨论】:

        • 我这辈子都想不出该怎么做。永远不会调用子类的 canPerformActionshouldChangeCharactersInRange 方法。
        【解决方案7】:

        在 Swift 中:

        func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
            questionField.resignFirstResponder();
            // Additional code here
            return false
        }
        

        【讨论】:

          【解决方案8】:

          我使用了 MrMage 提供的解决方案。我要添加的唯一一件事是您应该将 UITextView 作为第一响应者,否则您将被选中的文本卡住。

          这是我的快速代码:

          class TouchableTextView : UITextView {
          
              override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
                  self.resignFirstResponder()
                  return false
              }
          
              override func shouldChangeTextInRange(range: UITextRange, replacementText text: String) -> Bool {
                  self.resignFirstResponder()
                  return false
              }
          
          }
          

          【讨论】:

            【解决方案9】:

            对于处理 UIPickerView 和操作表的替代方法,请查看 ActionSheetPicker

            https://github.com/TimCinel/ActionSheetPicker

            它启用了 cocoapods。它处理操作表上的所有取消和完成按钮。示例项目中的示例很棒。我选择了 ActionSheetStringPicker,它可以轻松处理基于字符串的选项,但 API 可以处理我能想到的大部分内容。

            我最初启动了一个与勾选答案非常相似的解决方案,但偶然发现了这个项目并花了我大约 20 分钟将东西集成到我的应用程序中以供使用,包括使用 cocopods:ActionSheetPicker (~> 0.0)

            希望这会有所帮助。

            下载git项目,查看以下类:

            • ActionSheetPickerViewController.m
            • ActionSheetPickerCustomPickerDelegate.h

            这里大致是我添加的大部分代码,加上 *.h 导入。

            - (IBAction)gymTouched:(id)sender {
                  NSLog(@"gym touched");
            
                  [ActionSheetStringPicker showPickerWithTitle:@"Select a Gym" rows:self.locations initialSelection:self.selectedIndex target:self successAction:@selector(gymWasSelected:element:) cancelAction:@selector(actionPickerCancelled:) origin:sender];
             }
            
            
            - (void)actionPickerCancelled:(id)sender {
                NSLog(@"Delegate has been informed that ActionSheetPicker was cancelled");
            }
            
            
            - (void)gymWasSelected:(NSNumber *)selectedIndex element:(id)element {
                self.selectedIndex = [selectedIndex intValue];
            
                //may have originated from textField or barButtonItem, use an IBOutlet instead of element
                self.txtGym.text = [self.locations objectAtIndex:self.selectedIndex];
            }
            
            
            -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
                return NO;  // Hide both keyboard and blinking cursor.
            }
            

            【讨论】:

            【解决方案10】:

            在使用 UIPickerView 选择值时防止编辑 UITextField(在 Swift 中):

            self.txtTransDate = self.makeTextField(self.transDate, placeHolder: "Specify Date")
            self.txtTransDate?.addTarget(self, action: "txtTransDateEditing:", forControlEvents: UIControlEvents.EditingDidBegin)
            
            func makeTextField(text: String?, placeHolder: String) -> UITextField {
                var textField = UITextField(frame: CGRect(x: 140, y: 0, width: 220.00, height: 40.00));
                textField.placeholder = placeHolder
                textField.text = text
                textField.borderStyle = UITextBorderStyle.Line
                textField.secureTextEntry = false;
                textField.delegate = self
                return textField
            }
            
            
            func txtTransDateEditing(sender: UITextField) {
                var datePickerView:UIDatePicker = UIDatePicker()
                datePickerView.datePickerMode = UIDatePickerMode.Date
                sender.inputView = datePickerView
                datePickerView.addTarget(self, action: Selector("datePickerValueChanged:"), forControlEvents: UIControlEvents.ValueChanged)
            }
            
            func datePickerValueChanged(sender: UIDatePicker) {
                var dateformatter = NSDateFormatter()
                dateformatter.dateStyle = NSDateFormatterStyle.MediumStyle
                self.txtTransDate!.text = dateformatter.stringFromDate(sender.date)
            }
            
            func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool  {
                self.resignFirstResponder()
                return false
            }
            

            【讨论】:

              【解决方案11】:

              如果您准备好创建自定义文本字段,那么您可以使用另一个 * 问题的答案。 https://*.com/a/42698689/9369035

              只需覆盖上述答案中的这三种方法就足够了。至少就我的测试而言。

              【讨论】:

              • 感谢您参考答案,我想要的确切行为!
              【解决方案12】:

              此解决方法有效。在文本字段上方放一个透明的UIView,实现如下代码:

              - (void)viewDidLoad
              {
               [super viewDidLoad];
              
                 UILongPressGestureRecognizer *press = [[UILongPressGestureRecognizer alloc]             initWithTarget:self action:@selector(longPress)];
              [transparentView addGestureRecognizer:press];
               [press release];
                press = nil;
              }
              
              -(void)longPress
              {
                 txtField.userInteractionEnabled = NO;
              }
              
              -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
              {
                 txtField.userInteractionEnabled = YES;
              }
              
              -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
              {
                [txtField becomeFirstResponder];
              }
              

              【讨论】:

              • 我很困惑为什么你不使用简单的透明 UIButton + touchUpInside,而是选择了 UIView + 手势。
              【解决方案13】:

              使您的 inputView 由一个隐藏的文本字段呈现,该文本字段也会更改呈现和禁用的文本。

              【讨论】:

                【解决方案14】:

                不完全确定这是多么 hacky,但在我的案例中唯一能做到这一点的是添加一个目标操作并调用 endEditing。由于我的选择器控制着我的 UITextField.text 值,所以只要用户单击该字段,我就可以关闭键盘。这是一些代码:

                uiTextFieldVariable.addTarget(self, action: #selector(dismissKeyboard), for: .editingDidBegin)
                
                @objc private func dismissKeyboard() {
                    endEditing(true)
                }
                

                【讨论】:

                  【解决方案15】:

                  我用过:

                  [self.textField setEnabled:NO];
                  

                  它的工作正常

                  【讨论】:

                    【解决方案16】:

                    这对我有用 [textview setEditable:NO]; 上述答案使情况过于复杂。

                    【讨论】:

                    • OP 写道“我了解到我可以通过将 setEnabled 或 setUserInteractionEnabled:NO 设置为 NO 来禁用编辑。好的,但是 TextField 停止响应触摸并且选择器不显示。”您的回答将停止所有非预期结果的事件。
                    • @Tolgab 不是这个 OP 甚至相关的解决方案!