ios 计算 UITextView 中的行数,按帧大小包装的行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5837348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:46:02  来源:igfitidea点击:

Counting the number of lines in a UITextView, lines wrapped by frame size

iosobjective-ccocoa-touchuitextview

提问by Abhinav

I wanted to know when a text is wrapped by the frame of the text view is there any delimiter with which we can identify whether the text is wrapped or not.

我想知道当文本被文本视图的框架包裹时,是否有任何分隔符可以识别文本是否被包裹。

For instance if my text view has a width of 50 px and text is exceeding that, it wraps the text to next line.

例如,如果我的文本视图的宽度为 50 像素并且文本超过了该宽度,它会将文本换行到下一行。

I wanted to count the number of lines in my text view. Now "\n" and "\r" are not helping me.

我想计算文本视图中的行数。现在 "\n" 和 "\r" 没有帮助我。

My code is:

我的代码是:

NSCharacterSet *aCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r"];
    NSArray *myArray = [textViewText componentsSeparatedByCharactersInSet:aCharacterSet];
    NSLog(@"%d",[myArray count]);

回答by Himanshu padia

You need to use the lineHeightproperty, and font lineHeight:

您需要使用lineHeight属性和字体lineHeight

Objective-C

目标-C

int numLines = txtview.contentSize.height / txtview.font.lineHeight;

Swift

迅速

let numLines = (txtview.contentSize.height / txtview.font.lineHeight) as? Int

I am getting correct number of lines, hope it help you also.

我得到了正确的行数,希望它也能帮助你。

回答by Jano

This variation takes into account how you wrap your lines and the max size of the UITextView, and may output a more precise height. For example, if the text doesn't fit it will truncate to the visible size, and if you wrap whole words (which is the default) it may result in more lines than if you do otherwise.

这种变化考虑了您如何包装线条和 的最大尺寸UITextView,并且可能会输出更精确的高度。例如,如果文本不适合,它将被截断为可见大小,并且如果您将整个单词(这是默认设置)换行,则可能会导致比其他情况下更多的行。

UIFont *font = [UIFont boldSystemFontOfSize:11.0];
CGSize size = [string sizeWithFont:font 
                      constrainedToSize:myUITextView.frame.size 
                      lineBreakMode:UILineBreakModeWordWrap]; // default mode
float numberOfLines = size.height / font.lineHeight;

回答by castillejoale

Swift 3:

斯威夫特 3:

let layoutManager:NSLayoutManager = textView.layoutManager
let numberOfGlyphs = layoutManager.numberOfGlyphs
var numberOfLines = 0
var index = 0
var lineRange:NSRange = NSRange()

while (index < numberOfGlyphs) {
    layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
    index = NSMaxRange(lineRange);
    numberOfLines = numberOfLines + 1
}

print(numberOfLines)

回答by Juan Boero

Swift extension:

快速扩展:

Using @himanshu padia answer

使用@himanshu padia 答案

//MARK: - UITextView
extension UITextView{

    func numberOfLines() -> Int{
        if let fontUnwrapped = self.font{
            return Int(self.contentSize.height / fontUnwrapped.lineHeight)
        }
        return 0
    }

}

Usage : yourTextView.numberOfLines()

用法 : yourTextView.numberOfLines()

be aware that if for some reason the font of the text view is nil, the return will be zero.

请注意,如果由于某种原因文本视图的字体为零,则返回值将为零。

回答by Luke Chase

I found the perfect solution to this problem in Apple's Text Layout Programming Guide. Here is the solution Apple provides:

我在 Apple 的Text Layout Programming Guide 中找到了这个问题的完美解决方案。这是Apple提供的解决方案:

NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index;
unsigned numberOfGlyphs = [layoutManager numberOfGlyphs];
NSRange lineRange;

for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
    (void) [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&lineRange];
    index = NSMaxRange(lineRange);
}

This could easily be written into an extension for UITextView, or as a standalone method taking in a UITextView object as a parameter

这可以很容易地写入 UITextView 的扩展中,或者作为将 UITextView 对象作为参数的独立方法

回答by Yeesha

Swift 4version of Luke Chase'sanswer

Swift 4版本的Luke Chase 的答案

let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
var index = 0, numberOfLines = 0
var lineRange = NSRange(location: NSNotFound, length: 0)

while index < numberOfGlyphs {
  textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
  index = NSMaxRange(lineRange)
  numberOfLines += 1
}

回答by Hymany

You need to consider textView.textContainerInset, also need to round the calculated value since line number definitely is an integer

您需要考虑 textView.textContainerInset,还需要对计算值进行四舍五入,因为行号肯定是整数

float rawLineNumber = (textView.contentSize.height - textView.textContainerInset.top - textView.textContainerInset.bottom) / textView.font.lineHeight;
int finalLineNumber = round(rawLineNumber)

In real case, you may see following result rawLineNumber = 3.008099 finalLineNumber = 3 (3 lines)

在实际情况下,您可能会看到以下结果 rawLineNumber = 3.008099 finalLineNumber = 3 (3 行)

回答by Max

Use this (where _text_v is your text view):

使用这个(其中 _text_v 是你的文本视图):

-(NSInteger) linesCount {
    return _text_v.contentSize.height/_text_v.font.lineHeight;
}

回答by Softlabsindia

   func numberOfLines(textView: UITextView) -> Int {
    let layoutManager = textView.layoutManager
    let numberOfGlyphs = layoutManager.numberOfGlyphs
    var lineRange: NSRange = NSMakeRange(0, 1)
    var index = 0
    var numberOfLines = 0

    while index < numberOfGlyphs {
        layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
        numberOfLines += 1
    }
    return numberOfLines
}

Working Fine for me

对我来说工作得很好

回答by Franc

I spent a lot of time trying to calculate in real time the number of lines for an input TextView (say a chat text entry box) and the only solution that works in such a case is Luke Chase's (for some reason the frame.height approach appears to update only ever 3rd or fourth letter typed into a textView and so is not accurate).

我花了很多时间尝试实时计算输入 TextView 的行数(比如聊天文本输入框),在这种情况下唯一有效的解决方案是 Luke Chase 的(出于某种原因,frame.height 方法)似乎只更新输入到 textView 中的第三个或第四个字母,因此不准确)。

As a commenter mentioned however, there is a small bug in which a user generated line breaks ("\n" or keyboard return press) are not properly accounted for. Even stranger, it only "misses" the first such line-break, any subsequent ones are correctly captured (say you go to the line 4 times it will return only 3 lines clearly missing the first line break).

然而,正如评论者所提到的,存在一个小错误,即用户生成的换行符(“\n”或键盘回车键)没有得到正确考虑。更奇怪的是,它只“错过”了第一个这样的换行符,任何后续的换行符都被正确捕获(假设你去 4 次该行,它只会返回 3 行,显然缺少第一个换行符)。

So to go around that bug I simple look record the first such line-break (character "\n") and manually add a line to the # of lines that the gliph method returns.

所以为了解决这个错误,我简单地记录下第一个这样的换行符(字符“\n”),然后手动添加一行到 gliph 方法返回的行数。

In code that gives:

在给出的代码中:

    func offSetTableViewIfNeeded() {
    let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
    var index : Int = 0
    var lineRange = NSRange(location: NSNotFound, length: 0)
    var currentNumOfLines : Int = 0
    var numberOfParagraphJump : Int = 0

    while index < numberOfGlyphs {
        textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
        currentNumOfLines += 1

        // Observing whether user went to line and if it's the first such line break, accounting for it.
        if textView.text.last == "\n", numberOfParagraphJump == 0 {
            numberOfParagraphJump = 1
        }
    }

    currentNumOfLines += numberOfParagraphJump

    print("Number of lines is:", currentNumOfLines)

Hope this helps others who've been struggling with the super weird behavior of input textView (can't understand why Apple does not provide a # of line method out of the box!).

希望这可以帮助那些一直在为输入 textView 的超级奇怪行为而苦苦挣扎的其他人(无法理解为什么 Apple 不提供开箱即用的 # of line 方法!)。