【问题标题】:Detect moment when newline starts in UITextView检测 UITextView 中换行符开始的时刻
【发布时间】:2013-11-29 07:07:24
【问题描述】:

我尝试检测何时在 UITextView 中换行。我可以通过比较后总宽度与 UITextView 宽度来检测它:

CGSize size = [textView.text sizeWithAttributes:textView.typingAttributes];
if(size.width > textView.bounds.size.width)
      NSLog (@"New line");

但它不能正常工作,因为-sizeWithAttributes:textView 只返回没有缩进宽度的字母宽度。请帮忙解决这个问题。

【问题讨论】:

  • 这是您使用的标准UITextView,还是子类版本?
  • 抱歉,您想知道用户在输入时是否按了“回车”?或者您只想计算文本中换行符的总数?

标签: ios objective-c nsstring uitextview


【解决方案1】:

SWIFT 5

让事情不要过于复杂。

    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    if text == "\n" {
        // return pressed
    }
}

【讨论】:

    【解决方案2】:

    Swift-4@n00bProgrammer 的答案,更精确 换行检测。

    @n00bProgrammer 答案是完美的,除了当用户开始输入第一行时它的反应不同,它也显示Started New Line
    克服的问题,这里是精炼的代码

        var previousRect = CGRect.zero
        func textViewDidChange(_ textView: UITextView) {
            let pos = textView.endOfDocument
            let currentRect = textView.caretRect(for: pos)
            self.previousRect = self.previousRect.origin.y == 0.0 ? currentRect : self.previousRect
            if currentRect.origin.y > self.previousRect.origin.y {
                //new line reached, write your code
                print("Started New Line")
            }
            self.previousRect = currentRect
        }
    

    【讨论】:

      【解决方案3】:

      我会这样做:

      • 获取最后一个字符的UITextPosition
      • 在您的UITextView 上致电caretRectForPosition
      • 创建一个CGRect 变量并最初将CGRectZero 存储在其中。
      • 在您的textViewDidChange: 方法中,通过传递UITextPosition 来调用caretRectForPosition:
      • 将其与存储在CGRect 变量中的当前值进行比较。如果 caretRect 的新 y 原点大于最后一个,则表示已到达新行。

      示例代码:

      CGRect previousRect = CGRectZero;
      - (void)textViewDidChange:(UITextView *)textView{
      
          UITextPosition* pos = yourTextView.endOfDocument;//explore others like beginningOfDocument if you want to customize the behaviour
          CGRect currentRect = [yourTextView caretRectForPosition:pos];
      
          if (currentRect.origin.y > previousRect.origin.y){
                  //new line reached, write your code
              }
          previousRect = currentRect;
      
      }
      

      另外,您应该阅读UITextInput 协议参考here 的文档。我告诉你,这很神奇。

      如果您对此有任何其他问题,请告诉我。

      【讨论】:

      • @mriddi。我给了你一个骨架结构。您将必须根据需要添加条件。例如,在文本中间编辑代码,或者替换单词或字符。
      • 在某些情况下这不起作用。当用户粘贴文本并且插入符号位置在此过程中移动时怎么办?
      • 因此我提到必须添加条件
      • 请问有人可以帮我解决以下问题吗?如果用户在 UITextView 中写入项目符号文本(多个换行符),如何检测换行符的总数?
      • 如果 textView 的文本是以编程方式设置的,这会有帮助吗?
      【解决方案4】:

      SWIFT 4

      如果你不想使用previousRect。让我们试试这个:

      func textViewDidChange(_ textView: UITextView) {
          let pos = textView.endOfDocument
          let currentRect = textView.caretRect(for: pos)
          if (currentRect.origin.y == -1 || currentRect.origin.y == CGFloat.infinity){
             print("Yeah!, I've gone to a new line") 
             //-1 for new line with a char, infinity is new line with a space
          }
      }
      

      【讨论】:

      • 在这种情况下你会得到 currentRect.origin.y == -1 ??
      【解决方案5】:

      斯威夫特 3

      接受的答案和 swift 版本可以正常工作,但这里有一个 Swift 3 版本,适合那些懒惰的人。

      class CustomViewController: UIViewController, UITextViewDelegate {
      
          let textView = UITextView(frame: .zero)
          var previousRect = CGRect.zero
      
          override func viewDidLoad(){
              textView.frame = CGRect(
                  x: 20, 
                  y: 0, 
                  width: view.frame.width, 
                  height: 50
              )
              textView.delegate = self
              view.addSubview(textView)
          }
      
          func textViewDidChange(_ textView: UITextView) {
              let pos = textView.endOfDocument
              let currentRect = textView.caretRect(for: pos)
              if previousRect != CGRect.zero {
                  if currentRect.origin.y > previousRect.origin.y {
                      print("new line")
                  }
              }
              previousRect = currentRect
          }
      }
      

      【讨论】:

        【解决方案6】:

        对于 Swift 使用这个

        previousRect = CGRectZero
        
         func textViewDidChange(textView: UITextView) {
        
                var pos = textView.endOfDocument
                var currentRect = textView.caretRectForPosition(pos)
                if(currentRect.origin.y > previousRect?.origin.y){
                    //new line reached, write your code
                }
                previousRect = currentRect
        
            }
        

        【讨论】:

          【解决方案7】:

          你可以使用 UITextViewDelegate

          - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText: (NSString *)text
          {
               BOOL newLine = [text isEqualToString:@"\n"];
               if(newLine)
               {
                    NSLog(@"User started a new line");
               }
               return YES;
          }
          

          【讨论】:

          • 这应该是公认的答案。它是最优雅的。当前接受的答案非常hacky。
          • 这仅在用户按下回车键时有效,而不是在新行开始时有效,因为它到达了前一行的末尾。
          【解决方案8】:

          您需要获取文本的高度,而不是宽度。使用 sizeWithFont:constrainedToSize:lineBreakMode:(如果您需要支持 iOS 6 或更早版本)或使用 boundingRectWithSize:options:attributes:context: 如果您只支持 iOS 7。

          【讨论】:

          • 只有IOS7。请详细了解使用第二个
          • 查看文档。它类似于您使用的sizeWithAttributes: 方法。你只需要传递一个大小。传入具有所需宽度和非常大高度的尺寸。返回的大小将与宽度相同,但具有所需的高度以适合宽度中的文本。
          猜你喜欢
          • 2012-03-04
          • 1970-01-01
          • 2011-05-07
          • 2016-02-01
          • 1970-01-01
          • 2013-09-13
          • 1970-01-01
          • 1970-01-01
          • 2011-09-27
          相关资源
          最近更新 更多