UITextView dans iOS7 a été vraiment bizarre. Lorsque vous tapez et entrez la dernière ligne de votre UITextView, la vue de défilement ne défile pas vers le bas comme elle le devrait et elle provoque le "découpage" du texte. J'ai essayé de définir sa propriété clipsToBound sur NO, mais elle coupe toujours le texte.
Je ne veux pas appeler "setContentOffset: animated" parce que pour un: c'est une solution très hacky .. deuxièmement: si le curseur était au milieu (verticalement) de notre affichage de texte, cela provoquera un défilement indésirable.
Voici une capture d'écran.
Toute aide serait grandement appréciée!
Merci!
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];
}];
}
}
La solution que j'ai trouvée ici était d'ajouter un correctif d'une ligne après avoir créé un UITextView:
self.textview.layoutManager.allowsNonContiguousLayout = NO;
Cette ligne fixe trois problèmes J'ai dû créer un éditeur de code basé sur UITextView avec mise en évidence de la syntaxe sur iOS7:
Remarque, j'ai redimensionné l'ensemble de UITextView lorsque le clavier est affiché/masqué.
Essayez d'implémenter le -textViewDidChangeSelection:
méthode déléguée de UITextViewDelegate comme ceci:
-(void)textViewDidChangeSelection:(UITextView *)textView {
[textView scrollRangeToVisible:textView.selectedRange];
}
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'obtenais un bogue selon lequel lorsque la taille du contenu de textView est plus grande que les limites et que le curseur est hors écran (comme utiliser un clavier et appuyer sur la touche fléchée), textView ne s'animerait pas avec le texte inséré.
À mon humble avis, c'est la réponse définitive à tous les problèmes typiques liés au défilement/au clavier UITextView dans iOS 7. C'est propre, facile à lire, facile à utiliser, facile à entretenir et peut être facilement réutilisé.
L'astuce de base: Modifiez simplement la taille de l'UITextView, pas l'encart de contenu!
Voici un exemple pratique. Il est évident que vous disposez d'un UIViewController basé sur NIB/Storyboard utilisant Autolayout et UITextView remplit l'intégralité de la vue racine dans UIViewController. Sinon, vous devrez adapter la façon dont vous modifiez textViewBottomSpaceConstraint à vos besoins.
Comment:
Ajoutez ces propriétés:
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewBottomSpaceConstraint;
@property (nonatomic) CGFloat textViewBottomSpaceConstraintFromNIB;
Connectez le textViewBottomSpaceConstraint dans Interface Builder ( n'oubliez pas! )
Puis dans 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];
Ajoutez ces méthodes pour gérer le redimensionnement du clavier (grâce à https://github.com/brennanMKE/Interfaces/tree/master/Keyboarding - ces méthodes sont de 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 réagir aux notifications du clavier et redimensionnez l'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) {
}];
}
Ajoutez également ces méthodes pour faire défiler automatiquement où l'utilisateur a cliqué
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[textView scrollRangeToVisible:textView.selectedRange];
}
- (void)textViewDidChangeSelection:(UITextView *)textView
{
[textView scrollRangeToVisible:textView.selectedRange];
}
Si vous utilisez StoryBoard, ce comportement peut également se produire si vous avez laissé AutoLayout activé (comme c'est le cas par défaut) et n'avez pas défini de contraintes haut/bas pour votre UITextView. Vérifiez l'inspecteur de fichiers pour voir votre statut de mise en page automatique ...
Voici la version MonoTouch de la meilleure solution de davididsk (vue d'en haut).
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;
});
}
};
Cette ligne empêche la dernière ligne de texte de s'afficher pour moi:
textView.scrollEnabled = false
Essayez de supprimer cela et voyez ce qui se passe ...
textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);
Cela permettra également de résoudre votre problème