54 votes

UITextView dans iOS7 coupe la dernière ligne de chaîne de texte

UITextView dans iOS7 a été vraiment bizarre. À mesure que vous tapez et entrent dans la dernière ligne de votre UITextView, le défilement de la vue n'est pas faites défiler vers le bas comme il se doit et il provoque le texte à être "coupées". J'ai essayé de réglage c'est clipsToBound propriété, mais il reste des clips le texte.

Je ne veux pas l'appeler sur "setContentOffset:animation" parce que de un: c'est très hacky solution.. deuxièmement: si le curseur est au milieu (à la verticale) de notre textview, il va entrainer de défilement.

Voici une capture d'écran.

enter image description here

Toute aide serait grandement appréciée!

Merci!

93voto

davidisdk Points 1828

Le problème est dû à iOS 7. Dans le délégué de la vue texte, ajoutez ce code:

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

21voto

gmyers Points 51

La solution que j'ai trouvé ici a été d'ajouter une ligne de correction après vous créez un UITextView:

self.textview.layoutManager.allowsNonContiguousLayout = NO;

Cette ligne fixe trois questions , j'ai eu la création d'un UITextView base de l'éditeur de code avec la coloration syntaxique sur iOS7:

  1. Le défilement de conserver le texte dans la vue lors de l'édition (la question de ce post)
  2. UITextView parfois à sauter partout après avoir fait disparaître le clavier
  3. UITextView aléatoire défilement des sauts lors de la tentative de faire défiler la vue

Remarque, je n'ai redimensionner la UITextView lorsque le clavier est affiché/caché.

6voto

chris Points 6000

Essayez d'implémenter la méthode -textViewDidChangeSelection: delegate à partir de UITextViewDelegate comme ceci:

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

2voto

cnotethegr8 Points 984

Voici une version modifiée de la réponse sélectionnée par 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];
    }
}
 

J'avais un bogue qui disait que lorsque la taille du contenu de textView était plus grande que les limites et que le curseur était hors écran (par exemple, en utilisant un clavier et en appuyant sur la touche fléchée), textView ne s'animait pas avec le texte inséré.

1voto

Wirsing Points 556

À mon humble avis c'est la réponse définitive pour l'ensemble de la typique UITextView défilement / clavier des questions liées à l'iOS 7. Son propre, il est facile à lire, facile à utiliser, facile à entretenir et peuvent être facilement réutilisées.

L'astuce de base: Simplement changer la taille de la UITextView, pas le contenu de l'encart!

Voici un exemple pratique. Il prend pour acquis que vous avez une PLUME/Storyboard à base de UIViewController à l'aide de mise en page automatique et le UITextView remplit l'ensemble de la vue racine dans la UIViewController. Si non, vous devrez adapter la façon dont vous modifiez le textViewBottomSpaceConstraint à vos besoins.

Comment:


Ajouter ces propriétés:

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

Connectez le textViewBottomSpaceConstraint dans Interface Builder (ne pas oublier!)

Puis dans le 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];

Ajouter ces méthodes pour gérer le Clavier de redimensionnement (grâce à https://github.com/brennanMKE/Interfaces/tree/master/Keyboarding - ces méthodes sont par 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;
}

Enfin, ajoutez ces méthodes pour faire réagir le clavier de notifications et de redimensionner la 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) {

    }];
}

Également ajouter ces méthodes pour faire défiler automatiquement à l'endroit où l'utilisateur a cliqué

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X