web-dev-qa-db-fra.com

Redimensionner UITextView

J'ai ajouté une UITextView à ma UIView. La vue texte ajoutée n'est pas éditable, c'est juste pour afficher des données. Les données affichées dans la vue texte sont dynamiques. C'est que le nombre de lignes n'est pas fixe. Cela peut varier. Ainsi, si le nombre de lignes augmente, la taille de la vue texte doit également être augmentée. Je ne sais pas comment faire cela. S'il vous plaît donnez-moi quelques idées.

METTRE À JOUR:

Voici ce que je fais:

UIView *baseView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 200)];
baseView.backgroundColor = [UIColor grayColor];
[window addSubview:baseView];

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(5, 30, 100, 30)];
textView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
textView.text = @"asdf askjalskjalksjlakjslkasj";
[textView sizeToFit];
[baseView addSubview:textView];
26
saikamesh

Vous pouvez utiliser setFrame: ou sizeToFit.

METTRE À JOUR:

J'utilise sizeToFit avec UILabel, et cela fonctionne très bien, mais UITextView est une sous-classe de UIScrollView. Je peux donc comprendre pourquoi sizeToFit ne produit pas le résultat souhaité.

Vous pouvez toujours calculer la hauteur du texte et utiliser setFrame, mais vous voudrez peut-être tirer parti des barres de défilement de UITextView si le texte est trop long.

Voici comment vous obtenez la hauteur du texte:

#define MAX_HEIGHT 2000

NSString *foo = @"Lorem ipsum dolor sit amet.";
CGSize size = [foo sizeWithFont:[UIFont systemFontOfSize:14]
              constrainedToSize:CGSizeMake(100, MAX_HEIGHT)
                  lineBreakMode:UILineBreakModeWordWrap];

et ensuite vous pouvez l'utiliser avec votre UITextView:

[textView setFont:[UIFont systemFontOfSize:14]];
[textView setFrame:CGRectMake(5, 30, 100, size.height + 10)];

ou vous pouvez faire le calcul de hauteur en premier et éviter la ligne setFrame:

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(5, 30, 100, size.height + 10)];
29
Can Berk Güder

Il y a une réponse affichée à Comment dimensionner un UITextView par rapport à son contenu?

CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

ou mieux (en tenant compte de contentInset grâce au commentaire de kpower)

CGRect frame = _textView.frame;
UIEdgeInsets inset = textView.contentInset;
frame.size.height = _textView.contentSize.height + inset.top + inset.bottom;
_textView.frame = frame;

remarque: si vous allez référencer plusieurs fois une propriété d'un objet (par exemple, frame ou contentInset), il est préférable de l'affecter à une variable locale afin de ne pas déclencher d'appels de méthode supplémentaires (_textView.frame/[_ textView frame], méthode. appels). Si vous appelez beaucoup ce code (100 000 fois), le processus sera sensiblement plus lent (une douzaine d'appels de méthode sont insignifiants).

Cependant ... si vous voulez le faire en une ligne sans variables supplémentaires, ce serait

        _textView.frame = CGRectMake(_textView.frame.Origin.x, _textView.frame.Origin.y, _textView.frame.size.width, _textView.contentSize.height + _textView.contentInset.top + _textView.contentInset.bottom);

au prix de 5 appels de méthode supplémentaires.

58
Gabe

textView.contentSize.height dans la textViewDidChange ne peut que redimensionner après le texte s'agrandit réellement. Pour un meilleur résultat visuel, il est préférable de redimensionner au préalable. Après plusieurs heures, j'ai compris comment le rendre parfaitement comme sur Instagram (il possède le meilleur algorithme parmi tous les BTW)

Initialiser avec ceci:

    // Input
    _inputBackgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, size.height - _InputBarHeight, size.width, _InputBarHeight)];
    _inputBackgroundView.autoresizingMask = UIViewAutoresizingNone;
   _inputBackgroundView.contentMode = UIViewContentModeScaleToFill;
    _inputBackgroundView.userInteractionEnabled = YES;
    [self addSubview:_inputBackgroundView];
   [_inputBackgroundView release];

   [_inputBackgroundView setImage:[[UIImage imageNamed:@"Footer_BG.png"] stretchableImageWithLeftCapWidth:80 topCapHeight:25]];

    // Text field
    _textField = [[UITextView alloc] initWithFrame:CGRectMake(70.0f, 0, 185, 0)];
   _textField.backgroundColor = [UIColor clearColor];
    _textField.delegate = self;
   _textField.contentInset = UIEdgeInsetsMake(-4, -2, -4, 0);
   _textField.showsVerticalScrollIndicator = NO;
   _textField.showsHorizontalScrollIndicator = NO;
    _textField.font = [UIFont systemFontOfSize:15.0f];
    [_inputBackgroundView addSubview:_textField];
   [_textField release];

   [self adjustTextInputHeightForText:@""];

Remplissez les méthodes de délégué UITextView:

- (void) textViewDidBeginEditing:(UITextView*)textView {

   [self adjustTextInputHeightForText:_textField.text];
}

- (void) textViewDidEndEditing:(UITextView*)textView {

   [self adjustTextInputHeightForText:_textField.text];
}

- (BOOL) textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {

   if ([text isEqualToString:@"\n"])
   {
      [self performSelector:@selector(inputComplete:) withObject:nil afterDelay:.1];
      return NO;
   }
   else if (text.length > 0)
   {
      [self adjustTextInputHeightForText:[NSString stringWithFormat:@"%@%@", _textField.text, text]];
   }
   return YES;
}

- (void) textViewDidChange:(UITextView*)textView {

   [self adjustTextInputHeightForText:_textField.text];
}

Et le truc c'est ...

- (void) adjustTextInputHeightForText:(NSString*)text {

   int h1 = [text sizeWithFont:_textField.font].height;
   int h2 = [text sizeWithFont:_textField.font constrainedToSize:CGSizeMake(_textField.frame.size.width - 16, 170.0f) lineBreakMode:UILineBreakModeWordWrap].height;

   [UIView animateWithDuration:.1f animations:^
   {
      if (h2 == h1)
      {
         _inputBackgroundView.frame = CGRectMake(0.0f, self.frame.size.height - _InputBarHeight, self.frame.size.width, _InputBarHeight);
      }
      else
      {
         CGSize size = CGSizeMake(_textField.frame.size.width, h2 + 24);
         _inputBackgroundView.frame = CGRectMake(0.0f, self.frame.size.height - size.height, self.frame.size.width, size.height);
      }
      CGRect r = _textField.frame;
      r.Origin.y = 12;
      r.size.height = _inputBackgroundView.frame.size.height - 18;
      _textField.frame = r;

   } completion:^(BOOL finished)
   {
      //
   }];
}
2
m8labs

sizeToFit fonctionne

Si vous appelez sizeToFit après avoir défini le texte la première fois qu'il est redimensionné. Ainsi, après la première configuration, les appels suivants pour définir le texte ne modifieront pas la taille. Même si vous appelez sizeToFit.

Cependant, vous pouvez le forcer à redimensionner comme ceci:

  1. Définissez le texte.
  2. Modifiez la hauteur du cadre de textView pour qu'elle soit CGFLOAT_MAX.
  3. Appelez sizeToFit.
2

Cela fonctionne parfaitement pour moi:

    #define MAX_HEIGHT 2000     
    CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:14]
          constrainedToSize:CGSizeMake(100, MAX_HEIGHT)
              lineBreakMode:UILineBreakModeWordWrap];

    [textview setFont:[UIFont systemFontOfSize:14]];
    [textview setFrame:CGRectMake(45, 6, 100, size.height + 10)];
    textview.text = text;
1
Viggnesh

La réponse donnée par @Gabe ne fonctionne apparemment dans iOS7.1 qu'après viewDidAppear. Voir mes tests ci-dessous.

MISE À JOUR: En réalité, la situation est encore plus compliquée. Si vous affectez textView.text dans la méthode resizeTheTextView, dans iOS7, le redimensionnement revient à ne permettre qu'une seule ligne de texte. Sérieusement étrange.

UPDATE2: Voir aussi La taille du contenu UITextView est différente dans iOS7

UPDATE3: Voir mon code tout en bas pour ce que j'utilise maintenant. Semble faire le travail.

#import "ViewController.h"

@interface ViewController ()
{
    UITextView *textView;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    textView = [[UITextView alloc] initWithFrame:CGRectMake(50, 50, 200, 1)];
    [self.view addSubview:textView];
    CALayer *layer = textView.layer;
    layer.borderColor = [UIColor blackColor].CGColor;
    layer.borderWidth = 1;

    textView.text = @"hello world\n\n";

    // Calling the method directly, after the view is rendered, i.e., after viewDidAppear, works on both iOS6.1 and iOS7.1
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [button setTitle:@"Change size" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(resizeTheTextView) forControlEvents:UIControlEventTouchUpInside];
    [button sizeToFit];
    CGRect frame = button.frame;
    frame.Origin.y = 400;
    button.frame = frame;
    [self.view addSubview:button];

    // Works on iOS6.1, but does not work on iOS7.1
    //[self resizeTheTextView];
}

- (void) viewWillAppear:(BOOL)animated
{
    // Does not work on iOS7.1, but does work on iOS6.1
    //[self resizeTheTextView];
}

- (void) viewDidAppear:(BOOL)animated
{
    // Does work on iOS6.1 and iOS7.1
    //[self resizeTheTextView];
}

- (void) resizeTheTextView
{
    NSLog(@"textView.frame.size.height: %f", textView.frame.size.height);

    NSLog(@"textView.contentSize.height: %f", textView.contentSize.height);

    // 5) From https://stackoverflow.com/questions/728704/resizing-uitextview
    CGRect frame = textView.frame;
    UIEdgeInsets inset = textView.contentInset;
    frame.size.height = textView.contentSize.height + inset.top + inset.bottom;
    textView.frame = frame;

    NSLog(@"inset.top: %f, inset.bottom: %f",  inset.top,  inset.bottom);

    NSLog(@"textView.frame.size.height: %f", textView.frame.size.height);

    NSLog(@"textView.contentSize.height: %f", textView.contentSize.height);
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

UPDATE3:

if ([[UIDevice currentDevice] majorVersionNumber] < 7.0) {
    CGRect frame = _abstractTextView.frame;
    UIEdgeInsets inset = _abstractTextView.contentInset;
    frame.size.height = _abstractTextView.contentSize.height + inset.top + inset.bottom;
    _abstractTextView.frame = frame;
}
else {
    CGSize textViewSize = [_abstractTextView sizeThatFits:CGSizeMake(_abstractTextView.frame.size.width, FLT_MAX)];
    _abstractTextView.frameHeight = textViewSize.height;
}
0
Chris Prince

Faites ce qui suit:

_textView.text = someText;
[_textView sizeToFit];
_textView.frame.height = _textView.contentSize.height;
0
Dat Tran

Réglez simplement scrollEnabled sur NO ou décochez Scrolling Enabled dans la section Scroll View de IB et la UITextView se redimensionnera automatiquement.

0
Mojo66

Une fois que vous avez ajouté UITextView à son parent si vous définissez un mode de contenu, il semble alors se redimensionner automatiquement.

Cela signifie que vous n'avez pas besoin de calculer manuellement la hauteur et d'appliquer une contrainte de hauteur. Cela semble juste fonctionner !! Testé sous iOS7 et iOS8 sur iPad.

par exemple.

--
textView.contentMode = UIViewContentMode.Center;
--

Si quelqu'un peut expliquer pourquoi cela fonctionne, ce serait très apprécié. Je l'ai trouvé par accident en jouant avec les options du constructeur d'interface.

0
Dave Haigh

Abordant le même problème, je viens de créer une sous-classe UITextView légère, basée sur la mise en page automatique, qui s'agrandit et diminue automatiquement en fonction de la taille de l'entrée utilisateur et peut être contrainte par une hauteur maximale et minimale, le tout sans une seule ligne de code.

https://github.com/MatejBalantic/MBAutoGrowingTextView

0
Matej Balantič