Je souhaite centrer le texte verticalement dans une grande UITextView
qui remplit tout l'écran. Ainsi, lorsqu'il y a peu de texte, prononcez quelques mots, il est centré par la hauteur. Ce n’est pas une question de centrage du texte (une propriété que l’on trouve dans IB) mais de mettre le texte verticalement en plein milieu de UITextView
si le texte est court, pas de zones vierges dans la UITextView
. Est-ce possible? Merci d'avance!
Premièrement, ajoutez un observateur pour la valeur de la clé contentSize
de la UITextView
lorsque la vue est chargée:
- (void) viewDidLoad {
[textField addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
[super viewDidLoad];
}
Ajoutez ensuite cette méthode pour ajuster la contentOffset
chaque fois que la valeur contentSize
change:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
UITextView *tv = object;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
Parce que UIKit n'est pas conforme à KVO , j'ai décidé de l'implémenter en tant que sous-classe de UITextView
qui se met à jour chaque fois que la variable contentSize
change.
C'est une version légèrement modifiée de La réponse de Carlos qui définit contentInset
au lieu de contentOffset
. En plus de étant compatible avec iOS 9 , il semble également être moins bogué sur iOS 8.4.
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}
Si vous ne souhaitez pas utiliser KVO, vous pouvez également régler manuellement le décalage en exportant ce code vers une fonction telle que
-(void)adjustContentSize:(UITextView*)tv{
CGFloat deadSpace = ([tv bounds].size.height - [tv contentSize].height);
CGFloat inset = MAX(0, deadSpace/2.0);
tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right);
}
et en l'appelant
-(void)textViewDidChange:(UITextView *)textView{
[self adjustContentSize:textView];
}
et chaque fois que vous modifiez le texte dans le code. N'oubliez pas de définir le contrôleur en tant que délégué
Version Swift 3:
func adjustContentSize(tv: UITextView){
let deadSpace = tv.bounds.size.height - tv.contentSize.height
let inset = max(0, deadSpace/2.0)
tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right)
}
func textViewDidChange(_ textView: UITextView) {
self.adjustContentSize(tv: textView)
}
Pour iOS 9.0.2. nous aurons besoin de définir le contentInset à la place. Si nous KVO le contentOffset, iOS 9.0.2 le définit à 0 au dernier moment, annulant les modifications apportées à contentOffset.
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
UITextView *tv = object;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
[tv setContentInset:UIEdgeInsetsMake(topCorrect,0,0,0)];
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:NO];
[questionTextView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
}
J'ai utilisé 0,0 et 0 pour les inserts Edge gauche, bas et droit respectivement. Assurez-vous de les calculer également pour votre cas d'utilisation.
Voici une extension UITextView
qui centre le contenu verticalement:
extension UITextView {
func centerVertically() {
let fittingSize = CGSize(width: bounds.width, height: CGFloat.max)
let size = sizeThatFits(fittingSize)
let topOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(0, topOffset)
contentOffset.y = -positiveTopOffset
}
}
Swift 3:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textField.frame = self.view.bounds
var topCorrect : CGFloat = (self.view.frame.height / 2) - (textField.contentSize.height / 2)
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect
textField.contentInset = UIEdgeInsetsMake(topCorrect,0,0,0)
}
func alignTextVerticalInTextView(textView :UITextView) {
let size = textView.sizeThatFits(CGSizeMake(CGRectGetWidth(textView.bounds), CGFloat(MAXFLOAT)))
var topoffset = (textView.bounds.size.height - size.height * textView.zoomScale) / 2.0
topoffset = topoffset < 0.0 ? 0.0 : topoffset
textView.contentOffset = CGPointMake(0, -topoffset)
}
Vous pouvez le configurer directement avec seulement des contraintes:
Il y a 3 contraintes que j'ai ajoutées pour aligner le texte verticalement et horizontalement, comme ci-dessous:
J'ai une vue texte que j'utilise avec autolayout et avec la définition de lineFragmentPadding
et textContainerInset
à zéro. Aucune des solutions ci-dessus n'a fonctionné dans ma situation. Cependant, cela fonctionne pour moi. Testé avec iOS 9
@interface VerticallyCenteredTextView : UITextView
@end
@implementation VerticallyCenteredTextView
-(void)layoutSubviews{
[self recenter];
}
-(void)recenter{
// using self.contentSize doesn't work correctly, have to calculate content size
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)];
CGFloat topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0;
self.contentOffset = CGPointMake(0, -topCorrection);
}
@end
J'ai aussi ce problème et je l'ai résolu avec un UITableViewCell
avec UITextView
. J'ai créé la méthode dans une sous-classe UITableViewCell
personnalisée, propriété statusTextView
:
- (void)centerTextInTextView
{
CGFloat topCorrect = ([self.statusTextView bounds].size.height - [self.statusTextView contentSize].height * [self.statusTextView zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
self.statusTextView.contentOffset = (CGPoint){ .x = 0, .y = -topCorrect };
Et appelez cette méthode en méthodes:
- (void)textViewDidBeginEditing:(UITextView *)textView
- (void)textViewDidEndEditing:(UITextView *)textView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Cette solution a fonctionné pour moi sans aucun problème, vous pouvez l'essayer.
Je viens de créer une vue texte personnalisée centrée verticalement dans Swift 3:
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}
ref: http://geek-is-stupid.github.io/blog/2017/03/14/how-to-center-text-vertically-in-a-uitextview/
Ajoutez à la réponse Carlos, juste au cas où vous auriez du texte dans tv plus grand que la taille de tv, vous n'avez pas besoin de recentrer le texte, alors changez ce code:
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
pour ça:
if ([tv contentSize].height < [tv bounds].size.height) {
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
Solution de mise en page automatique:
J'ai résolu ce problème en créant une extension au centre de la hauteur verticalement.
Swift 5:
extension UITextView {
func centerContentVertically() {
let fitSize = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
let size = sizeThatFits(fitSize)
let heightOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(0, heightOffset)
contentOffset.y = -positiveTopOffset
}
}
Vous pouvez essayer ci-dessous le code, aucun observateur obligatoire. L'observateur génère parfois des erreurs lorsque la vue est désallouée . Vous pouvez conserver ce code dans viewDidLoad, viewWillAppear ou dans viewDidAppear n'importe où.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^(void) {
UITextView *tv = txtviewDesc;
CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
});
});
Je l'ai fait comme ceci: tout d'abord, j'ai incorporé UITextView dans un UIView (cela devrait fonctionner aussi pour Mac OS). Ensuite, j'ai épinglé les quatre côtés de l'UIView externe sur les côtés de son conteneur, lui donnant une forme et une taille similaires ou égales à celles de UITextView. Ainsi, j'avais un conteneur approprié pour UITextView. Ensuite, j'ai épinglé les bordures gauche et droite de UITextView sur les côtés de UIView et lui ai donné une hauteur. Enfin, j'ai centré UITextView verticalement dans UIView. Bingo :) Maintenant, UITextView est centré verticalement dans UIView, ainsi le texte à l'intérieur de UITextView est également centré verticalement.