web-dev-qa-db-fra.com

Comment ajuster la hauteur d'une vue de texte à son contenu dans SWIFT?

Dans mon contrôleur de vue, j'ai une UITextView. Ce textview est rempli avec une chaîne. La chaîne peut être courte ou longue. En fonction de la longueur de la chaîne, la hauteur de la vue de texte doit être ajustée… .. J'utilise des storyboards et une mise en page automatique.

J'ai quelques problèmes avec la hauteur de la vue de texte.

Parfois, la hauteur est parfaitement adaptée au texte. Parfois, non, le texte est recadré sur la première ligne. En bas, la vue texte est jaune. le bleu est un conteneur dans une vue à défilement. Le violet est l'endroit idéal pour une photo.

title1title2

Les textes proviennent de ma base de données principale, ce sont des attributs de chaîne. Entre l'écran 1 et 2, la seule chose qui a changé est la chaîne.
Si j'imprime les chaînes dans la console, j'ai les textes corrects:

my amazing new title

Another funny title for demo

Les contraintes de ma textview: 

enter image description here

Je ne comprends pas pourquoi j'ai 2 affichages différents.

MODIFIER

J'ai essayé le conseil @Nate, dans viewDidLoad, j'ai ajouté:

    myTextViewTitle.text="my amazing new title"

    myTextViewTitle.setContentHuggingPriority(1000, forAxis: UILayoutConstraintAxis.Vertical)
    myTextViewTitle.setContentCompressionResistancePriority(1000, forAxis: UILayoutConstraintAxis.Vertical)
    myTextViewTitle.setTranslatesAutoresizingMaskIntoConstraints(false)  

    let views = ["new_view": myTextViewTitle]
    var constrs = NSLayoutConstraint.constraintsWithVisualFormat("|-8-[new_view]-8-|", options: NSLayoutFormatOptions(0), metrics: nil, views: views)
    self.view.addConstraints(constrs)
    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[new_view]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
    self.myTextViewTitle.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[new_view(220@300)]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))

Aucun résultat. Avec ou sans contrainte de hauteur ajoutée pour ma visualisation de texte dans le constructeur d'interface ...

EDIT 2

J'ai besoin d'un UITextView et non d'un UIlabel, à cause du bouton Précédent, pour utiliser un chemin d'exclusion.

     let exclusionPathBack:UIBezierPath = UIBezierPath(rect: CGRect(x:backButton.bounds.Origin.x, y:backButton.bounds.Origin.y, width:backButton.bounds.width+10, height:backButton.bounds.height))
     myTextViewTitle.textContainer.exclusionPaths=[exclusionPathBack]
23
cmii

J'ai trouvé une solution.

Je me suis concentré sur la hauteur de mon UITextView, puis j'ai lu un article sur le rapport hauteur/largeur. Je voulais essayer et ça a fonctionné!

Donc, dans le storyboard, j'ai ajouté un rapport d'aspect pour la vue texte et j'ai coché l'option "Supprimer au moment de la construction".

Dans viewDidLayoutSubviews (), j'ai écrit:

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()

    let contentSize = self.myTextViewTitle.sizeThatFits(self.myTextViewTitle.bounds.size)
    var frame = self.myTextViewTitle.frame
    frame.size.height = contentSize.height
    self.myTextViewTitle.frame = frame

    aspectRatioTextViewConstraint = NSLayoutConstraint(item: self.myTextViewTitle, attribute: .Height, relatedBy: .Equal, toItem: self.myTextViewTitle, attribute: .Width, multiplier: myTextViewTitle.bounds.height/myTextViewTitle.bounds.width, constant: 1)
    self.myTextViewTitle.addConstraint(aspectRatioTextViewConstraint!)

}

Ça fonctionne parfaitement.

40
cmii

Commencez par désactiver le défilement . De UITextView. Deux options:

  1. décochez la case Défilement activé dans .xib. 
  2. [TextView setScrollEnabled: NO];

Créez un UITextView et connectez-le avec IBOutlet (TextView). Ajoutez une contrainte de hauteur UITextView avec une hauteur par défaut, connectez-la avec IBOutlet (TextViewHeightConstraint). Lorsque vous définissez le texte de votre UITextView de manière asynchrone, vous devez calculer la hauteur de UITextView et lui attribuer la contrainte de hauteur.

CGSize sizeThatFitsTextView = [TextView sizeThatFits:CGSizeMake(TextView.frame.size.width, MAXFLOAT)];

TextViewHeightConstraint.constant = sizeThatFitsTextView.height; 

Dans Swift 3.0, où tvHeightConstraint est la contrainte de hauteur du sujet TextView (si vous l'utilisez pour plusieurs vues de texte, l'ajouter aux entrées de fonction):

func textViewDidChange(textView: UITextView) {

        let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        if size.height != tvHeightConstraint.constant && size.height > textView.frame.size.height{
            tvHeightConstraint.constant = size.height
            textView.setContentOffset(CGPoint.zero, animated: false)
        }
    }

H/T à @cmi et @Pablo Ruan

8
agrippa

Dans Swift 2.3:

 func textViewDidChange(textView: UITextView) {

    let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.max))
    if size.height != TXV_Height.constant && size.height > textView.frame.size.height{
        TXV_Height.constant = size.height
        textView.setContentOffset(CGPointZero, animated: false)
    }
}
5
Pablo Ruan

J'ai adapté votre code et je l'ai utilisé pour les deux: layout subview et textViewDidChange. Merci beaucoup d'avoir fait ma journée après une heure de dépannage ...

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()
    textViewDidChange(self.recordingTitleTV)


}

func textViewDidChange(_ textView: UITextView) {

    let contentSize = textView.sizeThatFits(textView.bounds.size)
    var frame = textView.frame
    frame.size.height = contentSize.height
    textView.frame = frame

    let aspectRatioTextViewConstraint = NSLayoutConstraint(item: textView, attribute: .height, relatedBy: .equal, toItem: textView, attribute: .width, multiplier: textView.bounds.height/textView.bounds.width, constant: 1)
    textView.addConstraint(aspectRatioTextViewConstraint)
}
0
AppNerd

Ma solution simple à un problème extrêmement similaire:

J'ai utilisé des étiquettes avec le nombre de lignes défini sur 0 au lieu d'essayer d'utiliser des champs de texte ou des vues. Ensuite, j'ai coupé les bords d'attaque et de fuite dans les conteneurs des étiquettes, ce qui limite leur largeur dans mon cas, avec la constante 0 pour les contraintes. Le problème est de définir le nombre de lignes sur 0 pour permettre aux étiquettes de se développer ou de se réduire en fonction de leur contenu. Le texte n'est jamais coupé et la hauteur des étiquettes ne dépasse jamais leur contenu pour toutes les classes de taille que j'ai configurées pour les largeurs (les largeurs de conteneur dans mon cas). Testé pour IOS 8.0 et versions ultérieures (assurez-vous également que la case "explicite" n'est pas cochée en regard des attributs "Largeur préférée" pour toutes les étiquettes pour les largeurs d'étiquette à ajuster pour différentes classes de taille) - fonctionne parfaitement 

0
AshleyC

Pourquoi ne pas avoir une image pour le bouton de retour et un UILabel pour votre texte et utiliser autolayout pour les positionner? Et peut-être une troisième vue pour le fond jaune.

0
Koen