限制UITextview的行数

发布于 2024-10-21 06:35:23 字数 210 浏览 2 评论 0原文

我想知道如何限制用户在编辑 UITextField 时可以输入的行数(不是其他问题中询问的字符数)。

理想情况下,我想将输入限制为最大值。 10 行。

我需要从哪里开始?我是否用某种方法来做到这一点?在

 - (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView

I was wondering how to limit the amount of LINES (not characters as asked in other questions) a user can enter when editing a UITextField.

Ideally, I would like to limit the input to max. 10 lines.

Where would I need to start? Do I do this with a method? In

 - (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

奶气 2024-10-28 06:35:23

Maciek Czarnik 的回答对我来说不起作用,但它让我了解了该怎么做。

iOS 7+

Swift

textView.textContainer.maximumNumberOfLines = 10
textView.textContainer.lineBreakMode = .byTruncatingTail

ObjC

textView.textContainer.maximumNumberOfLines = 10;
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;

Maciek Czarnik answer does not worked for me, but it got me insights what to do.

iOS 7+

Swift

textView.textContainer.maximumNumberOfLines = 10
textView.textContainer.lineBreakMode = .byTruncatingTail

ObjC

textView.textContainer.maximumNumberOfLines = 10;
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
梦在深巷 2024-10-28 06:35:23

也许这可以帮助(iOS 7+):

textView.textContainer.maximumNumberOfLines = 10;
[textView.layoutManager textContainerChangedGeometry:textView.textContainer];

我猜即使是第一行也应该能达到目的,但没有......也许它是 SDK 中的一个错误

Maybe this can help (iOS 7+):

textView.textContainer.maximumNumberOfLines = 10;
[textView.layoutManager textContainerChangedGeometry:textView.textContainer];

Even first line should do the trick I guess, but doesn't... Maybe its a bug in SDK

亚希 2024-10-28 06:35:23

你的想法是对的,但方法是错误的。每当文本要更改时,就会调用 textView:shouldChangeTextInRange:replacementText: ;您可以使用其 text 属性访问文本视图的当前内容,并且可以使用 [textView.text stringByReplacingCharactersInRange:range withString:replacementText 从传递的范围和替换文本构造新内容]。然后,您可以计算行数并返回“是”以允许更改,或返回“否”以拒绝更改。

You have the right idea, but the wrong method. textView:shouldChangeTextInRange:replacementText: is called whenever the text is going to change; you can access the current content of the text view using its text property, and you can construct the new content from the passed range and replacement text with [textView.text stringByReplacingCharactersInRange:range withString:replacementText]. You can then count the number of lines and return YES to allow the change or NO to reject it.

開玄 2024-10-28 06:35:23

在 Swift 3.0 版本中:

self.textView.textContainer.maximumNumberOfLines = self.textViewNumberOflines
self.textView.textContainer.lineBreakMode = .byTruncatingTail

in Swift 3.0 version:

self.textView.textContainer.maximumNumberOfLines = self.textViewNumberOflines
self.textView.textContainer.lineBreakMode = .byTruncatingTail
涙—继续流 2024-10-28 06:35:23

Maciek Czarnik 的答案似乎对我不起作用,即使在 iOS7 中也是如此。它给了我奇怪的行为,我不知道为什么。

我限制 UITextView 中行数的方法很简单:(

仅在 iOS7 中测试)在以下 UITextViewDelegate 方法中:

- (void)textViewDidChange:(UITextView *)textView
{
    NSUInteger maxNumberOfLines = 5;
    NSUInteger numLines = textView.contentSize.height/textView.font.lineHeight;
    if (numLines > maxNumberOfLines)
    {
        textView.text = [textView.text substringToIndex:textView.text.length - 1];
    }
}

Maciek Czarnik's answer does not seem to work for me, even in iOS7. It gives me strange behavior, I don't know why.

What I do to limit the number of lines in the UITextView is simply :

(tested only in iOS7) In the following UITextViewDelegate method :

- (void)textViewDidChange:(UITextView *)textView
{
    NSUInteger maxNumberOfLines = 5;
    NSUInteger numLines = textView.contentSize.height/textView.font.lineHeight;
    if (numLines > maxNumberOfLines)
    {
        textView.text = [textView.text substringToIndex:textView.text.length - 1];
    }
}
私藏温柔 2024-10-28 06:35:23

这是 Swift 4.2 / Swift 5 中 Numereyes 答案的改进版本,

我做了一些扩展,以便可以重用代码。
我正在使用 While 循环来检查尺寸是否合适。当用户一次粘贴大量文本时,这也适用。

extension UITextView {        
    var numberOfCurrentlyDisplayedLines: Int {
        let size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
        //for Swift <=4.0, replace with next line:
        //let size = systemLayoutSizeFitting(UILayoutFittingCompressedSize)

        return Int(((size.height - layoutMargins.top - layoutMargins.bottom) / font!.lineHeight))
    }

    /// Removes last characters until the given max. number of lines is reached
    func removeTextUntilSatisfying(maxNumberOfLines: Int) {
        while numberOfCurrentlyDisplayedLines > (maxNumberOfLines) {
            text = String(text.dropLast())
            layoutIfNeeded()
        }
    }
}

// Use it in UITextView's delegate method:
func textViewDidChange(_ textView: UITextView) {        
    textView.removeTextUntilSatisfying(maxNumberOfLines: 10)
}        

Here's a improved Version of Numereyes answer in Swift 4.2 / Swift 5

I made a little extension so I can reuse the code.
I'm using a While-Loop to check if the size fits. This also works when the user pastes a lot of text at once.

extension UITextView {        
    var numberOfCurrentlyDisplayedLines: Int {
        let size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
        //for Swift <=4.0, replace with next line:
        //let size = systemLayoutSizeFitting(UILayoutFittingCompressedSize)

        return Int(((size.height - layoutMargins.top - layoutMargins.bottom) / font!.lineHeight))
    }

    /// Removes last characters until the given max. number of lines is reached
    func removeTextUntilSatisfying(maxNumberOfLines: Int) {
        while numberOfCurrentlyDisplayedLines > (maxNumberOfLines) {
            text = String(text.dropLast())
            layoutIfNeeded()
        }
    }
}

// Use it in UITextView's delegate method:
func textViewDidChange(_ textView: UITextView) {        
    textView.removeTextUntilSatisfying(maxNumberOfLines: 10)
}        
口干舌燥 2024-10-28 06:35:23

Swift 4

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
    let newLines = text.components(separatedBy: CharacterSet.newlines)
    let linesAfterChange = existingLines.count + newLines.count - 1
    return linesAfterChange <= textView.textContainer.maximumNumberOfLines
}

如果您还想限制字符:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
        let newLines = text.components(separatedBy: CharacterSet.newlines)
        let linesAfterChange = existingLines.count + newLines.count - 1
        if(text == "\n") {
            return linesAfterChange <= textView.textContainer.maximumNumberOfLines
        }

        let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
        let numberOfChars = newText.count
        return numberOfChars <= 30 // 30 characters limit
    }
}

不要忘记在 viewDidLoad 中添加您希望限制的行数:

txtView.textContainer.maximumNumberOfLines = 2

Swift 4

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
    let newLines = text.components(separatedBy: CharacterSet.newlines)
    let linesAfterChange = existingLines.count + newLines.count - 1
    return linesAfterChange <= textView.textContainer.maximumNumberOfLines
}

And if you want to limit characters also:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
        let newLines = text.components(separatedBy: CharacterSet.newlines)
        let linesAfterChange = existingLines.count + newLines.count - 1
        if(text == "\n") {
            return linesAfterChange <= textView.textContainer.maximumNumberOfLines
        }

        let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
        let numberOfChars = newText.count
        return numberOfChars <= 30 // 30 characters limit
    }
}

don't forget to add how many lines you want the limit to be in viewDidLoad:

txtView.textContainer.maximumNumberOfLines = 2
贪了杯 2024-10-28 06:35:23

给出的其他解决方案不能解决与最后创建的最后一行(问题案例中的第 11 行)相关的问题。

这是一个使用 Swift 4.0 和 Swift 4.0 的可行解决方案。 Xcode 9.0 beta(位于 这篇博文

   class ViewController: UIViewController, UITextViewDelegate {

      @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
        textView.textContainer.maximumNumberOfLines = 10
        textView.textContainer.lineBreakMode = .byWordWrapping
      }

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

        let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
        let newLines = text.components(separatedBy: CharacterSet.newlines)
        let linesAfterChange = existingLines.count + newLines.count - 1

        return linesAfterChange <= textView.textContainer.maximumNumberOfLines
    }

注意:此解决方案无法处理最后一行太长而无法显示的情况(文本将隐藏在 UITextView 的最右侧)。

The other solutions given do not solve an issue related to a last line being created at the end (an 11th line in the question's case).

Here is a working solution with Swift 4.0 & Xcode 9.0 beta (found on this blog post)

   class ViewController: UIViewController, UITextViewDelegate {

      @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
        textView.textContainer.maximumNumberOfLines = 10
        textView.textContainer.lineBreakMode = .byWordWrapping
      }

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

        let existingLines = textView.text.components(separatedBy: CharacterSet.newlines)
        let newLines = text.components(separatedBy: CharacterSet.newlines)
        let linesAfterChange = existingLines.count + newLines.count - 1

        return linesAfterChange <= textView.textContainer.maximumNumberOfLines
    }

Nota bene: This solution does not handle the scenario where the last line is too long to display (text will be hidden on the far right side of the UITextView).

酒绊 2024-10-28 06:35:23

Swift 5.7、iOS 16

UITextView(或 UITextField)的 UIViewRepresentable 包装器中

func makeUIView(context: Context) -> UITextView {

    let textView = UITextView() // ..or MyCustomUITextView()

    // ..your existing makeUIView body here..

    // Limit to N = 3 visible (displayed) lines.
    textView.textContainer.maximumNumberOfLines = 3

    // When visible line count is exceeded typing can continue,
    // but what's entered will be truncated so hidden from view.
    textView.textContainer.lineBreakMode = .byTruncatingTail

    // ..or prevent further text entry when limit is hit.
    // See https://developer.apple.com/documentation/uikit/nslinebreakmode
    //textView.textContainer.lineBreakMode = .byClipping

    // Set delegate now that other changes are made.
    textView.delegate = self

    return textView
}

Swift 5.7, iOS 16

Inside your UIViewRepresentable wrapper for UITextView (or UITextField)

func makeUIView(context: Context) -> UITextView {

    let textView = UITextView() // ..or MyCustomUITextView()

    // ..your existing makeUIView body here..

    // Limit to N = 3 visible (displayed) lines.
    textView.textContainer.maximumNumberOfLines = 3

    // When visible line count is exceeded typing can continue,
    // but what's entered will be truncated so hidden from view.
    textView.textContainer.lineBreakMode = .byTruncatingTail

    // ..or prevent further text entry when limit is hit.
    // See https://developer.apple.com/documentation/uikit/nslinebreakmode
    //textView.textContainer.lineBreakMode = .byClipping

    // Set delegate now that other changes are made.
    textView.delegate = self

    return textView
}

椵侞 2024-10-28 06:35:23

与其他答案类似,但可以直接从情节提要使用,无需子类化:

extension UITextView {
    @IBInspectable var maxNumberOfLines: NSInteger {
        set {
            textContainer.maximumNumberOfLines = maxNumberOfLines
        }
        get {
            return textContainer.maximumNumberOfLines
        }
    }
    @IBInspectable var lineBreakByTruncatingTail: Bool {
        set {
            if lineBreakByTruncatingTail {
                textContainer.lineBreakMode = .byTruncatingTail
            }
        }
        get {
            return textContainer.lineBreakMode == .byTruncatingTail
        }
    }
}

Similar to other answers, but usable directly from Storyboard and without subclassing:

extension UITextView {
    @IBInspectable var maxNumberOfLines: NSInteger {
        set {
            textContainer.maximumNumberOfLines = maxNumberOfLines
        }
        get {
            return textContainer.maximumNumberOfLines
        }
    }
    @IBInspectable var lineBreakByTruncatingTail: Bool {
        set {
            if lineBreakByTruncatingTail {
                textContainer.lineBreakMode = .byTruncatingTail
            }
        }
        get {
            return textContainer.lineBreakMode == .byTruncatingTail
        }
    }
}
白况 2024-10-28 06:35:23

请参阅 APPLE 文档:计算文本行数 https ://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextLayout/Tasks/CountLines.html

    - (void)textViewDidChangeSelection:(UITextView *)textView{
NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index, numberOfGlyphs =
(unsigned)[layoutManager numberOfGlyphs];
NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
    (void) [layoutManager lineFragmentRectForGlyphAtIndex:index
            effectiveRange:&lineRange];
    index = (unsigned)NSMaxRange(lineRange);
}
if(numberOfLines > 10){
    self.textField.text = self.lastString;
}

}

处理“\n”

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if([text containsString:@"\n"]){
    NSLayoutManager *layoutManager = [textView layoutManager];
    unsigned numberOfLines, index, numberOfGlyphs =
            (unsigned)[layoutManager numberOfGlyphs];
    NSRange lineRange;
    for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
        (void) [layoutManager lineFragmentRectForGlyphAtIndex:index
                effectiveRange:&lineRange];
        index = (unsigned)NSMaxRange(lineRange);
    }
    NSLog(@"lines = %d",numberOfLines);
    if(numberOfLines >= 10){
        return NO;
    }
}
self.lastString = textView.text;

return YES;

}

Refer to APPLE documentation: Counting Lines of Text https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextLayout/Tasks/CountLines.html

    - (void)textViewDidChangeSelection:(UITextView *)textView{
NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index, numberOfGlyphs =
(unsigned)[layoutManager numberOfGlyphs];
NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
    (void) [layoutManager lineFragmentRectForGlyphAtIndex:index
            effectiveRange:&lineRange];
    index = (unsigned)NSMaxRange(lineRange);
}
if(numberOfLines > 10){
    self.textField.text = self.lastString;
}

}

handle "\n"

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if([text containsString:@"\n"]){
    NSLayoutManager *layoutManager = [textView layoutManager];
    unsigned numberOfLines, index, numberOfGlyphs =
            (unsigned)[layoutManager numberOfGlyphs];
    NSRange lineRange;
    for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
        (void) [layoutManager lineFragmentRectForGlyphAtIndex:index
                effectiveRange:&lineRange];
        index = (unsigned)NSMaxRange(lineRange);
    }
    NSLog(@"lines = %d",numberOfLines);
    if(numberOfLines >= 10){
        return NO;
    }
}
self.lastString = textView.text;

return YES;

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文