缘由
看了很多输入框,处理的最好的,就是微信,QQ,以及支付宝,其他的看了不少,包括百思,简书,same.微信,QQ,支付宝的就不做gif了。百思之前的版本输入框做的也不好,后来反馈了之后换了一种方式而已。拿简书和same举个列子。(ps:same 是同事推荐,我也不知道是什么软件,此处没有打广告)
简书:
可以看到在返回的时候输入框会跳跃到键盘下方,然后很快再出来。(做的好的会一体返回)
问题2:在限制多行之后,就会出现最上面的一行显示不全。
same
问题:same的输入框和简书的如出一辙,在侧滑返回的时候会跳跃。
有两种思路,推荐第二种。第一种因为有系统默认的上下间距,动画效果不好。第二种我们可以关闭掉系统的默认间距,为textView添加一个假的上下间距,动画会比较自然。
第一种:利用textview自定义键盘,限制多行输入。
关于跳跃问题,实现一体键盘,参考文章:iOS 怎么做成和微信一样的一体键盘?
限制多行问题,讨论一下。
UITextView
有默认的上下间距是8
,打印textContainerInset
是可以测出来的。微信的输入框在单行的时候保持了默认的上下间距8,但是在大于一行文字后上下间距就会变化。
为了做的和微信输入框很像,我们在限制了最大行数之后,可以设置textView
的setContentOffset
属性,滚动距离为(当前行数 - 限制的最大行数)* lineHeight + 上边距。即可。为了过渡效果,在超出限制最大行数时候关闭掉系统的默认动画[self.textView setContentOffset:point animated:NO]
,否则在回退的时候会很丑,在小于最大行数是使用系统的动画效果[self.textView setContentOffset:CGPointZero animated:YES];
if (line >self.maxLine) {
CGPoint point = CGPointMake(0, (line -self.maxLine) *lineH +8 );
[self.textView setContentOffset:point animated:NO];
self.textView.lx_height = ceil(self.maxLine *lineH +8);
}else{
self.textView.lx_height = contentSizeH;
[self.textView setContentOffset:CGPointZero animated:YES];
还有一点需要说明,输入框的初始高度,因为textView的默认上下间距,我们需要计算好初始高度,经过测试,如果textView font大小为16时,系统的默认高度最好设置为36. 当textView font大小为16时,lineHeight为19.09,加上上下间距为35.09,系统取了36.
所以初始化高度为:
CGFloat orignTextH = ceil (TEXTFONT.lineHeight + 16);
self.frame = CGRectMake(0, Device_Height - orignTextH, Device_Width, orignTextH);
一体键盘的处理:
-(void)keyboardWillChangeFrame:(NSNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
// 动画的持续时间
double duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 键盘的frame
CGRect keyboardF = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// NSLog(@"%@",NSStringFromCGRect(keyboardF));
keyboardY = keyboardF.origin.y;
if (!_isDisappear) {
[self dealKeyBoardWithKeyboardF:keyboardY duration:duration];
}
}
-(void)keyboardDidChangeFrame:(NSNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
// 动画的持续时间
double duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 键盘的frame
CGRect keyboardF = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// NSLog(@"%@",NSStringFromCGRect(keyboardF));
keyboardY = keyboardF.origin.y;
// // 工具条的Y值 == 键盘的Y值 - 工具条的高度
if (_isDisappear) {
[self dealKeyBoardWithKeyboardF:keyboardY duration:duration];
}
}
#pragma mark---处理高度---
-(void)dealKeyBoardWithKeyboardF:(CGFloat)keyboardY duration:(CGFloat)duration {
if (!_isDisappear) {
[UIView animateWithDuration:duration animations:^{
// 工具条的Y值 == 键盘的Y值 - 工具条的高度
if (keyboardY > Device_Height) {
self.lx_y = Device_Height- self.lx_height;
}else
{
self.lx_y = keyboardY - self.lx_height;
}
}];
}else{
if (keyboardY > Device_Height) {
self.lx_y = Device_Height- self.lx_height;
}else
{
self.lx_y = keyboardY - self.lx_height;
}
}
}
第二种 关闭掉系统对
textView
的默认间距。
如图,我们给textView
一个上下间距,然后再做动画就比较自然.
#pragma mark---getter---
-(LXTextView *)textView{
if (!_textView) {
_textView =[[LXTextView alloc]initWithFrame:CGRectMake(0, self.topOrBottomEdge, self.lx_width - 60, ceil(self.font.lineHeight))];
_textView.font = self.font;
_textView.delegate = self;
_textView.layoutManager.allowsNonContiguousLayout = NO;
_textView.enablesReturnKeyAutomatically = YES;
_textView.scrollsToTop = NO;
_textView.textContainerInset = UIEdgeInsetsZero; //关闭textview的默认间距属性
_textView.textContainer.lineFragmentPadding = 0;
_textView.placeholder = @"发表评论:";
}
return _textView;
}
在处理文字变化的代理方法更改如下:
-(void)textViewDidChange:(UITextView *)textView{
CGFloat contentSizeH = self.textView.contentSize.height;
CGFloat lineH = self.textView.font.lineHeight;
CGFloat maxHeight = ceil(lineH * self.maxLine + textView.textContainerInset.top + textView.textContainerInset.bottom);
if (contentSizeH <= maxHeight) {
self.textView.lx_height = contentSizeH;
}else{
self.textView.lx_height = maxHeight;
}
[textView scrollRangeToVisible:NSMakeRange(textView.selectedRange.location, 1)];
CGFloat totalH = ceil(self.textView.lx_height) + 2 * self.topOrBottomEdge;
self.frame = CGRectMake(0, keyboardY - totalH, self.lx_width, totalH);
self.sendBtn.lx_height = totalH;
self.line.lx_height = totalH - 10;
}
补充一点:为了适配iOS11
以下,需要处理textView
,否则xcode9
写的代码在iOS11
以下的设备上跑的时候回跳动。
textView做如下处理:
if (@available(iOS 11.0, *)) {
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
控制器中添加处理:
if (@available(iOS 11.0, *)) {
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// 这部分使用到的过期api
self.automaticallyAdjustsScrollViewInsets = NO;
#pragma clang diagnostic pop
}
demo中没有第一种效果,上面就是探路的思路。demo
中的第二种效果支持代码以及XIB创建keyboard
.
demo 地址:一体键盘,限制最大行数
博客推荐:https://4xx.me