先來(lái)看一下效果圖:
效果就如展示的一樣,彈出樣式也很簡(jiǎn)單,但是做這個(gè)我花費(fèi)了足足的一天時(shí)間,可能我對(duì) textview 的代理和鍵盤的通知之類的方法不是很了解,走了不少?gòu)澛啡鳌O旅婢徒o大家分享一下我做這個(gè)界面的兩個(gè)思路:
思路一:
將要彈出的視圖做為一個(gè) textFiled 的inputAccessoryView
這樣做的好處是不用處理彈出視圖的動(dòng)畫與鍵盤動(dòng)畫同步,也不用監(jiān)聽鍵盤的彈出收回事件蒜鸡。
我在控制器里聲明一個(gè) textFiled
@property (nonatomic, strong) UITextField *textFile;
在初始化的時(shí)候只alloc
而不給Frame
self.textFile = [UITextField new];
//加載到 view 中讓 view 持有避免回收
[self.view addSubview:self.textFile];
因?yàn)橄胫鲆粋€(gè)類似微信回復(fù)評(píng)論的那種杆麸,可以輸入多行有高度限制祝蝠,就在自定義 view 里面用到了 textview 的代理扭弧,第一步想到的代理就是用ViewDidChange
方法
- (void)textViewDidChange:(UITextView *)textView只锭;
通過(guò)這個(gè)代理來(lái)計(jì)算輸入文字的寬度谢澈,計(jì)算文字寬度是用的系統(tǒng)的字體Attribute
屬性
CGSize textSize = [textView.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:FontSize]}];
給 textview 一個(gè)固定寬度(或者在初始化視圖時(shí)獲取 textview 的寬度)芦劣,通過(guò)兩者比較來(lái)判斷輸入的文字是否換行粗俱,如果換行就把 textview 的高度和視圖本身的高度改變,改變的大小就是文字換行的大小虚吟。
在控制器里寸认,初始化自定義視圖:
self.inputAccessoryView = [[MReplyCommentView alloc] initWithFrame: CGRectMake(0, 0, windowRect.size.width, 50)];
self.textField.inputAccessoryView = self.inputAccessoryView;
這樣我在點(diǎn)評(píng)論按鈕的時(shí)候?qū)?code>textFiled變成鍵盤第一響應(yīng)就行了,鍵盤帶著輸入框就彈出來(lái)了串慰,很流暢偏塞。等等,不對(duì)啊邦鲫,自定義視圖里的 textview 并沒(méi)有進(jìn)入編輯狀態(tài)灸叼,也就是沒(méi)有光標(biāo)閃爍。然后我在自定義視圖init
方法里加了鍵盤的通知UIKeyboardWillShowNotification
:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
- (void)keyboardWillShow {
if (![self.textView isFirstResponder]) {
[self.textView becomeFirstResponder];
}
}
通過(guò) if 判斷來(lái)判斷 textv 是否為鍵盤第一響應(yīng)者庆捺。
輸入文字換行遇到的問(wèn)題
因?yàn)樽远x視圖的高度是寫死的為50古今,textview 的高度也是寫死的是30,(16號(hào)字體時(shí) textview 高度為36)在換行的時(shí)候光標(biāo)總是下移滔以,刪除字體換行的時(shí)候光標(biāo)會(huì)上移捉腥,每當(dāng)輸入當(dāng)前行最后一個(gè)字換到下一行時(shí)光標(biāo)就跑的很離譜。字體寬度我是通過(guò)計(jì)算字體的寬度來(lái)計(jì)算的你画,高度我是這樣計(jì)算的:
// TextView 大小
CGRect bounds = self.textView.bounds;
CGSize maxSize = CGSizeMake(bounds.size.width, CGFLOAT_MAX);
//用這個(gè)方法將得到的尺寸轉(zhuǎn)化為 textview 最適合的尺寸
CGSize newSize = [self.textView sizeThatFits:maxSize];
self.textView.frame = CGRectMake(10, 10, bounds.size.width, newSize.height);
但是每次一到換行的時(shí)候光標(biāo)就移動(dòng)的很離譜抵碟,而且 textview 有晃動(dòng),我以為是這個(gè)sizeThatFits
方法轉(zhuǎn)化的不是很準(zhǔn)確坏匪,我就打斷點(diǎn)一點(diǎn)一點(diǎn)看數(shù)據(jù)拟逮,發(fā)現(xiàn)也是正確的,這讓我感到很困惑适滓,我在網(wǎng)上查了下相關(guān)資料敦迄,都推薦讓用kvo 去監(jiān)聽 textview 的contentSize
屬性,我也借來(lái)用了一下:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
UITextView * view =(UITextView *)object;
if ([keyPath isEqualToString:@"contentSize"]) {
CGFloat height = view.contentSize.height;
if (height > 112) {
height = 112;
}
CGRect textViewFrame = self.textView.frame;
textViewFrame.size.height = height;
self.textView.frame = textViewFrame;
[self updateSelfOfTextViewSize];
}
}
發(fā)現(xiàn)比原來(lái)的要好很多,而且這個(gè)監(jiān)聽方法比 textview 的代理要好用的多颅崩,代理是沒(méi)次輸入字的時(shí)候都會(huì)去計(jì)算寬度几于,而這個(gè)監(jiān)聽只有 textview 換行的時(shí)候才會(huì)調(diào)用,而且換行高度也是字體高度⊙睾螅現(xiàn)在 textview 的光標(biāo)沒(méi)有跑那么離譜了沿彭,但是還是有 frame 設(shè)置的問(wèn)題,我百思不得其解尖滚,我隨意輸入幾行字喉刘,用 xcode 打開app 的圖層,發(fā)現(xiàn)光標(biāo)的高度在16號(hào)字體下竟然是36而不是30漆弄,導(dǎo)致每次換行都有誤差睦裳,設(shè)置好高度換行問(wèn)題都迎刃而解了。
點(diǎn)擊頁(yè)面空白處不能回收鍵盤問(wèn)題
我在控制器中設(shè)置取消編輯事件發(fā)現(xiàn)鍵盤不能回收撼唾,
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
而且在點(diǎn)擊控制器頁(yè)面的時(shí)候發(fā)現(xiàn)方法都不執(zhí)行廉邑,可能是我用一個(gè)三方IQKeyboardManager
的原因,也可能是圖層的原因倒谷,我也沒(méi)有追究到底是哪里的原因蛛蒙,我放棄了這種做法,因?yàn)槔速M(fèi)的時(shí)間已經(jīng)很多了渤愁。
思路二:
自定義視圖重寫-(instancetype)init
方法牵祟,將textview的初始化放在這里,分別加入鍵盤出現(xiàn)監(jiān)聽:UIKeyboardWillShowNotification
抖格,和消失監(jiān)聽UIKeyboardWillHideNotification
诺苹,通過(guò)對(duì)鍵盤的監(jiān)聽來(lái)設(shè)置自定視圖的Frame
和 textview 的動(dòng)畫,再加上上次踩的坑都一起設(shè)置完畢雹拄,run 了一下達(dá)到了預(yù)想的結(jié)果收奔,可能是因?yàn)槿綆?kù)IQKeyboard
的原因,每次彈出視圖办桨,控制器視圖會(huì)滾動(dòng)筹淫,所以在viewWillAppear
和viewWillDisappear
中加入了[IQKeyboardManager sharedManager].enable = NO;
將 IQ 的作用取消。具體代碼可以看一下 demo 點(diǎn)我下載呢撞。
總結(jié)
這個(gè)功能也不是很復(fù)雜损姜,花費(fèi)了一天時(shí)間才搞定。主要用的知識(shí)點(diǎn):對(duì) textview 做contentSize
kvo 監(jiān)聽殊霞,通過(guò)contentSize.height
來(lái)設(shè)定高度要比自己計(jì)算準(zhǔn)確的多摧阅,一定要根據(jù)字號(hào)高度把 textview 的初始化高度計(jì)算準(zhǔn)確,要不然光標(biāo)會(huì)跳躍绷蹲;通過(guò)監(jiān)聽鍵盤來(lái)做動(dòng)畫改變 frame棒卷。
最后再說(shuō)一點(diǎn)
此 demo 很簡(jiǎn)單顾孽,只適應(yīng)小工程,有興趣的同學(xué)可以試一下比规,如果你的工程里比如有界面套界面若厚,列表套列表,層級(jí)關(guān)系比較多蜒什,想彈鍵盤視圖可以將自定義 view 設(shè)置成單例测秸,這樣就好控制了。設(shè)置單例的時(shí)候要把-(void)close
方法中的[[NSNotificationCenter defaultCenter] removeObserver:self];
代碼注釋掉.