programing

UI 텍스트 보기의 줄 수 제한

css3 2023. 8. 13. 09:54

UI 텍스트 보기의 줄 수 제한

사용자가 UI 텍스트 필드를 편집할 때 입력할 수 있는 라인 수를 제한하는 방법이 궁금합니다.

이상적으로는 입력을 최대 10줄로 제한하고 싶습니다.

어디서부터 시작해야 합니까?이거 메소드로 하는 거예요? 인.

 - (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView

Maciek Czarnik의 대답은 저에게 효과가 없었지만, 무엇을 해야 하는지에 대한 통찰력을 얻었습니다.

iOS 7+

스위프트

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

ObjC

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

이것이 도움이 될 수도 있습니다(iOS 7+).

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

제 생각엔 첫 번째 라인도 그렇게 해야 할 것 같은데, 그렇지 않아요...아마도 SDK의 버그일 것입니다.

당신 생각은 맞지만 방법은 틀렸습니다.textView:shouldChangeTextInRange:replacementText:텍스트가 변경될 때마다 호출됩니다. 텍스트 보기의 현재 내용에 액세스할 수 있습니다.text속성을 사용하여 전달된 범위와 대체 텍스트에서 새 내용을 구성할 수 있습니다.[textView.text stringByReplacingCharactersInRange:range withString:replacementText]그런 다음 줄 수를 세고 YES를 반환하여 변경을 허용하거나 NO를 거부할 수 있습니다.

Swift 3.0버전:

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

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];
    }
}

Swift 4.2 / Swift 5에서 Numereyes 답변의 개선된 버전입니다.

코드를 재사용할 수 있도록 약간의 확장을 했습니다.사이즈가 맞는지 확인하기 위해 While-Loop을 사용하고 있습니다.이것은 사용자가 한 번에 많은 텍스트를 붙여넣을 때도 작동합니다.

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)
}        

스위프트 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

주어진 다른 솔루션은 마지막에 작성되는 마지막 줄(질문의 경우 11번째 줄)과 관련된 문제를 해결하지 못합니다.

다음은 사용 가능한 솔루션입니다.Swift 4.0Xcode 9.0 베타(이 블로그 게시물에서 찾을 수 있음)

   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의 맨 오른쪽에 텍스트가 숨겨져 있음).

다른 답변과 비슷하지만, 스토리보드에서 직접 사용할 수 있으며 하위 분류 없이 사용할 수 있습니다.

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
        }
    }
}

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;

}

스위프트 5.7, iOS 16

의 용자내 에.UIViewRepresentable의 .UITextView(또는)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
}

언급URL : https://stackoverflow.com/questions/5225763/limit-the-number-of-lines-for-uitextview