Multi-line/Autoresizing UITextView similar to SMS-app

转载 2011年10月13日 09:43:49

I’ve been tinkering around the last days, creating a multi-line UITextView. I wanted a SMS-app like experience and needed a growing (and shrinking) textView. I tried using three20′s TTTextEditor, but it disables the bounces of the scroll (which is ugly) and has this big white margin on the bottom when you scroll down manually. So I needed a UITextView which grows/shrinks with the text always on the bottom and a bouncing scroll. Well, I wouldn’t be blogging this if I wouldn’t have been succesful.

Growing and Shrinking

I started with the code of Brett Schumann (iPhone Multiline Textbox for SMS style chat). Brett calculates the new height when UITextViewTextDidChangeNotification is posted. He determines the needed height by using sizeWithFont:

CGSize newSize = [textView.text
            sizeWithFont:[UIFont fontWithName:@"Helvetica" size:14]

I find this rather inconsistent with other typefaces and sized, because of the inset/padding of the UITextView.

I ended with a much simpler approach, using the textViewDidChange: delegate method. This method is called after inserting the typed character. Determining the height is than as easy as: textView.contentSize.height (UITextView extends UIScrollView)

Determining the height of, for example, one line is done by a hidden UITextView, this is needed for the properties of minNumberOfLines and maxNumberOfLines.

Removing the bottom margin

The first problem that comes about when using a UITextView with one line is that the UITextView scrolls up when focused. With googling you can find the answer for the solution:

textView.contentInset = UIEdgeInsetsZero;

Some people say that the “word-tip” or correction bubble will be cut by the bounds of the UITextview, but I couldn’t reproduce that.

Removing the bottom margin took quite a long time. After a few days of research I found out that UITextView is setting the contentInset on unpredictable times. I tried setting it in several delegate methods but ended up in subclassing UITextView and overriding the method. It seems that this works perfectly.

	UIEdgeInsets insets = s;
	if(s.bottom>8) insets.bottom = 0; = 0;
	[super setContentInset:insets];

Sometimes you want a inset on the bottom when you’re typing and wraps to the next line. But when the user is going to scroll manually you need to set the inset to 0. The solution is overriding setContentOffset:.

	if(self.tracking || self.decelerating){
		//initiated by user...
		self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
	} else {
		float bottomOffset = (self.contentSize.height - self.frame.size.height + self.contentInset.bottom);
		if(s.y < bottomOffset && self.scrollEnabled){
			self.contentInset = UIEdgeInsetsMake(0, 0, 8, 0); //maybe use scrollRangeToVisible?
	[super setContentOffset:s];

Delegate and UITextView properties

The class uses a internal UITextView, but you can set nearly all properties on a class instance, the will be applied on the internal UITextView. All the UITextView delegate methods are also possible to use.

I also included 2 delegate methods for determining when a grow/shrink starts. willChangeHeight is called within the animation block, so every change you make there on a view gets animated.

The Delegate methods

- (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView;
- (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView;
- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView;
//called WITHIN animation block!
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height;
//called after animation
- (void)growingTextView:(HPGrowingTextView *)growingTextView didChangeHeight:(float)height;
- (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView;
- (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView;

The included properties

int maxNumberOfLines;
int minNumberOfLines;
BOOL animateHeightChange; //default is YES
//UITextView properties
NSString *text;
UIFont *font;
UIColor *textColor;
UITextAlignment textAlignment;
NSRange selectedRange;
BOOL editable;
UIDataDetectorTypes dataDetectorTypes;
UIReturnKeyType returnKeyType;

You can read/write the properties on a class instance. When you need to set a specific property that is not listed here, you can set it directly on the internalTextView. Be careful though; the HPGrowingTextView needs to stay the delegate of the internalTextView!



Update: Added fixes suggested in the comments.

License: MIT license

It’s a zip file, with the class and an example included.

Autoresizing UITextView similar to SMS-app

  • shshjing
  • shshjing
  • 2012年04月27日 09:50
  • 206


  • xuebing22022
  • xuebing22022
  • 2016年01月11日 09:31
  • 401

multi-line comment In file

写注释引起的编译问题: //s3c_gpio_cfgpin(pin, GTP_INT_CFG); \ 如果向上面那样写注释的话,就会引起问题,GCC,警告,有可能编译不通过,我遇到的问题就是编译不通...
  • weiqifa0
  • weiqifa0
  • 2015年01月05日 17:30
  • 951

python 错误的原因 token Error: EOF in multi-line statement

python 错误的原因 token Error: EOF in multi-line statement是括号等不匹配
  • yanleigis
  • yanleigis
  • 2010年01月04日 11:09
  • 4463


UIView *redView = [[UIView alloc] init];     redView.backgroundColor = [UIColor redColor];     CGF...
  • liangliang2727
  • liangliang2727
  • 2016年11月25日 09:53
  • 373

python webpy 错误的原因 token Error: EOF in multi-line statement

一般出现这种情况是括号或者引号等不匹配造成的。 在webpy中,模板html里面可以写python代码,但要用$开始。但如果网页代码本来就有$符号(javascript或者正则表达式),...
  • cedricporter
  • cedricporter
  • 2011年09月02日 22:16
  • 2503

iOS适配之两大自动布局利器—— Autoresizing、Autolayout

  • iOSbird
  • iOSbird
  • 2015年12月21日 16:24
  • 1231


IOS自动布局之Autoresizing 对于IOS的app开发者来说,不会像Android开发者一样为很多的屏幕尺寸来做界面适配,因此硬编码的坐标也能工作良好,但是从设计模式上来说这不是好...
  • yongyinmg
  • yongyinmg
  • 2014年11月23日 23:16
  • 22338


今天用GCC编译遇到如下警告(使用了-Wall选项):warning: multi-line comment [-Wcomment]     导致警告的代码是一个函数声明上面的注释,如下: /...
  • gemo
  • gemo
  • 2013年01月09日 17:44
  • 3595


*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Must tr...
  • u010558548
  • u010558548
  • 2015年05月19日 18:04
  • 2452
您举报文章:Multi-line/Autoresizing UITextView similar to SMS-app