2014-05-16 4 views
0

J'implémente un autogrowingUITextView. Je vise un comportement similaire de la boîte de message dans WhatsApp, qui s'autogrows lorsque votre texte a plus de 1 ligne.Animer le redimensionnement UITextView en utilisant la mise en page automatique

J'utilise l'approche décrite ci-dessous qui stocke la contrainte de hauteur dans une sous-classe UITextView et la modifie lorsque le texte change.

Ma solution s'anime correctement lorsque j'appuie sur la touche et que j'entre la touche dans le TextView, mais cela ne fonctionne pas lorsque je tape à la fin de la ligne. Dans ce cas, il change juste la taille instantanément.

L'exécution de l'animation sur le délégué méthode - (void)textViewDidChange:(UITextView *)textView produit le même résultat. Comment puis-je animer correctement la hauteur de TextView à l'aide du système de mise en page automatique?

Je suis la mise en œuvre comme ceci:

@interface OEAutoGrowingTextView() 

@property (strong, nonatomic) NSLayoutConstraint *heightConstraint; 

@end 


@implementation OEAutoGrowingTextView 

- (id)initWithFrame:(CGRect)frame 
{ 
    if (!(self = [super initWithFrame:frame])) 
    { 
     return nil; 
    } 

    [self commonInit]; 

    return self; 
} 

- (void)awakeFromNib 
{ 
    [self commonInit]; 
} 

- (void)commonInit 
{ 
    // If we are using auto layouts, than get a handler to the height constraint. 
    for (NSLayoutConstraint *constraint in self.constraints) 
    { 
     if (constraint.firstAttribute == NSLayoutAttributeHeight) 
     { 
      self.heightConstraint = constraint; 
      break; 
     } 
    } 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:self]; 
} 

- (void)dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

- (void)textDidChange:(NSNotification *)notification 
{ 
    self.heightConstraint.constant = self.contentSize.height; 
    [UIView animateWithDuration:1.0f animations:^ 
    { 
     [self layoutIfNeeded]; 
    }]; 
} 

@end 

Note: faire ce qui suit ne permet pas.

- (void)textDidChange:(NSNotification *)notification 
{ 
    self.heightConstraint.constant = self.contentSize.height; 
    [UIView animateWithDuration:1.0f animations:^ 
    { 
     [self layoutIfNeeded]; 
     for (UIView *view in self.subviews) 
     { 
      [view layoutIfNeeded]; 
     } 
    }]; 
} 

nouvelle mise à jour: Cela semble être un bug dans iOS 7.x, je pense qu'il est fixé sur iOS 8.0.

Répondre

1

Ok, la question est que de iOS 7, .contentSize n'est pas correct pour UITextViews. J'ai cette fonctionnalité, et vous devez calculer le contentSize vous-même. J'ai ajouté une méthode de catégorie à UITextView, -contentHeight, et l'utilise à la place pour calculer contentSize.

Voir ces deux liens.

UITextView Content Size

SO on the same question

Voici le code qui le fixe:

@implementation UITextView (Sizing) 

- (CGFloat)contentHeight { 
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) { 
     // This is the code for iOS 7. contentSize no longer returns the correct value, so 
     // we have to calculate it. 
     // 
     // This is partly borrowed from HPGrowingTextView, but I've replaced the 
     // magic fudge factors with the calculated values (having worked out where 
     // they came from) 

     CGRect frame = self.bounds; 

     // Take account of the padding added around the text. 

     UIEdgeInsets textContainerInsets = self.textContainerInset; 
     UIEdgeInsets contentInsets = self.contentInset; 

     CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + self.textContainer.lineFragmentPadding * 2; 
     leftRightPadding += contentInsets.left + contentInsets.right; 

     CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom; 

     frame.size.width -= leftRightPadding; 
     frame.size.height -= topBottomPadding; 

     NSString* textToMeasure = self.text; 
     if(![textToMeasure isNotEmpty]) 
      textToMeasure = @"-"; 

     if ([textToMeasure hasSuffix:@"\n"]) { 
      textToMeasure = [NSString stringWithFormat:@"%@-", self.text]; 
     } 

     // NSString class method: boundingRectWithSize:options:attributes:context is 
     // available only on ios7.0 sdk. 

     NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 
     [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping]; 

     NSDictionary* attributes = @{NSFontAttributeName : self.font, 
            NSParagraphStyleAttributeName : paragraphStyle}; 

     CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT) 
                options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) 
               attributes:attributes 
                context:nil]; 

     CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding); 
     return measuredHeight; 
    } else { 
     return self.contentSize.height; 
    } 
} 

@end 

Au lieu de contentSize, utiliser pour calculer la hauteur du contenu. Vous n'avez pas besoin du tout d'animation - le mien calcule juste et c'est assez lisse, donc vous devriez vous assurer que vous avez vraiment besoin de l'animation.

4

J'ai essayé envelopper le changement heightConstraint dans un bloc d'animation UIView et cela ne fonctionne pas

Ce n'est pas comment vous animez un changement de contrainte. Vous le faites en changeant la contrainte et animant l'acte de mise en page elle-même, comme ceci:

// change the text view constraint here 
[UIView animateWithDuration:duration animations:^{ 
    [self.textView layoutIfNeeded]; 
}]; 
+0

Oui, mais comment peut-on déclencher l'animation étant donné que le changement de contrainte se produit automatiquement dans la méthode autoLayout de UITextView? –

+0

Cela n'arrive pas automatiquement. Si votre vue de texte change de taille, c'est parce que vous changez sa taille. Donc, si vous pouvez changer sa contrainte directement, vous pouvez changer sa contrainte avec l'animation. – matt

+0

Il ne semble pas judicieux d'animer 'layoutIfNeeded' dans' layoutSubviews'; et cela ne fonctionne pas comme prévu. Ce que j'essaie de me demander, c'est où dois-je animer 'layoutIfNeeded', étant donné que le changement de heightConstraint se produit dans' layoutSubviews' de 'UITextView'? –

Questions connexes