HPTextViewInternal.h
#import <UIKit/UIKit.h> @interface HPTextViewInternal : UITextView { } @end
HPTextViewInternal.m
#import "HPTextViewInternal.h" @implementation HPTextViewInternal - (void) setContentOffset:(CGPoint)s { if(self.tracking || self.decelerating) { 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); } } [super setContentOffset:s]; } - (void) setContentInset:(UIEdgeInsets)s { UIEdgeInsets insets = s; if(s.bottom > 8) insets.bottom = 0; insets.top = 0; [super setContentInset:insets]; } @end
HPGrowingTextView.h
#import <UIKit/UIKit.h> @class HPGrowingTextView; @class HPTextViewInternal; @protocol HPGrowingTextViewDelegate @optional - (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; - (void) growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height; - (void) growingTextView:(HPGrowingTextView *)growingTextView didChangeHeight:(float)height; - (void) growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView; - (BOOL) growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView; @end @interface HPGrowingTextView : UIView <UITextViewDelegate> { HPTextViewInternal *internalTextView; int minHeight; int maxHeight; int maxNumberOfLines; int minNumberOfLines; BOOL animateHeightChange; NSObject <HPGrowingTextViewDelegate> *delegate; NSString *text; UIFont *font; UIColor *textColor; UIColor *backgroundColor; UITextAlignment textAlignment; NSRange selectedRange; BOOL editable; UIDataDetectorTypes dataDetectorTypes; UIReturnKeyType returnKeyType; } @property int maxNumberOfLines; @property int minNumberOfLines; @property BOOL animateHeightChange; @property (retain) UITextView *internalTextView; @property (assign) NSObject<HPGrowingTextViewDelegate> *delegate; @property (nonatomic, assign) NSString *text; @property (nonatomic, assign) UIFont *font; @property (nonatomic, assign) UIColor *textColor; @property (nonatomic, assign) UIColor *backgroundColor; @property (nonatomic) UITextAlignment textAlignment; @property (nonatomic) NSRange selectedRange; @property (nonatomic, getter = isEditable) BOOL editable; @property (nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_3_0); @property (nonatomic) UIReturnKeyType returnKeyType; - (BOOL) hasText; - (void) scrollRangeToVisible:(NSRange)range; @end
HPGrowingTextView.m
#import "HPGrowingTextView.h" #import "HPTextViewInternal.h" @implementation HPGrowingTextView @synthesize internalTextView; @synthesize maxNumberOfLines; @synthesize minNumberOfLines; @synthesize delegate; @synthesize text; @synthesize font; @synthesize textColor; @synthesize backgroundColor; @synthesize textAlignment; @synthesize selectedRange; @synthesize editable; @synthesize dataDetectorTypes; @synthesize animateHeightChange; @synthesize returnKeyType; - (id) initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { CGRect r = frame; r.origin.y = 0; r.origin.x = 0; internalTextView = [[HPTextViewInternal alloc] initWithFrame:r]; internalTextView.delegate = self; internalTextView.scrollEnabled = NO; internalTextView.font = [UIFont fontWithName:@"Helvetica" size:13]; internalTextView.contentInset = UIEdgeInsetsZero; internalTextView.showsHorizontalScrollIndicator = NO; internalTextView.text = @"-"; [self addSubview:internalTextView]; UIView *internal = (UIView*)[[internalTextView subviews] objectAtIndex:0]; minHeight = internal.frame.size.height; minNumberOfLines = 1; animateHeightChange = YES; internalTextView.text = @""; [self setMaxNumberOfLines:3]; } return self; } - (void) sizeToFit { CGRect r = self.frame; r.size.height = minHeight; self.frame = r; } - (void) setFrame:(CGRect)aframe { CGRect r = aframe; r.origin.y = 0; r.origin.x = 0; internalTextView.frame = r; [super setFrame:aframe]; } - (void) setMaxNumberOfLines:(int)n { UITextView *test = [[HPTextViewInternal alloc] init]; test.font = internalTextView.font; test.hidden = YES; NSMutableString *newLines = [NSMutableString string]; if(n == 1) { [newLines appendString:@"-"]; } else { for(int i = 1; i < n; i++) { [newLines appendString:@"\n"]; } } test.text = newLines; [self addSubview:test]; maxHeight = test.contentSize.height; maxNumberOfLines = n; [test removeFromSuperview]; [test release]; } - (void) setMinNumberOfLines:(int)m { UITextView *test = [[HPTextViewInternal alloc] init]; test.font = internalTextView.font; test.hidden = YES; NSMutableString *newLines = [NSMutableString string]; if(m == 1) { [newLines appendString:@"-"]; } else { for(int i = 1; i < m; i++){ [newLines appendString:@"\n"]; } } test.text = newLines; [self addSubview:test]; minHeight = test.contentSize.height; [self sizeToFit]; minNumberOfLines = m; [test removeFromSuperview]; [test release]; } - (void) textViewDidChange:(UITextView *)textView { NSInteger newSizeH = internalTextView.contentSize.height; if(newSizeH < minHeight || !internalTextView.hasText) newSizeH = minHeight; if (internalTextView.frame.size.height != newSizeH) { if (newSizeH <= maxHeight) { if(animateHeightChange){ [UIView beginAnimations:@"" context:nil]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(growDidStop)]; [UIView setAnimationBeginsFromCurrentState:YES]; } if ([delegate respondsToSelector:@selector(growingTextView:willChangeHeight:)]) { [delegate growingTextView:self willChangeHeight:newSizeH]; } CGRect internalTextViewFrame = self.frame; internalTextViewFrame.size.height = newSizeH; self.frame = internalTextViewFrame; internalTextViewFrame.origin.y = 0; internalTextViewFrame.origin.x = 0; internalTextView.frame = internalTextViewFrame; if(animateHeightChange){ [UIView commitAnimations]; } } if (newSizeH >= maxHeight) { if(!internalTextView.scrollEnabled) { internalTextView.scrollEnabled = YES; [internalTextView flashScrollIndicators]; } } else { internalTextView.scrollEnabled = NO; } } if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) { [delegate growingTextViewDidChange:self]; } } - (void) growDidStop { if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) { [delegate growingTextView:self didChangeHeight:self.frame.size.height]; } } - (BOOL) resignFirstResponder { [super resignFirstResponder]; return [internalTextView resignFirstResponder]; } - (void) dealloc { [internalTextView release]; [super dealloc]; } #pragma mark UITextView properties - (void) setText:(NSString *)atext { internalTextView.text= atext; } - (NSString *)text { return internalTextView.text; } - (void)setFont:(UIFont *)afont { internalTextView.font = afont; [self setMaxNumberOfLines:maxNumberOfLines]; [self setMinNumberOfLines:minNumberOfLines]; } - (UIFont *)font { return internalTextView.font; } - (void) setTextColor:(UIColor *)color { internalTextView.textColor = color; } - (UIColor *)textColor { return internalTextView.textColor; } - (void) setBackgroundColor:(UIColor *)color { internalTextView.backgroundColor = color; } - (UIColor *) backgroundColor { return internalTextView.backgroundColor; } - (void) setTextAlignment:(UITextAlignment)aligment { internalTextView.textAlignment = aligment; } - (UITextAlignment) textAlignment { return internalTextView.textAlignment; } - (void) setSelectedRange:(NSRange)range { internalTextView.selectedRange = range; } - (NSRange)selectedRange { return internalTextView.selectedRange; } - (void) setEditable:(BOOL)beditable { internalTextView.editable = beditable; } - (BOOL) isEditable { return internalTextView.editable; } - (void) setReturnKeyType:(UIReturnKeyType)keyType { internalTextView.returnKeyType = keyType; } - (UIReturnKeyType) returnKeyType { return internalTextView.returnKeyType; } - (void) setDataDetectorTypes:(UIDataDetectorTypes)datadetector { internalTextView.dataDetectorTypes = datadetector; } - (UIDataDetectorTypes) dataDetectorTypes { return internalTextView.dataDetectorTypes; } - (BOOL) hasText { return [internalTextView hasText]; } - (void) scrollRangeToVisible:(NSRange)range { [internalTextView scrollRangeToVisible:range]; } #pragma mark - #pragma mark UITextViewDelegate - (BOOL) textViewShouldBeginEditing:(UITextView *)textView { if ([delegate respondsToSelector:@selector(growingTextViewShouldBeginEditing:)]) { return [delegate growingTextViewShouldBeginEditing:self]; } else { return YES; } } - (BOOL) textViewShouldEndEditing:(UITextView *)textView { if ([delegate respondsToSelector:@selector(growingTextViewShouldEndEditing:)]) { return [delegate growingTextViewShouldEndEditing:self]; } else { return YES; } } - (void)textViewDidBeginEditing:(UITextView *)textView { if ([delegate respondsToSelector:@selector(growingTextViewDidBeginEditing:)]) { [delegate growingTextViewDidBeginEditing:self]; } } - (void) textViewDidEndEditing:(UITextView *)textView { if ([delegate respondsToSelector:@selector(growingTextViewDidEndEditing:)]) { [delegate growingTextViewDidEndEditing:self]; } } - (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)atext { if(![textView hasText] && [atext isEqualToString:@""]) return NO; if ([atext isEqualToString:@"\n"]) { if ([delegate respondsToSelector:@selector(growingTextViewShouldReturn:)]) { if (![delegate performSelector:@selector(growingTextViewShouldReturn:) withObject:self]) { return YES; } else { [textView resignFirstResponder]; return NO; } } } return YES; } - (void) textViewDidChangeSelection:(UITextView *)textView { if ([delegate respondsToSelector:@selector(growingTextViewDidChangeSelection:)]) { [delegate growingTextViewDidChangeSelection:self]; } } @end
AddMessageViewController.h
#import <UIKit/UIKit.h> #import "HPGrowingTextView.h" @class ReceptionListViewController; @interface AddMessageViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate, HPGrowingTextViewDelegate> { UIView *_sendView; UIScrollView *_receptionView; UITextField *_receptionLabel; NSMutableArray *_receptionArray; NSMutableArray *_receptionDtoArray; HPGrowingTextView *_sendTextView; UITextField *_sendTextField; ReceptionListViewController *_receptionListViewController; UINavigationController *_receptionNavigationController; UIButton *_addButton; CGFloat _receptionWidth; CGFloat _receptionHeight; BOOL _isButtonDelete; BOOL _isToReceptionList; } @property (nonatomic, retain) IBOutlet UIView *sendView; @property (nonatomic, retain) IBOutlet UIScrollView *receptionView; @property (nonatomic, retain) HPGrowingTextView *sendTextView; @property (nonatomic, retain) IBOutlet UITextField *receptionLabel; @property (nonatomic, retain) NSMutableArray *receptionArray; @property (nonatomic, retain) NSMutableArray *receptionDtoArray; @property (nonatomic, retain) IBOutlet UITextField *sendTextField; @property (nonatomic, retain) IBOutlet ReceptionListViewController *receptionListViewController; @property (nonatomic, retain) IBOutlet UINavigationController *receptionNavigationController; @property (nonatomic, retain) IBOutlet UIButton *addButton; @property (nonatomic, assign) CGFloat receptionWidth; @property (nonatomic, assign) CGFloat receptionHeight; @property (nonatomic, assign) BOOL isButtonDelete; @property (nonatomic, assign) BOOL isToReceptionList; - (IBAction) dismissMyselfAction:(id)sender; - (IBAction) addReceptionAction:(id)sender; - (IBAction) sendMessageAction:(id)sender; - (void) initForPage; - (void) addReceiver; - (void) resumeView; - (IBAction) deleteButton:(id)sender; @end
AddMessageViewController.m
#import "AddMessageViewController.h" #import "ReceptionListViewController.h" @implementation AddMessageViewController @synthesize sendView = _sendView,receptionView = _receptionView; @synthesize receptionLabel = _receptionLabel, receptionArray = _receptionArray; @synthesize receptionListViewController = _receptionListViewController; @synthesize receptionNavigationController = _receptionNavigationController; @synthesize addButton = _addButton; @synthesize receptionWidth = _receptionWidth, receptionHeight = _receptionHeight; @synthesize isButtonDelete = _isButtonDelete; @synthesize sendTextField = _sendTextField; @synthesize isToReceptionList = _isToReceptionList; @synthesize receptionDtoArray = _receptionDtoArray; @synthesize sendTextView = _sendTextView; - (void) viewDidLoad { [super viewDidLoad]; self.receptionWidth = 62; self.receptionHeight = 6; self.sendTextView = [[HPGrowingTextView alloc] initWithFrame:CGRectMake(68, 205, 185, 35)]; self.sendTextView.minNumberOfLines = 1; self.sendTextView.maxNumberOfLines = 6; self.sendTextView.font = [UIFont systemFontOfSize:15.0f]; self.sendTextView.delegate = self; self.sendTextView.backgroundColor = [UIColor clearColor]; [self.view addSubview:self.sendTextView]; [self.sendTextView sizeToFit]; self.sendTextField.frame = CGRectMake(66, 5, 190, 36); NSMutableArray *array = [[NSMutableArray alloc] init]; self.receptionDtoArray = array; [array release]; self.view.backgroundColor = [UIColor colorWithRed:0.859f green:0.886f blue:0.929f alpha:1.0f]; self.receptionListViewController.addMessageViewController = self; } - (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self initForPage]; } - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (!self.isToReceptionList) { NSMutableArray *array = [[NSMutableArray alloc] init]; self.receptionDtoArray = array; [array release]; [self resumeView]; self.sendTextView.text = @""; self.sendView.frame = CGRectMake(0, 200, 320, 44); self.sendTextField.frame = CGRectMake(66, 5, 190, 36); self.sendTextView.frame = CGRectMake(68, 205, 185, 35); } } - (void)dealloc { [_sendView release]; [_receptionView release]; [_receptionLabel release]; [_receptionArray release]; [_receptionListViewController release]; [_receptionNavigationController release]; [_addButton release]; [_sendTextField release]; [_receptionDtoArray release]; [_sendTextView release]; [super dealloc]; } - (void) initForPage { [self.sendTextField becomeFirstResponder]; [self.receptionLabel becomeFirstResponder]; } - (void) addReceiver { [self resumeView]; NSMutableString *receiver = [[NSMutableString alloc] init]; NSMutableArray *tempArray = [[NSMutableArray alloc] init]; self.receptionArray = tempArray; [tempArray release]; for (int i = 0; i < self.receptionDtoArray.count; i++) { NSString *guideName = [self.receptionDtoArray objectAtIndex:i]; [self.receptionArray addObject:guideName]; UIFont *baseFone = [UIFont systemFontOfSize:12]; CGSize size = [guideName sizeWithFont:baseFone constrainedToSize:CGSizeMake(200, 1000) lineBreakMode:UILineBreakModeWordWrap]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:guideName forState:UIControlStateNormal]; UIImage *normalImage = [UIImage imageNamed:@"act-normal.png"]; [button setBackgroundImage:[normalImage stretchableImageWithLeftCapWidth:21 topCapHeight:14] forState:UIControlStateNormal]; [button setBackgroundImage:[normalImage stretchableImageWithLeftCapWidth:21 topCapHeight:14] forState:UIControlStateHighlighted]; UIImage *highImage = [UIImage imageNamed:@"act.png"]; [button setBackgroundImage:[highImage stretchableImageWithLeftCapWidth:21 topCapHeight:14]forState:UIControlStateDisabled]; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateDisabled]; button.titleLabel.font = [UIFont systemFontOfSize:12]; button.tag = i; [button addTarget:self action:@selector(deleteButton:) forControlEvents:UIControlEventTouchUpInside]; //设置按钮位置 if (self.receptionWidth + size.width + 10 >= 275) { self.receptionHeight = self.receptionHeight + size.height + 12; self.receptionWidth = 8; if (self.receptionHeight > 6.0f) { button.frame = CGRectMake(self.receptionWidth, self.receptionHeight, size.width + 18, 26); } else { button.frame = CGRectMake(self.receptionWidth - 52, self.receptionHeight, size.width + 18, 26); } } else { button.frame = CGRectMake(self.receptionWidth, self.receptionHeight, size.width + 18, 26); } [self.receptionView addSubview:button]; self.receptionWidth += size.width + 23; //设置隐藏的textfield中的值 if (i == self.receptionDtoArray.count - 1) { [receiver appendFormat:@"%@", guideName]; } else { [receiver appendFormat:@"%@,", guideName]; } } self.receptionLabel.text = receiver; self.addButton.frame = CGRectMake(280, self.receptionHeight, 29, 29); self.addButton.tag = 99; [self.receptionView addSubview:self.addButton]; //定义scrollview高度 self.receptionView.frame = CGRectMake(0, 44, 320, self.receptionHeight + 32); if (self.receptionView.frame.size.height >= 199 - self.sendView.frame.size.height) { self.receptionView.frame = CGRectMake(0, 44, 320, 199 - self.sendView.frame.size.height); } self.receptionView.contentSize = CGSizeMake(320, self.receptionHeight + 40); } //页面恢复原状,按钮全部去掉 - (void) resumeView { self.receptionView.frame = CGRectMake(0, 44, 320, 38); self.receptionView.contentSize = CGSizeMake(320, 38); self.receptionWidth = 62; self.receptionHeight = 6; for(UIView *subview in [self.receptionView subviews]) { if([[subview class] isSubclassOfClass:UIButton.class]){ UIButton *tipsButton = (UIButton *)subview; [tipsButton removeFromSuperview]; } } } - (IBAction) deleteButton:(id)sender { self.isButtonDelete = YES; NSMutableArray *tempArray = [[NSMutableArray alloc] init]; self.receptionArray = tempArray; [tempArray release]; for (int i = 0; i < self.receptionDtoArray.count; i++) { NSString *guideName = [self.receptionDtoArray objectAtIndex:i]; [self.receptionArray addObject:guideName]; } UIButton *button = (UIButton *)sender; //当选中当前按钮时,其他按钮恢复原状,可以点击 for(UIView *subview in [self.receptionView subviews]){ if([[subview class] isSubclassOfClass:UIButton.class]){ UIButton *tipsButton = (UIButton *)subview; if (tipsButton.tag != 99) { [tipsButton setEnabled:YES]; } } } //当前按钮进入选中状态而且不可点击 [button setEnabled:NO]; //删除替补数组中的信息 for (int i = 0; i < self.receptionArray.count; i++) { if (button.tag == i) { [self.receptionArray removeObject:[self.receptionArray objectAtIndex:i]]; } } } #pragma mark - #pragma mark TextField Delegate Method - (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSString *candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string]; if ([candidateString length] < [self.receptionLabel.text length]) { //如果是选中状态则删除对应按钮,不然就将最后一个联系人设为选中状态 if (self.isButtonDelete) { for (int i = 0; i < self.receptionDtoArray.count; i++) { NSString *guideName = [self.receptionDtoArray objectAtIndex:i]; if ([self.receptionArray containsObject:guideName]) { } else { [self.receptionDtoArray removeObject:guideName]; } } [self addReceiver]; self.isButtonDelete = NO; } else { //将scrollview子视图里面联系人的按钮存放在新的数组里 NSMutableArray *tempArray = [[NSMutableArray alloc] init]; for(UIView *subview in [self.receptionView subviews]){ if([[subview class] isSubclassOfClass:UIButton.class]){ UIButton *tipsButton = (UIButton *)subview; if(tipsButton.tag != 99){ [tempArray addObject:tipsButton]; } } } if ([[self.receptionView subviews] count] != 1) { for(UIButton *button in tempArray){ if (button == [tempArray lastObject]) { [self deleteButton:button]; } } } } } return NO; } - (void) growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height { float diff = (self.sendTextView.frame.size.height - height); CGRect r = self.sendTextView.frame; r.origin.y += diff; self.sendTextView.frame = r; CGRect sendFrame = self.sendView.frame; sendFrame.origin.y += diff; sendFrame.size.height -= diff; self.sendView.frame = sendFrame; CGRect textFieldFrame = self.sendTextField.frame; textFieldFrame.size.height -= diff; self.sendTextField.frame = textFieldFrame; } - (BOOL) growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView { [self.receptionLabel setHidden:NO]; [self resumeView]; return YES; } - (BOOL) textFieldShouldBeginEditing:(UITextField *)textField { //切换textfield的状态 if (textField == self.receptionLabel) { [self.receptionLabel setHidden:YES]; [self addReceiver]; } return YES; } - (IBAction) dismissMyselfAction:(id)sender { self.isToReceptionList = NO; [self dismissModalViewControllerAnimated:YES]; } - (IBAction) addReceptionAction:(id)sender { self.isToReceptionList = YES; [self presentModalViewController:self.receptionNavigationController animated:YES]; } @end
示例图: