Nice programing

iOS7의 UITextView는 텍스트 문자열의 마지막 줄을 자릅니다.

nicepro 2021. 1. 10. 19:57
반응형

iOS7의 UITextView는 텍스트 문자열의 마지막 줄을 자릅니다.


iOS7의 UITextView는 정말 이상했습니다. UITextView의 마지막 줄을 입력하고 입력 할 때 스크롤보기가 예상대로 아래쪽으로 스크롤되지 않고 텍스트가 "잘립니다". clipsToBound 속성을 NO로 설정하려고 시도했지만 여전히 텍스트를 자릅니다.

나는 "setContentOffset : animated"를 호출하고 싶지 않습니다. 왜냐하면 하나는 매우 엉뚱한 솔루션입니다. 둘째, 커서가 텍스트 뷰의 중간 (수직)에 있으면 원하지 않는 스크롤이 발생합니다.

다음은 스크린 샷입니다.

여기에 이미지 설명 입력

어떤 도움이라도 대단히 감사하겠습니다!

감사!


문제는 iOS 7 때문입니다. 텍스트보기 대리자에 다음 코드를 추가합니다.

- (void)textViewDidChange:(UITextView *)textView {
    CGRect line = [textView caretRectForPosition:
        textView.selectedTextRange.start];
    CGFloat overflow = line.origin.y + line.size.height
        - ( textView.contentOffset.y + textView.bounds.size.height
        - textView.contentInset.bottom - textView.contentInset.top );
    if ( overflow > 0 ) {
        // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
        // Scroll caret to visible area
        CGPoint offset = textView.contentOffset;
        offset.y += overflow + 7; // leave 7 pixels margin
        // Cannot animate with setContentOffset:animated: or caret will not appear
        [UIView animateWithDuration:.2 animations:^{
            [textView setContentOffset:offset];
        }];
    }
}

내가 찾은 해결책 여기가 당신이 UITextView를 만든 후 한 줄 수정을 추가했다 :

self.textview.layoutManager.allowsNonContiguousLayout = NO;

이 한 줄 은 iOS7에서 구문 강조 표시를 사용하여 UITextView 기반 코드 편집기를 만드는 세 가지 문제를 해결했습니다 .

  1. 편집 할 때 텍스트를 계속 볼 수 있도록 스크롤 (이 게시물의 문제)
  2. UITextView가 키보드를 닫은 후 가끔 점프
  3. 보기를 스크롤하려고 할 때 UITextView 임의 스크롤 점프

참고로 키보드가 표시되거나 숨겨 질 때 전체 UITextView의 크기를 조정했습니다.


다음 -textViewDidChangeSelection:과 같이 UITextViewDelegate에서 delegate 메소드를 구현해보십시오 .

-(void)textViewDidChangeSelection:(UITextView *)textView {
    [textView scrollRangeToVisible:textView.selectedRange];
}

다음은 davidisdk가 선택한 답변의 수정 된 버전입니다.

- (void)textViewDidChange:(UITextView *)textView {
    NSRange selection = textView.selectedRange;

    if (selection.location + selection.length == [textView.text length]) {
        CGRect caretRect = [textView caretRectForPosition:textView.selectedTextRange.start];
        CGFloat overflow = caretRect.origin.y + caretRect.size.height - (textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top);

        if (overflow > 0.0f) {
            CGPoint offset = textView.contentOffset;
            offset.y += overflow + 7.0f;

            [UIView animateWithDuration:0.2f animations:^{
                [textView setContentOffset:offset];
            }];
        }
    } else {
        [textView scrollRangeToVisible:selection];
    }
}

textView의 콘텐츠 크기가 경계보다 크고 커서가 화면에서 벗어난 경우 (예 : 키보드 사용 및 화살표 키 누르기) textView가 삽입되는 텍스트에 애니메이션이 적용되지 않는 버그가 발생했습니다.


Imho 이것은 iOS 7의 모든 일반적인 UITextView 스크롤 / 키보드 관련 문제에 대한 확실한 대답 입니다. 깔끔하고 읽기 쉽고 사용하기 쉽고 유지 관리가 쉽고 쉽게 재사용 할 수 있습니다.

기본 트릭 : 콘텐츠 삽입이 아닌 UITextView의 크기를 변경하기 만하면됩니다!

다음은 실습 예제입니다. Autolayout을 사용하는 NIB / Storyboard 기반 UIViewController가 있고 UITextView가 UIViewController에서 전체 루트 뷰를 채운다는 것은 당연한 일입니다. 그렇지 않은 경우 필요에 맞게 textViewBottomSpaceConstraint를 변경하는 방법을 조정해야합니다.

어떻게:


다음 속성을 추가합니다.

@property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewBottomSpaceConstraint;
@property (nonatomic) CGFloat textViewBottomSpaceConstraintFromNIB;

Interface Builder에서 textViewBottomSpaceConstraint를 연결하십시오 ( 잊지 마세요! ).

그런 다음 viewDidLoad에서 :

// Save the state of the UITextView's bottom constraint as set up in your NIB/Storyboard
self.textViewBottomSpaceConstraintFromNIB = self.textViewBottomSpaceConstraint.constant;

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShowNotification:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHideNotification:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

다음 메서드를 추가하여 키보드 크기 조정을 처리합니다 ( https://github.com/brennanMKE/Interfaces/tree/master/Keyboarding 덕분에 -이 메서드는 brennan에서 제공합니다!).

- (void)keyboardWillShowNotification:(NSNotification *)notification {
    CGFloat height = [self getKeyboardHeight:notification forBeginning:TRUE];
    NSTimeInterval duration = [self getDuration:notification];
    UIViewAnimationOptions curve = [self getAnimationCurve:notification];

    [self keyboardWillShowWithHeight:height duration:duration curve:curve];
}

- (void)keyboardWillHideNotification:(NSNotification *)notification {
    CGFloat height = [self getKeyboardHeight:notification forBeginning:FALSE];
    NSTimeInterval duration = [self getDuration:notification];
    UIViewAnimationOptions curve = [self getAnimationCurve:notification];

    [self keyboardWillHideWithHeight:height duration:duration curve:curve];
}

- (NSTimeInterval)getDuration:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval duration;

    NSValue *durationValue = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    [durationValue getValue:&duration];

    return duration;
}

- (CGFloat)getKeyboardHeight:(NSNotification *)notification forBeginning:(BOOL)forBeginning {
    NSDictionary *info = [notification userInfo];

    CGFloat keyboardHeight;

    NSValue *boundsValue = nil;
    if (forBeginning) {
        boundsValue = [info valueForKey:UIKeyboardFrameBeginUserInfoKey];
    }
    else {
        boundsValue = [info valueForKey:UIKeyboardFrameEndUserInfoKey];
    }

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    if (UIDeviceOrientationIsLandscape(orientation)) {
        keyboardHeight = [boundsValue CGRectValue].size.width;
    }
    else {
        keyboardHeight = [boundsValue CGRectValue].size.height;
    }

    return keyboardHeight;
}

- (UIViewAnimationOptions)getAnimationCurve:(NSNotification *)notification {
    UIViewAnimationCurve curve = [[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];

    switch (curve) {
        case UIViewAnimationCurveEaseInOut:
            return UIViewAnimationOptionCurveEaseInOut;
            break;
        case UIViewAnimationCurveEaseIn:
            return UIViewAnimationOptionCurveEaseIn;
            break;
        case UIViewAnimationCurveEaseOut:
            return UIViewAnimationOptionCurveEaseOut;
            break;
        case UIViewAnimationCurveLinear:
            return UIViewAnimationOptionCurveLinear;
            break;
    }

    return kNilOptions;
}

마지막으로, 키보드 알림에 반응하는 이러한 메서드를 추가하고 UITextView의 크기를 조정합니다.

- (void)keyboardWillShowWithHeight:(CGFloat)height duration:(CGFloat)duration curve:(UIViewAnimationOptions)curve
{
    CGFloat correctionMargin = 15; // you can experiment with this margin so the bottom text view line is not flush against the keyboard which doesn't look nice
    self.textViewBottomSpaceConstraint.constant = height + correctionMargin;

    [self.view setNeedsUpdateConstraints];

    [UIView animateWithDuration:duration delay:0 options:curve animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {

    }];
}

- (void)keyboardWillHideWithHeight:(CGFloat)height duration:(CGFloat)duration curve:(UIViewAnimationOptions)curve
{
    self.textViewBottomSpaceConstraint.constant = self.textViewBottomSpaceConstraintFromNIB;

    [self.view setNeedsUpdateConstraints];

    [UIView animateWithDuration:duration delay:0 options:curve animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {

    }];
}

또한 이러한 메서드를 추가하여 사용자가 클릭 한 위치로 자동으로 스크롤합니다.

- (void)textViewDidBeginEditing:(UITextView *)textView
{
    [textView scrollRangeToVisible:textView.selectedRange];
}

- (void)textViewDidChangeSelection:(UITextView *)textView
{
    [textView scrollRangeToVisible:textView.selectedRange];
}

textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);

이것은 또한 당신의 문제를 해결할 것입니다


StoryBoard를 사용하는 경우 AutoLayout을 켜고 (기본적으로) UITextView에 대한 상단 / 하단 제약 조건을 설정하지 않은 경우에도이 동작이 발생할 수 있습니다. 파일 검사기를 확인하여 AutoLayout 상태를 확인하십시오.


다음은 davididsk의 가장 우수한 솔루션의 MonoTouch 버전입니다 (위에서).

TextView.SelectionChanged += (object sender, EventArgs e) => {
                TextView.ScrollRangeToVisible(TextView.SelectedRange);
            };


            TextView.Changed += (object sender, EventArgs e) => {

                CGRect line = TextView.GetCaretRectForPosition(TextView.SelectedTextRange.Start);
                nfloat overflow = line.Y + line.Height - 
                                     (TextView.ContentOffset.Y + 
                                      TextView.Bounds.Height -          
                                      TextView.ContentInset.Bottom -
                                      TextView.ContentInset.Top );
                if ( overflow > 0 ) 
                {
                    // We are at the bottom of the visible text and introduced 
                    // a line feed, scroll down (iOS 7 does not do it)
                    // Scroll caret to visible area
                    CGPoint offset = TextView.ContentOffset;
                    offset.Y+= overflow + 7; // leave 7 pixels margin
                    // Cannot animate with setContentOffset:animated: 
                    // or caret will not appear
                    UIView.Animate(0.1,()=> {
                        TextView.ContentOffset = offset;
                    });
                }
            };

이 줄은 마지막 텍스트 줄이 표시되지 않도록합니다.

textView.scrollEnabled = false

이것을 제거하고 무슨 일이 일어나는지보십시오 ...


   textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

이것은 나를 위해 문제를 해결했습니다.


.m에서 theViewDelegate를 "self"로 설정하고 .h에서 사용한 다음이 코드를 .m에 추가하십시오.

텍스트가있는 다음 줄로 이동 (래핑 또는 캐리지 리턴) 및 타이핑하기 위해 발생하는이 결함의 버전을 모두 처리합니다. 그리고 캐리지 리턴 만 있고 타이핑없이 다음 줄로 이동합니다 (다른 코드와 달리이 코드는 이 두 번째 글리치 시나리오에서 잘리지 않는 깜박이는 커서를 표시하기 위해 스크롤됩니다.)

//!!!*!!****!*!**!*!*!!!MAKE SURE YOU SET DELEGATE AND USE THE <UITEXTVIEWDELEGATE>

-(void)textViewDidChange:(UITextView *)textView {
    [theTextView scrollRangeToVisible:[textView selectedRange]];//resizing textView frame causes text itself "content frame?" to still go below the textview frame and get clipped... auto-scrolling must be implimented. (iOS7 bug)
}

-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if (([text isEqualToString:@"\n"]) && (range.location == textView.text.length)) {//"return" at end of textView
        [textView scrollRectToVisible:CGRectMake(5,5,5,999999999999999999) animated:NO];//for some reason the textViewDidChange auto scrolling doesnt work with a carriage return at the end of your textView... so I manually set it INSANELY low (NOT ANIMATED) here so that it automagically bounces back to the proper position before interface refreshes when textViewDidChange is called after this.
    }
    return YES;
}

참조 URL : https://stackoverflow.com/questions/18966675/uitextview-in-ios7-clips-the-last-line-of-text-string

반응형