Center text vertically in a UITextView

I want to center the text vertically inside a large UITextView that fills the entire screen - so when the text is a little, say, a couple of words, it is centered on the height. This is not a question of centering the text (a property that can be found in IB), but also of keeping the text vertically in the middle of the UITextView if the text is short, so there are no empty areas in the UITextView . It can be done? Thanks in advance!

+61
ios objective-c iphone xcode uitextview
Sep 25 '12 at 21:17
source share
18 answers

First add an observer for the contentSize key value for the UITextView when loading the view:

 - (void) viewDidLoad { [textField addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL]; [super viewDidLoad]; } 

Then add this method to adjust the contentOffset each time the contentSize value changes:

 -(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}; } 
+61
Sep 25 '12 at 21:26
source share

Since UIKit does not meet KVO requirements , I decided to implement this as a subclass of UITextView , which is updated whenever the contentSize changes.

This is a slightly modified version of Carlos answer that sets contentInset instead of contentOffset . In addition to being compatible with iOS 9 , it also looks less buggy on 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) } } } 
+47
Oct 29 '15 at 10:13
source share

If you do not want to use KVO, you can also manually adjust the offset by exporting this code to a function like this:

 -(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); } 

and calling him

 -(void)textViewDidChange:(UITextView *)textView{ [self adjustContentSize:textView]; } 

and every time you edit text in code. Remember to set the controller as a delegate

Swift 3 version:

 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) } 
+24
May 6 '15 at 20:39
source share

For iOS 9.0.2. we will need to set the contentInset. If we KVO contentOffset, iOS 9.0.2 sets it to 0 at the last moment, overriding the changes to 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]; } 

I used 0,0 and 0 to insert on the left, bottom and right. Remember to also calculate them for your use case.

+20
Oct 25 '15 at 22:04
source share

Here is a UITextView extension that centers content vertically:

 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 } } 
+8
Aug 09 '16 at 15:42 on
source share
 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) } 
+5
Aug 14 '15 at 19:42
source share

I have a text view that I use with autorun and setting lineFragmentPadding and textContainerInset to zero. None of the above solutions worked in my situation. However, this works for me. Tested with 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 
+5
Feb 05 '16 at 17:06
source share

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) } 
+5
Mar 21 '17 at 23:18
source share

You can configure it directly using only restrictions:

There are three constraints that I have added to align text vertically and horizontally in the constraints, as shown below:

enter image description here

  • Make height 0 and add more restrictions
  • Add vertical parental alignment
  • Add horizontal parental constraint

enter image description here

+5
Aug 10 '17 at 13:06 on
source share

I also have this problem, and I solved it with a UITableViewCell with a UITextView . I created a method in a custom subclass of UITableViewCell , the statusTextView property:

 - (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 }; 

And call this method in the methods:

 - (void)textViewDidBeginEditing:(UITextView *)textView - (void)textViewDidEndEditing:(UITextView *)textView - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

This solution worked for me without any problems, you can try.

+4
Sep 24 '13 at 7:59
source share

I just created custom vertical text in 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) } } } 

Link: https://geek-is-stupid.imtqy.com/2017-05-15-how-to-center-text-vertically-in-a-uitextview/

+3
Mar 14 '17 at 4:37 on
source share

Auto Layout Solution:

  • Create a UIView that acts as a container for the UITextView.
  • Add the following restrictions:
    • TextView: align leading space to: Container
    • TextView: align end space to: Container
    • TextView: align center Y to: Container
    • TextView: Equal Height to: Container, Relation: <
+2
Mar 08 '15 at 10:33
source share

Add Carlos to the answer, just in case if you have text in tv larger than the size of tv, you do not need to re-enter the text, so change this code:

 tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; 

:

 if ([tv contentSize].height < [tv bounds].size.height) { tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; } 
+1
Jun 26 '14 at 6:10
source share

You can try to execute the code below, not necessarily an observer. Sometimes the observer throws an error when the view is freed. You can save this code in viewDidLoad, viewWillAppear or in viewDidAppear anywhere.

 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}; }); }); 
0
Jul 27 '15 at 12:23
source share

I did it this way: first, I introduced a UITextView in a UIView (this should work for Mac OS too). Then I attached all four sides of the outer UIView to the sides of its container, giving it a shape and size similar to or equal to the shape of a UITextView. So I had a suitable container for a UITextView. Then I attached the left and right borders of the UITextView to the sides of the UIView and gave the UITextView height. Finally, I centered the UITextView vertically in a UIView. Bingo :) now the UITextView is vertically centered in the UIView, so the text inside the UITextView is also vertically centered.

0
Sep 28 '16 at 6:18
source share

I fixed this problem by creating a vertical extension to the center height.

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 } } 
0
Jul 14 '19 at 23:50
source share

UITextView + VerticalAlignment.h

 // UITextView+VerticalAlignment.h // (c) The Internet 2015 #import <UIKit/UIKit.h> @interface UITextView (VerticalAlignment) - (void)alignToVerticalCenter; - (void)disableAlignment; @end 

UITextView + VerticalAlignment.m

 #import "UITextView+VerticalAlignment.h" @implementation UITextView (VerticalAlignment) - (void)alignToVerticalCenter { [self addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL]; } - (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}; } - (void)disableAlignment { [self removeObserver:self forKeyPath:@"contentSize"]; } @end 
-one
May 18 '15 at 21:02
source share

Solution for iOS10 in RubyMotion:

 class VerticallyCenteredTextView < UITextView def init super end def layoutSubviews self.recenter end def recenter contentSize = self.sizeThatFits(CGSizeMake(self.bounds.size.width, Float::MAX)) topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0; topCorrection = 0 if topCorrection < 0 self.contentInset = UIEdgeInsetsMake(topCorrection, 0, 0, 0) end end 
-3
Sep 20 '16 at 19:35
source share



All Articles