J'ai une vue qui est entièrement présentée en utilisant la mise en page automatique par programmation. J'ai un UITextView au milieu de la vue avec des éléments au-dessus et en dessous. Tout fonctionne bien, mais je veux pouvoir étendre UITextView au fur et à mesure que du texte est ajouté. Cela devrait pousser tout ce qui se trouve en dessous à mesure qu'il se développe.
Je sais comment faire cela de la manière "ressorts et entretoises", mais y a-t-il un moyen de mise en page automatique? La seule façon dont je peux penser est de supprimer et de rajouter la contrainte à chaque fois qu'elle doit se développer.
Réponses:
La vue contenant UITextView se verra attribuer sa taille
setBounds
par AutoLayout. Alors, c'est ce que j'ai fait. Le superview est initialement configuré toutes les autres contraintes comme elles devraient l'être, et à la fin j'ai mis une contrainte spéciale pour la hauteur de UITextView, et je l'ai sauvegardée dans une variable d'instance.Dans la
setBounds
méthode, j'ai ensuite changé la valeur de la constante.la source
textViewDidChange
cela, cela devrait éviter des tracas de sous-classification et d'écriture de code…textViewDidChange:
cela ne sera pas appelé lors de l'ajout de texte à UITextView par programme.Résumé: désactivez le défilement de votre vue texte et ne contraignez pas sa hauteur.
Pour ce faire par programme, placez le code suivant dans
viewDidLoad
:Pour ce faire dans Interface Builder, sélectionnez la vue de texte, décochez Défilement activé dans l'inspecteur d'attributs et ajoutez les contraintes manuellement.
Remarque: Si vous avez d'autres vues au-dessus / en dessous de votre vue texte, pensez à utiliser a
UIStackView
pour toutes les organiser.la source
intrinsicContentSize
comme ceci- (CGSize)intrinsicContentSize { CGSize size = [super intrinsicContentSize]; if (self.text.length == 0) { size.height = UIViewNoIntrinsicMetric; } return size; }
. Dites-moi si ça marche pour vous. Je ne l'ai pas testé moi-même.Voici une solution pour les personnes qui préfèrent tout faire par mise en page automatique:
Dans l'inspecteur de taille:
Définissez la priorité verticale de la résistance à la compression du contenu sur 1000.
Réduisez la priorité de la hauteur de contrainte en cliquant sur "Modifier" dans Contraintes. Faites simplement moins de 1000.
Dans l'inspecteur d'attributs:
la source
UITextView ne fournit pas de intrinsicContentSize, vous devez donc le sous-classer et en fournir un. Pour le faire grandir automatiquement, invalidez intrinsicContentSize dans layoutSubviews. Si vous utilisez autre chose que le contentInset par défaut (que je ne recommande pas), vous devrez peut-être ajuster le calcul intrinsicContentSize.
la source
setScrollEnabled:
pour toujours le définir,NO
vous obtiendrez une boucle infinie pour une taille de contenu intrinsèque toujours croissante.[textView sizeToFit]
letextViewDidChange:
rappel de délégué pour la mise en page automatique pour agrandir ou réduire la vue de texte (et recalculer toutes les contraintes dépendantes) après chaque frappe.-(void)layoutSubviews
et enveloppez tout le code-(CGSize)intrinsicContentSize
avecversion >= 7.0f && version < 7.1f
+else return [super intrinsicContentSize];
Vous pouvez le faire via le storyboard, désactivez simplement "Défilement activé" :)
la source
J'ai trouvé que ce n'est pas tout à fait rare dans les situations où vous pouvez toujours avoir besoin de isScrollEnabled défini sur true pour permettre une interaction raisonnable avec l'interface utilisateur. Un cas simple pour cela est lorsque vous souhaitez autoriser une vue de texte à expansion automatique tout en limitant sa hauteur maximale à quelque chose de raisonnable dans un UITableView.
Voici une sous-classe de UITextView que j'ai proposée qui permet l'expansion automatique avec mise en page automatique mais que vous pouvez toujours contraindre à une hauteur maximale et qui gérera si la vue peut faire défiler en fonction de la hauteur. Par défaut, la vue s'agrandit indéfiniment si vous avez configuré vos contraintes de cette façon.
En prime, il est possible d'inclure un texte d'espace réservé similaire à UILabel.
la source
Vous pouvez également le faire sans sous-classer
UITextView
. Jettes un coup d'oeil à ma réponse à Comment dimensionner un UITextView en fonction de son contenu sur iOS 7?Utilisez la valeur de cette expression:
mettre à jour la
constant
de latextView
hauteur de »UILayoutConstraint
.la source
Une chose importante à noter:
Étant donné que UITextView est une sous-classe de UIScrollView, il est soumis à la propriété automaticAdjustsScrollViewInsets de UIViewController.
Si vous configurez la mise en page et que TextView est la première sous-vue d'une hiérarchie UIViewControllers, son contentInsets sera modifié si automaticAdjustsScrollViewInsets est vrai, provoquant parfois un comportement inattendu dans la mise en page automatique.
Donc, si vous rencontrez des problèmes avec la disposition automatique et les vues de texte, essayez de définir
automaticallyAdjustsScrollViewInsets = false
sur le contrôleur de vue ou de déplacer le textView vers l'avant dans la hiérarchie.la source
C'est plus un commentaire très important
La clé pour comprendre pourquoi la réponse de vitaminwater fonctionne sont trois choses:
contentOffset
soit probablement rien d'autre que:Pour en savoir plus, voir objc scrollview et comprendre scrollview
En combinant les trois ensemble, vous comprendrez facilement que vous devez permettre au contentSize intrinsèque du textView de fonctionner avec les contraintes de mise en page automatique du textView pour piloter la logique. C'est presque comme si votre textView fonctionnait comme un UILabel
Pour ce faire, vous devez désactiver le défilement, ce qui signifie essentiellement la taille de scrollView, la taille de contentSize et en cas d'ajout d'un containerView, la taille de containerView serait la même. Quand ils sont identiques, vous n'avez PAS de défilement. Et vous auriez . Ayant
0
contentOffset
0
contentOffSet
signifie que vous n'avez pas fait défiler vers le bas. Pas même un point de moins! En conséquence, le textView sera tout étiré.Cela ne vaut également rien qui signifie que les limites et le cadre de scrollView sont identiques. Si vous faites défiler vers le bas de 5 points, votre contentOffset serait alors que votre serait égal à
0
contentOffset
5
scrollView.bounds.origin.y - scrollView.frame.origin.y
5
la source
Solution prête à l'emploi - Xcode 9
Autolayout comme
UILabel
, avec la détection de lien , la sélection de texte , l' édition et le défilement deUITextView
.Gère automatiquement
Un grand nombre de ces réponses m'ont permis d'atteindre 90%, mais aucune n'était infaillible.
Descendez dans cette
UITextView
sous - classe et vous êtes bon.la source
La réponse de vitaminwater fonctionne pour moi.
Si le texte de votre vue de texte rebondit de haut en bas pendant la modification, après le réglage
[textView setScrollEnabled:NO];
, définissezSize Inspector > Scroll View > Content Insets > Never
.J'espère que ça aide.
la source
Placez UILabel caché sous votre vue de texte. Lignes d'étiquette = 0. Définissez les contraintes de UITextView pour qu'elles soient égales à UILabel (centerX, centerY, largeur, hauteur). Fonctionne même si vous laissez le comportement de défilement de textView.
la source
BTW, j'ai construit un UITextView en expansion en utilisant une sous-classe et en remplaçant la taille du contenu intrinsèque. J'ai découvert un bogue dans UITextView que vous voudrez peut-être étudier dans votre propre implémentation. Voici le problème:
La vue de texte extensible s'agrandit pour s'adapter au texte croissant si vous tapez des lettres uniques à la fois. Mais si vous collez un tas de texte dedans, il ne grossirait pas mais le texte défilerait vers le haut et le texte en haut était hors de vue.
La solution: Remplacez setBounds: dans votre sous-classe. Pour une raison inconnue, le collage a rendu la valeur bounds.origin.y non-zee (33 dans chaque cas que j'ai vu). J'ai donc surchargé setBounds: pour toujours mettre le bounds.origin.y à zéro. Correction du problème.
la source
Voici une solution rapide:
Ce problème peut se produire si vous avez défini la propriété clipsToBounds sur false de votre textview. Si vous le supprimez simplement, le problème disparaît.
la source
la source