iOS 一步步封装一个微信键盘

作者: 雪_晟 | 来源:发表于2017-03-09 13:36 被阅读1462次

    效果图:


    键盘.gif

    前言:要做成上面的效果图,需要我们自定义键盘。但是上面的键盘一个view 就可以搞定,可是下面的表情或者扩展怎么处理呢,有人说用UITextview的inputView 处理,可是在使用inpuview的时候,处理表情键盘或者扩展键盘,UITextview会一直成为响应者,光标会一直存在,所以我们把辅助键盘放在 下面。

    如图:


    说明.png
    大概思路就是 点击键盘上UITextview的时候,让UITextview成为第一响应者,点击语音按钮,表情按钮,more 按钮,让UITextview取消第一响应者,然后把辅助键盘视图放置在键盘的下方。
    1、 首先,我们自定义一个view,ChatBox。设置几种 键盘状态
    typedef NS_ENUM(NSInteger, LXChatBoxStatus) {
        LXChatBoxStatusNothing,     // 默认状态
        LXChatBoxStatusShowVoLXe,   // 录音状态
        LXChatBoxStatusShowFace,    // 输入表情状态
        LXChatBoxStatusShowMore,    // 显示“更多”页面状态
        LXChatBoxStatusShowKeyboard,// 正常键盘
        LXChatBoxStatusShowVideo    // 录制视频
    };
    

    @property(nonatomic,assign)LXChatBoxStatus status;

    在点击按钮或者 编辑UITextview的时候设置状态:
    #pragma mark---textview--代理方法---
    -(void)textViewDidBeginEditing:(UITextView *)textView{
        if (self.status != LXChatBoxStatusShowKeyboard) {
            self.status = LXChatBoxStatusShowKeyboard;
    
        }
            [self changeFrame:ceilf([textView sizeThatFits:textView.frame.size].height)];
    }
    
    #pragma mark---Event Responds---
    
    -(void)voiceButtonDown:(UIButton *)button{
        
        button.selected = !button.selected;
        if (button.selected) {
            self.status = LXChatBoxStatusShowKeyboard;
        }else{
            self.status = LXChatBoxStatusShowVoLXe;
        }
        
    }
    -(void)faceButtonDown:(UIButton *)button{
        button.selected = !button.selected;
        if (button.selected) {
            self.status = LXChatBoxStatusShowFace;
        }else{
            self.status = LXChatBoxStatusShowKeyboard;
        }
       
        
    }
    -(void)moreButtonDown:(UIButton *)button{
        button.selected = !button.selected;
        if (button.selected) {
            self.status = LXChatBoxStatusShowMore;
        }else{
            self.status = LXChatBoxStatusShowKeyboard;
        }
    }
    
    通过设置键盘状态,在设置状态里对键盘视图的隐藏做一些处理。调整高度
    -(void)setStatus:(LXChatBoxStatus)status{
        if (_status == status) {
            return;
        }
        _status = status;
        switch (_status) {
            case LXChatBoxStatusNothing:
            {
                self.voiceButton.selected = YES;
                self.faceView.hidden = self.moreView.hidden = YES;
                [self.textView resignFirstResponder];
                [UIView animateWithDuration:0.3 animations:^{
                    self.frame = CGRectMake(0, KScreenH - self.textView.height - 2 *BOXTEXTViewSPACE, KScreenW, self.textView.height + 2 *BOXTEXTViewSPACE);
    
                }];
            }
                
               
                break;
            case LXChatBoxStatusShowKeyboard:
            {
                self.faceView.hidden = self.moreView.hidden = YES;
    
                self.voiceButton.selected = YES;
                self.textView.hidden = NO;
                self.talkButton.hidden = YES;
                self.faceButton.selected= NO;
                
                [UIView animateWithDuration:0.3 animations:^{
                    self.frame = CGRectMake(0, self.y, KScreenW, self.textView.height + 2 *BOXTEXTViewSPACE);
                    
                }];
                 [self.textView becomeFirstResponder];
            }
            break;
            case LXChatBoxStatusShowVoLXe:
            {
                self.faceView.hidden = self.moreView.hidden = YES;
    
                [self.textView resignFirstResponder];
                self.voiceButton.selected = NO;
                self.talkButton.hidden = NO;
                self.textView.hidden = YES;
                [UIView animateWithDuration:0.3 animations:^{
                    [self voiceResetFrame];
                }];
    
            }
                
                break;
            case LXChatBoxStatusShowFace:
            {
                if (self.textView.isFirstResponder) {
                    [self.textView resignFirstResponder];
                }
                
    
                self.voiceButton.selected = YES;
                self.moreView.hidden = YES;
                self.faceView.hidden = NO;
                
                self.height = self.textView.height+2 *BOXTEXTViewSPACE + BOXOTHERH;
                self.y = KScreenH - self.height;
                self.bottomCotainer.y = self.textView.height + 2 *BOXTEXTViewSPACE;
    
            }
                
                break;
            case LXChatBoxStatusShowMore:
            {
                
    
                if (self.textView.isFirstResponder) {
                    [self.textView resignFirstResponder];
                }
                
                self.voiceButton.selected = YES;
                self.moreView.hidden = NO;
                self.faceView.hidden = YES;
    
                self.height = self.textView.height+2 *BOXTEXTViewSPACE + BOXOTHERH;
                self.y = KScreenH - self.height;
                self.bottomCotainer.y = self.textView.height + 2 *BOXTEXTViewSPACE;
            }
            default:
                break;
        }
        if ([self.delegate respondsToSelector:@selector(changeStatusChat:)]) {
            [self.delegate changeStatusChat:self.y];
        }
    }
    
    
    2、但是,只是在状态里设置键盘高度是不够的,如果我们点击UITextview,执行顺序是这样的:

    (1) -(void)keyboardWillChangeFrame:(NSNotification *)notification
    (2) -(void)textViewDidBeginEditing:(UITextView *)textView

    所以说,如果没有点击其他按钮(声音,表情,更多),点击了UITextview,在-(void)textViewDidBeginEditing:(UITextView *)textView设置键盘状态是没有用的,所以要键盘通知里做处理
    -(void)keyboardWillChangeFrame:(NSNotification *)notification{
        
       
        //因为在 切换视图的时候,点击了表情按钮,或者更多按钮,输入框是,键盘弹出在textViewDidBeginEditing 这个方法调用之前就会调用,
    //        self.height = self.textView.height + 2 *BOXTEXTViewSPACE;
        if (self.status == LXChatBoxStatusShowMore ||self.status == LXChatBoxStatusShowFace) {
            return;
        }
    
    3、 针对键盘高度改变设置代理接口
    @property(nonatomic,weak)id<LXChatBoxDelegate>delegate;
    
    在键盘高度改变的地方设置代理(键盘状态改变得地方),(键盘Textview文字 改变的地方)(键盘通知),
     if ([self.delegate respondsToSelector:@selector(changeStatusChat:)]) {
            [self.delegate changeStatusChat:self.y];
        }
    

    关于 接口:@property(nonatomic,assign)BOOL isDisappear;//为了在侧滑返回的时候自定义键盘与 键盘一体,可以参考文章:一体键盘
    demo 地址:仿微信键盘

    相关文章

      网友评论

      • lei_wang_ph:self.navigationController.navigationBar.translucent = NO;
        这样之后你的工具栏的高度会乱掉
        雪_晟:@王子袭来了 最简单的就是在这个页面设置透明度为yes 其他页面设置为no
        lei_wang_ph:@雪_晟 那修改哪里啊,看你的代码看了俩小时了
        雪_晟:@王子袭来了 那是肯定的 导航栏的透明度会影响啊
      • 十八掌:我想问一下 我把你这个导入到我的项目中,在运行的时候有一个问题:点击输入框之后键盘会弹出来然后又消失了,keyboardWillChangeFrame这个方法会走两遍。相当于是第一遍键盘弹出来,再走第二遍的时候键盘就消失了。这个是什么情况了?
        雪_晟:@十八掌 又消失的原因呢 是什么操作呢 是这个原因导致的吧
        十八掌:@雪_晟 我用的是苹果系统的键盘
        雪_晟:@十八掌 是不是输入法切换了?
      • mf168:不错
      • ebay_Happy:可以,跟我做的思路差不多。谢谢分享
        雪_晟:@ebay_Happy 好的 感谢分享啊
        ebay_Happy:@雪_晟 说说我的思路,你要把每个点击状态判断到,还有表情包跟语音的处理。最后是table高度跟不同cell的 加载事件
        雪_晟:@ebay_Happy 不太好 其实
      • 香橙柚子:刚刚给你加了一个star
        雪_晟:@iOS_xuanhe 因为中间有表情所以需要转成富文本,如果也是字符串比较快捷一点的也是转成富文本,要么就是在刚开始做个判断,判断是否含有表情这些等特殊字符,比较急的话就全部转为富文本计算,也是一样的
        香橙柚子:@雪_晟 问你个问题,你这个键盘发送内容,发送的是富文本吧,我用你的键盘集成在融云sdk的时候,融云发送的消息都是字符串,这个怎么解决?
        雪_晟:@iOS_xuanhe 感谢大佬:smile:
      • 香橙柚子:有空可以优化一下,发送图片功能.这个也挺长用的.
        香橙柚子:@雪_晟 可以适配一下iPhone X了.
        雪_晟:@iOS_xuanhe 好的,近期项目有点赶,
      • JohnQ:博主,你能不能在这个原框架上进行修改一下啊!我看了一下你的代码然后在看了原框架代码感觉你修改了很多啊!我按照你的思路去修改后一塌糊涂
        雪_晟:@JohnQ 没有按照原框架的来,只是借鉴了那个思路,只许表情与文字互转,直接用了就
        雪_晟:@JohnQ 这个其实实现的不是很好 大体思路是这样的 ,可以利用inputView 做
      • 80245bab5416:请问 当自定义的图片表情进入到cell后 如何从cell中获取到图片表情的名称? 另外还请问自定义表情在进入输入框的时候如何变成图片而不是文字?
        雪_晟:在 分类 #import "NSString+Extension.h" 里做了处理,把文字转换为表情。

      本文标题:iOS 一步步封装一个微信键盘

      本文链接:https://www.haomeiwen.com/subject/btswgttx.html