我們在朋友圈,qq空間或微博的app看到這樣的操作,點擊回復,在視圖的下面立即顯示一個輸入框。輸入我們的文字後點擊發送就可以。那麼這個小小的輸入框是怎麼實現的呢
我也試著自己寫了一個小小對話框,先看一下樣式
主要的功能有
通過功能區分我們可以大致將該視圖分成三個部分,第一個是分割線,寬度為1的UIView
,第二個是類似html中的具有placeHolder功能的輸入框,最後是按鈕button。
輸入框是由UILabel
+UITextView
+UIImageView
(藍色線)實現的,UITextView
的內容長度變化可以通過監聽UITextViewTextDidChangeNotification
來判斷當前輸入框的輸入字數。
先建一個類繼承UITextView
添加placeText和placeColor到頭文件由於外部改變placetext內容,現在添加UILable
-(void)PlaceTextLabel{
if (self.placeText.length>0) {
if (!_placeTextLab) {
CGRect frame=CGRectMake(8,8, self.bounds.size.width-16, 0);
_placeTextLab=[[UILabel alloc]initWithFrame:frame];
_placeTextLab.font=self.font;
_placeTextLab.backgroundColor=[UIColor clearColor];
_placeTextLab.textColor=self.placeColor;
_placeTextLab.tag=999;
_placeTextLab.alpha=0;
_placeTextLab.lineBreakMode=NSLineBreakByWordWrapping;
_placeTextLab.numberOfLines=0;
[self addSubview:_placeTextLab];
}
_placeTextLab.text=self.placeText;
[_placeTextLab sizeToFit];
[_placeTextLab setFrame:CGRectMake(8, 8, CGRectGetWidth(self.bounds)-16, CGRectGetHeight(_placeTextLab.frame))];
}
if (self.text.length==0 && self.placeText.length>0) {
[[self viewWithTag:999]setAlpha:1.0];
}
}
用Photoshop做一個單行像素的類似藍線的圖片,保存為png格式,必須設置圖片的UIImageView
的圖片顯示模式
-(void)addLineView{
[_subLine removeFromSuperview];
_subLine=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"subline.png"]];
[_subLine setContentMode:UIViewContentModeScaleToFill];
[self addSubline:_subLine];
}
UITextView
的設置會相對麻煩一些,重寫初始化代碼
-(instancetype)initWithFrame:(CGRect)frame PlaceText:(NSString *)placeText PlaceColor:(UIColor *)placeColor{
self=[super initWithFrame:frame];
if (self) {
self.scrollEnabled=NO;
_placeText=placeText;
_placeColor=placeColor;
_Textnil=YES;
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(TextChange:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}
由於輸入框會隨著輸入的文字而不斷增高,我們需要把這個值傳遞給父視圖,讓父視圖也能根據內容而增大,可以通過委托來,但是委托又有點重量級,這裡我們可以用更簡單的block
這裡首先我想到的是通過監聽UITextViewTextDidChangeNotification
來實時監測輸入,輸入實時變化引起高度的實時變化。但是不幸的是我掉坑裡了,我發現當我們輸入一行到頭以後再輸入一個字符換行後,這個時候高度居然沒有變。再輸入這一行的第二個字符時候,高度值才發生變化。我想應該是高度變化之前,已經發送了通知所以導致我們的高度變化其實不是實時的,如果這樣就不能用這種方式了,所幸的我們還可以使用UITextView
的一個簡單函數
CGSize size= [self sizeThatFits:CGSizeMake(self.contentSize.width, 1000.0)];
這樣size就是我們要的大小了。
-(void)TextChange:(NSNotification *)notification{
if (self.text.length==0) {
_Textnil=YES;
}else{
_Textnil=NO;
}
[self addLineView];
if (self.placeText.length==0) {
return;
}
[UIView animateWithDuration:0.5 animations:^{
if (_Textnil) {
[[self viewWithTag:999]setAlpha:1.0];
}else{
[[self viewWithTag:999] setAlpha:0];
}
}];
}
-(void)addSubline:(UIView *)view{
CGSize size= [self sizeThatFits:CGSizeMake(self.contentSize.width, 1000.0)];
if (view) {
CGRect frame=CGRectMake(2, size.height-3, self.bounds.size.width-4, 3.0);
view.frame=frame;
}
[self addSubview:view];
self.viewSize(size);//先判斷一下更好。。。
}
這裡使用block傳遞size,我們先聲明一個block的私有變量,再寫一個方法用來賦值,block的實現也是由調用該對象的類創建的。然後像委托一樣調用就可以,AFNetwork中我們可以到處看到block而不像他的前輩ASIhttprequest到處是委托。
主要的輸入框完工後,就能組裝了,先新建一個UIview子類。UIView需要和鍵盤高度保持一致。需要監聽鍵盤滑出滑入的通知UIKeyboardWillChangeFrameNotification
,實時改變輸入框的高度
-(void)keyboardWillShow:(NSNotification *)notification{
NSDictionary *userInfo=[notification userInfo];
NSTimeInterval boardAnimationDuration=[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame=[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];
[UIView animateWithDuration:boardAnimationDuration delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGFloat keyBoardY=frame.origin.y;
CGFloat keyBoardHeigh=frame.size.height;
maxy=[UIScreen mainScreen].bounds.size.height-keyBoardHeigh;
CGRect frame=self.frame;
frame.origin.y=keyBoardY-CGRectGetHeight(self.frame);
self.frame=frame;
} completion:^(BOOL finished) {
nil;
}];
}
這裡的maxY是指輸入框的y方向的標准位置。在沒有鍵盤的情況下是[UIScreen mainScreen].bounds.size.height
,在有鍵盤的情況是鍵盤的y值,在輸入框字符變化的時候實時改變他的高度
如下面圖所示
-(void)TextViewDidChange:(CGSize)size{
self.frame=CGRectMake(0, self.frame.origin.y, self.frame.size.width,size.height+6*2);
self.frame=CGRectMake(0,maxy-self.frame.size.height, self.frame.size.width, self.frame.size.height);
_Inputview.frame=CGRectMake(10, 6, self.frame.size.width-K_right_padding, size.height);
}
以上是比較重要的UIView高度自適應變化的問題
這裡button與外部類的調用關系也采用的是block的方式
@property (nonatomic,copy)void(^sendText)(NSString *);
-(void)sendMessage:(void (^)(NSString * text))inputText{
if (inputText) {
self.sendText=inputText;
}
}
-(void)buttonClick{
[self sendInputText];
}
-(void)sendInputText{
if (_Inputview.Textnil) {
return;
}else{
if(self.sendText){
self.sendText(_Inputview.text);
_Inputview.text=@"";
}
}
}
最後附上我的sourceCode,獻給那些在ios道路上一起默默前進的小白們,我也是小白,求寬恕的對待O(∩_∩)O