17

I have a grouped table view with one cell. In this cell I'm putting a UITextView in cellForRowAtIndexPath:, and I instantly make this first Responder.

My problem is: When I start typing, the text is left-justified, not centered horizontally and vertically as I want. This is on iOS 7.

How can I center the text?

jscs
  • 63,694
  • 13
  • 151
  • 195
user3083408
  • 335
  • 1
  • 4
  • 11

2 Answers2

27

I resolve this issue by observing the contentsize of UITextView, when there is any change in the contentSize, update the contentOffset.

Add observer as follows:

[textview addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];

Handle the observer action as follows:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
     UITextView *txtview = object;
     CGFloat topoffset = ([txtview bounds].size.height - [txtview contentSize].height * [txtview zoomScale])/2.0;
     topoffset = ( topoffset < 0.0 ? 0.0 : topoffset );
     txtview.contentOffset = (CGPoint){.x = 0, .y = -topoffset};
}

To make the textview text horizontally center, select the textview from .xib class and go to the library and in that set Alignment as center.

Enjoy. :)

Vinay Jain
  • 2,644
  • 3
  • 26
  • 44
  • That's what I was searching for, thank you very much! Just one more question: Before I start typing, it is aligned to the bottom of the tableview cell (cursor is on the bottom). When I start typing, it is perfectly aligned. Do you know how to fix this? – user3083408 Feb 25 '14 at 12:23
  • 3
    If you add an observer, don't forget to remove it: [self.messageTextView removeObserver:self forKeyPath:@"contentSize"]; – ddiego Aug 21 '14 at 05:57
  • changing contentOffset only seems to work if the text view's "Selectable" flag is checked – Maiaux Oct 01 '14 at 13:08
  • Wow. I've been banging my head for two days trying to get my textview to present a newline smoothly. This is awesome. I have my textView embedded in a TableFooter, and for some reason I have to resize the textView twice, before and after I use your method above. I really don't understand why setting contentOffset can't be done in textViewDidChange, but it seems to only take affect after the second character on a newline...Thanks – hidden-username Dec 20 '14 at 00:05
  • 2
    Code is clearly copy-pasted from http://stackoverflow.com/a/12591299/603977 with two variable names changed. – jscs Dec 10 '15 at 08:00
1

Very good solution! This is a Swift + Interface Builder solution so that you can enable it in IB.

I'll put it as part of the LSwift library.

extension UITextView {
    @IBInspectable var align_middle_vertical: Bool {
        get {
            return false    //  TODO
        }
        set (f) {
            self.addObserver(self, forKeyPath:"contentSize", options:.New, context:nil)
        }
    }
    override public func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject:AnyObject], context: UnsafeMutablePointer<Void>) {
        if let textView = object as? UITextView {
            var y: CGFloat = (textView.bounds.size.height - textView.contentSize.height * textView.zoomScale)/2.0;
            if y < 0 {
                y = 0
            }
            textView.content_y = -y
        }
    }
}

public extension UIScrollView {
    public var content_x: CGFloat {
        set(f) {
            contentOffset.x = f
        }
        get {
            return contentOffset.x
        }
    }
    public var content_y: CGFloat {
        set(f) {
            contentOffset.y = f
        }
        get {
            return contentOffset.y
        }
    }
}
superarts.org
  • 7,009
  • 1
  • 58
  • 44