【问题标题】:Hide the cursor of a UITextField隐藏 UITextField 的光标
【发布时间】:2011-04-11 14:43:36
【问题描述】:

我使用UITextFieldUIPickerView 作为其inputView,这样当用户点击文本字段时,会召唤一个选择器让他们从中选择一个选项。

几乎一切正常,但我有一个问题:当它处于活动状态时,光标仍会在文本字段中闪烁,这是丑陋且不合适的,因为不希望用户在该字段中输入,也不会出现键盘.我知道我可以通过在文本字段上将editing 设置为NO 并跟踪对它的触摸,或者将其替换为自定义样式的按钮并通过代码调用选择器来解决这个问题。但是,我想对文本字段上的所有事件处理使用 UITextFieldDelegate 方法,并且用按钮替换文本字段等黑客行为不允许这种方法。

我怎样才能简单地将光标隐藏在UITextField 上?

【问题讨论】:

    标签: ios cocoa-touch uitextfield uipickerview


    【解决方案1】:

    由 OP 提供的答案,从问题正文中复制,以帮助清理不断增长的未回答问题。

    我认为我有正确的解决方案,但如果可以改进将受到欢迎 :) 好吧,我创建了 UITextField 的子类并覆盖了返回边界的 CGRect 的方法

    -(CGRect)textRectForBounds:(CGRect)bounds {
        return CGRectZero;
    }
    

    问题?文本不显示,因为 rect 为零。但是我添加了一个 UILabel 作为控件的子视图并覆盖了 setText 方法,因此,当我们像往常一样输入文本时,文本字段文本为 nil 并且是显示文本的标签

    - (void)setText:(NSString *)aText {
        [super setText:nil];
    
        if (aText == nil) {
            textLabel_.text = nil;
        }
    
        if (![aText isEqualToString:@""]) {
            textLabel_.text = aText;
        }
    }
    

    有了这个,事情就可以按预期工作了。你知道有什么方法可以改进吗?

    【讨论】:

    • 这个答案现在基本上毫无价值,因为 Joseph Chiu 的替代方法非常相似但更简单。我可以建议删除它吗?
    【解决方案2】:

    由 OP 提供的答案,从问题正文中复制,以帮助清理不断增长的未回答问题。

    我找到了另一个解决方案:子类UIButton 并覆盖这些方法

    - (UIView *)inputView {
        return inputView_;
    }
    
    - (void)setInputView:(UIView *)anInputView {
        if (inputView_ != anInputView) {
            [inputView_ release];
            inputView_ = [anInputView retain];
        }
    }
    
    - (BOOL)canBecomeFirstResponder {
        return YES;
    }
    

    现在,作为UIResponder 的按钮具有与UITextField 类似的行为,并且实现非常简单。

    【讨论】:

    • 这并不是一个很好的解决方案。在下面查看这个答案:stackoverflow.com/a/13660503/1103584
    • 为什么这不是一个很好的解决方案?它达到了预期的效果,还为以前没有的类提供了功能。它也不是黑客。我觉得这真的很酷。那么它有什么问题呢?
    • @BreadicalMD 我能看到的最大问题是你不能使用UITextFieldDelegate 来处理开始和结束编辑事件。相反 - 除非有办法处理我不知道的那些事件 - 您需要在按钮子类中覆盖 becomeFirstResponderresignFirstResponder,并可能创建自己的委托协议,添加 delegate属性,并从上述方法调用委托。这比在UITextField 子类中覆盖caretRectForPosition 要多得多。
    • @BreadicalMD 就是说,尽管从任何实际的角度来看,Joseph Chiu 的回答都优越,但我仍然同意你的观点,这很性感。我以前从未仔细查看过 UIResponder 类参考,也不知道这样的技巧是可能的。
    • 派对迟到了,但我认为这是一个非常好的解决方案,而且感觉比使用 UITextField 和隐藏光标更合适,也更不像黑客,这基本上是一个黑客,因为然后,我们将文本字段用作标签,而不使用 UITextField 的任何功能。
    【解决方案3】:

    我只是继承UITextField,并覆盖layoutSubviews,如下所示:

    - (void)layoutSubviews
    {
        [super layoutSubviews];
        for (UIView *v in self.subviews)
        {
            if ([[[v class] description] rangeOfString:@"UITextSelectionView"].location != NSNotFound)
            {
                v.hidden = YES;
            }
        }
    }
    

    这是一个肮脏的 hack,将来可能会失败(此时光标将再次可见 - 您的应用不会崩溃),但它可以工作。

    【讨论】:

      【解决方案4】:

      简单地继承 UITextField 并覆盖 caretRectForPosition

      - (CGRect)caretRectForPosition:(UITextPosition *)position
      {
          return CGRectZero;
      }
      

      【讨论】:

      • 漂亮!对我来说就像一个魅力。
      • @Joseph Chiu 效果很好。但不适用于 iOS 4.3。你能帮我解决这个问题吗?
      • 最干净和最短的方法,值得双重支持 =)
      • 只是一个注释。在我的子类中,我添加了一个 bool hideCaret 然后在此覆盖中如果它是 true -> 返回 CGRectZero 否则返回 super 的结果。
      • 请注意,即使光标被隐藏并且您使用选择器视图,使用外部键盘的用户也可以更改文本字段的值。
      【解决方案5】:

      查看协议 UITextInput属性 selectedTextRange UITextField 符合该协议。很少!这是面向对象编程的一课。

      隐藏插入符号

      要隐藏插入符号,请将文本字段的选定文本范围归零。

      textField.selectedTextRange = nil; // hides caret
      

      取消隐藏插入符号

      这里有两种方法可以取消隐藏插入符号。

      1. 将文本字段的选定文本范围设置为文档的末尾。

        UITextPosition *end = textField.endOfDocument;
        textField.selectedTextRange = [textField textRangeFromPosition:end
                                                            toPosition:end];
        
      2. 要将插入符号保持在同一位置,首先,将文本字段的选定文本范围存储到实例变量中。

        _textFieldSelectedTextRange = textField.selectedTextRange;
        textField.selectedTextRange = nil; // hides caret
        

        然后,当您想取消隐藏插入符号时,只需将文本字段的选定文本范围设置回原来的值:

        textField.selectedTextRange     = _textFieldSelectedTextRange;
        _textFieldLastSelectedTextRange = nil;
        

      【讨论】:

      • 这个特殊的解决方案不适用于我的实现。光标仍在闪烁。
      • 那么,也许你应该在bugreport.apple.com 提交一个错误,因为 iOS 文档说:“如果文本范围有长度,它表示当前选择的文本。如果它的长度为零,它表示插入符号(插入点)。如果 text-range 对象为 nil,则表示没有当前选择。"
      • 我不在乎提交报告。如果其他人使用您的“解决方案”并且认为它不起作用,我希望他们知道他们并不孤单。
      • 尽管有@ArtGeigel 的cmets,但这对我来说非常有效。但是,我更喜欢涉及覆盖caretRectForPosition 的解决方案。它在做什么更明确,并且您引用的文档并没有明确在“没有当前选择”时插入符号的行为应该是什么。如果@ArtGeigel 声称这不起作用是正确的(至少在我看来不是),那么这是否是一个错误就不清楚了。
      • 对我也不起作用。插入符号仍然存在并闪烁。
      【解决方案6】:

      如果你想隐藏光标,你可以轻松使用它!它对我有用..

      [[textField valueForKey:@"textInputTraits"] setValue:[UIColor clearColor] forKey:@"insertionPointColor"]
      

      【讨论】:

      • 据我所知,这是无证的。如果您将应用程序提交到应用商店,使用它可能会因为调用私有 API 而被拒绝,但我不知道有任何提交使用它来以一种或另一种方式测试这种推测。很遗憾,因为能够在没有子类化的情况下解决这个问题会很好,而这个答案可以做到这一点。
      【解决方案7】:

      从 iOS 7 开始,您现在只需在 textField 上设置 tintColor = [UIColor clearColor],插入符号就会消失。

      【讨论】:

      • 目前有效,但我建议不要使用它,因为它可能会在未来发生变化。而是选择 caretRectForPosition: 覆盖解决方案。
      • @lipka 没错,这可能是一个更好的方法。
      • 现在已经足够了。有时您只需要一个快速的解决方案。
      • 这是迄今为止最简单的解决方案!
      • 这个答案应该被批准用于 iOS 7+
      【解决方案8】:

      您可以通过关联对象将BOOL cursorless 属性添加到类别中的UITextField

      @interface UITextField (Cursorless)
      
      @property (nonatomic, assign) BOOL cursorless;
      
      @end
      

      然后使用方法调配来调配caretRectForPosition:,并使用在CGRectZero 和使用cursorless 的默认值之间切换的方法。

      这通过一个插入类别导致了一个简单的界面。以下文件对此进行了演示。

      只需将它们放入并获得这个简单界面的好处

      UITextField 类别: https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless.h https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless.m

      方法混搭: https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXRuntimeAdditions.h https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXRuntimeAdditions.m

      【讨论】:

      • 在这么多级别上的糟糕解决方案!对于初学者:永远不要覆盖类别中的方法。除非您真的非常需要它,否则请避免使用 Method Swizzling(其他人已经为这个问题提出了很好的解决方案)。它使您的代码变得如此复杂。
      • 如果您真正查看了代码,您会意识到类别中没有方法被覆盖,并且方法调配被正确实现。我多年来一直在使用这个实现。
      • 另外,请解释添加约 150 行的独立代码库以永久解决不断重复出现的问题有什么复杂之处?这不仅不会使您的代码库复杂化,而且还提供了最简单的接口;一个布尔值来指示功能。
      • 看看这个关于方法调配stackoverflow.com/questions/5339276/…特别是调试的精彩讨论。方法调配是一个了不起的功能,但恕我直言,只应在需要时使用。使用此处提供的建议之一很容易解决此问题,并且将为其他程序员提供更易于维护和阅读的代码。
      • 我之前已经阅读过,并且在我的实现中遵循了所有概述的指导方针以确保正确性。可以说,这是方法调配胜出的一个很好的例子。这是基本库未能以简单的方式跨平台实现广泛需要的功能的孤立但常见的情况。建议的其他示例在语义上没有定义无光标文本字段,它们仅通过混淆光标的框架或其颜色来执行它。对于新程序员来说,这个界面是最容易阅读的,并且完全符合预期。
      【解决方案9】:

      为了同时禁用光标和菜单,我使用了这两种方法的子类:

      - (CGRect)caretRectForPosition:(UITextPosition *)position {
          return CGRectZero;
      }
      
      - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
          [UIMenuController sharedMenuController].menuVisible = NO;
          self.selectedTextRange = nil;
      
          return NO;
      }
      

      【讨论】:

        【解决方案10】:

        您可能还想阻止用户选择、复制或粘贴任何文本,以便唯一的文本输入来自选择器视图。

        - (CGRect) caretRectForPosition:(UITextPosition*) position
        {
            return CGRectZero;
        }
        
        - (NSArray *)selectionRectsForRange:(UITextRange *)range
        {
            return nil;
        }
        
        - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
        {
            if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(paste:))
            {
                returnNO;
            }
        
            return [super canPerformAction:action withSender:sender];
        }
        

        http://b2cloud.com.au/tutorial/disabling-the-caret-and-text-entry-in-uitextfields/

        【讨论】:

          【解决方案11】:

          您可以只清除文本字段的 tintColor

          self.textField.tintColor = [UIColor clearColor];
          

          Swift 3.0

          self.textField.tintColor = .clear
          

          【讨论】:

          • 最简单的答案。
          • 如上所述,清除色调并不会阻止使用外部键盘 (iPad Pro) 的用户更改文本。
          • @MichaelLong 这并不是要阻止用户更改文本,它只是一种样式选择。
          【解决方案12】:

          Swift 5 版本的网帖

            override func caretRect(for position: UITextPosition) -> CGRect {
              return .zero
            }
            
            override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
              return []
            }
            
            override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
              return false
            }
          

          【讨论】:

          • 就我而言,它有效。使用 Swift 4 使用这些方法添加了 UITextField 的子类。谢谢!
          【解决方案13】:

          将 tintColor 设置为 Clear Color

          textfield.tintColor = [UIColor clearColor];
          

          您也可以从界面生成器中设置

          【讨论】:

          • 您刚刚复制了 2 年前的答案。
          • 对不起我的朋友,但我没有复制任何东西。
          • 这很有趣,“我的朋友”。您的答案看起来与 15 年 5 月 1 日 @oldman 的答案非常接近。你能告诉我你的有什么不同吗?
          • 如上所述,清除色调并不会阻止使用外部键盘 (iPad Pro) 的用户更改文本。
          • 专业用户可以为所欲为。他们是专业人士:他们知道自己在做什么;^)
          【解决方案14】:

          如果您喜欢更简洁 = 更少的代码,请使用界面生成器:

          (属性检查器,查看部分。)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-06
            • 2014-07-30
            • 1970-01-01
            • 1970-01-01
            • 2012-07-16
            • 2011-05-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多