7

I want to align text vertically center in UItextView.

I am using following code

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}

;

Somehow this doesn't work in iOS 5 as the contentSize returned there is different what I get in iOS6.

Any Idea why contentSize of the same textView is different in iOS 5 and iOS 6?

Cœur
  • 37,241
  • 25
  • 195
  • 267
subhash Amale
  • 325
  • 3
  • 4
  • 14
  • Possible duplicate of [Center text vertically in a UITextView](https://stackoverflow.com/questions/12591192/center-text-vertically-in-a-uitextview) – Tommy Devoy Jul 27 '18 at 16:52

3 Answers3

20

Add an observer for the contentSize key value of the UITextView when the view loaded :-

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

Adjust the contentOffset every time the contentSize value 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};
}

Hope it helps you...

You may take guide from

https://github.com/HansPinckaers/GrowingTextView

Arpit Kulsreshtha
  • 2,452
  • 2
  • 26
  • 52
  • 1
    This doesn't keep the text constantly centered vertically because if the UITextView is resized (for example, when the keyboard appears) then the content in the UITextView reverts to top alignment. – motionpotion Mar 02 '14 at 10:22
  • 1
    This is a great bit of code apart from its value as a keypath observer. Thanks. – Dan Rosenstark May 21 '14 at 04:27
  • I had a crash while using this code in a `UITableView`. Working well on ios8 but also needs to remove observer after alignment is done. Add this line as last line of `observeValueForKeyPath` method: `[tv removeObserver:self forKeyPath:@"contentSize"];` – Vaibhav Saran Apr 15 '15 at 09:42
5

try this on observeValueForKeyPath method on iOS7:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
UITextView *tv = object;

CGFloat height = [tv bounds].size.height;
CGFloat contentheight;

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) {
    contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
    NSLog(@"iOS7; %f %f", height, contentheight);
}else{
    contentheight = [tv contentSize].height;
    NSLog(@"iOS6; %f %f", height, contentheight);
}

CGFloat topCorrect = height - contentheight;
topCorrect = (topCorrect <0.0 ? 0.0 : topCorrect);
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}

to be defined:

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
Max B.
  • 881
  • 10
  • 21
0

I've modified Arpit's solution so it can fit with expanding textview contentView

static NSString *const kContentOffsetKeyPath = @"contentOffset";

-(void)viewDidLoad {
     [self.replyTextView addObserver:self
                         forKeyPath:kContentOffsetKeyPath
                            options:(NSKeyValueObservingOptionNew)
                            context:NULL];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:kContentOffsetKeyPath]) {
        // To keep scrolling to bottom while typing and text content view is larger than maximum limit
        if (textView.contentSize.height > singleLineHeight) {
            UITextView *textView = object;
            CGFloat topCorrect = ([textView bounds].size.height - [textView contentSize].height * [textView zoomScale]) / 2.0;
            CGFloat fineTune = -3.0;
            topCorrect = (topCorrect < fineTune ? fineTune : topCorrect);
            // To avoid recursion
            [textView removeObserver:self forKeyPath:kContentOffsetKeyPath];
            textView.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
            // add observer back
            [textView addObserver:self
                       forKeyPath:kContentOffsetKeyPath
                          options:(NSKeyValueObservingOptionNew)
                          context:NULL];
        }
    }
}

- (void)dealloc {
    [self.replyTextView removeObserver:self forKeyPath:kContentOffsetKeyPath];
    }
Ali Amin
  • 667
  • 5
  • 17