即时通讯整个页面的搭建(二)

作者: CoderFM | 来源:发表于2016-09-25 21:13 被阅读342次

接着即时通讯整个页面的搭建(一)继续写

上一篇说完了控制器, 这一篇说说Cell, 底部ToolBar以及录音的显示的View, 约束嘛, 用的Masonry

IMBaseCell

这个属性是一个枚举值

typedef enum{
    IMBaseCellDefaultStyle = -1, // 默认状态  左边
    IMBaseCellLeftStyle, //左边的状态
    IMBaseCellRightStyle  // 右边的状态
} IMBaseCellStyle;

一开始是没有这个属性的, 直接就是一个isLeft判断, (当然正常的一个即时通讯的判断是不会放在外面的), 后来运行发现, Masony每一次reMake约束, 很耗时, 所以采用一个属性保存之前的样式, 和当前样式一样, 就不用再去改变约束了, 相对而言, 要提升一点流畅度

@property(nonatomic, assign)IMBaseCellStyle style;

这是一个Block属性, 是为了cell的Item变量改变,让控制器的数组的也同时更新,(一切显示靠模型去控制), 会有下载的进度的改变等等

@property(nonatomic, copy)void(^reloadCell)(IMBaseItem *messageItem);

查看图片, 以及播放视频的需要跳转, 很喜欢用block, 但是像这种情况还是选择了代理(具体哪里该使用代理, 哪里使用block, 不是很清楚, 有的人说block跟踪代码不方便, 代理点一下就跳过去了, 说的也是, 不过自己写的代码, 跟踪肯定是没问题的, 各有优劣吧, 全凭自己选择)

@property(nonatomic, weak)id<IMBaseCellDelegate> delegate;

看看让代理干了啥

/**
 *  点击视频,图片的代理方法
 *
 *  @param cell           点击的cell
 *  @param viewController 实例化好的控制器
 *  @param animated       是否动画过去
 *  @param completion     动画完成后要执行的代码
 */
- (void)IMBaseCell:(IMBaseCell *)cell presentViewController:(UIViewController *)viewController animated:(BOOL)animated completion:(void(^)())completion;
/**
 *  重新发送(发送失败的情况下)
 */
- (void)IMBaseCell:(IMBaseCell *)cell reSendMessage:(IMBaseItem *)message;
/**
 *  点击了语音播放(上一篇已经讲过连续播放)
 */
- (void)IMBaseCellClickAudioCell:(IMBaseCell *)cell;

cell里没有太多的逻辑代码, 其他的就是赋值了

其他就没有了(子弟动手,丰衣足食😀), 因为是demo, 并没有联网的, 所以上传,下载的进度, 运行时没有显示的, 代码已经注释了, 具体这个进度怎么监听的, 放到下一篇, 上传,下载的方法里(因为用的AFN2.x的版本, 并没有3.0里的block回调, 所以只能用kvo了),也是懵了一会,最后也想了这个办法解决, 有更好的方法,可以告诉我,不慎感激

下面说说底部的工具栏吧

IMChatToolBar

直接上代码

@property(nonatomic, weak)id<IMChatToolBarDelegate> delegate;

@property(nonatomic, weak)PlacehodeTextView *inputTextView;
/**
 *  实例化一个toolBar
 *
 *  @param frame          尺寸
 *  @param toolBarHeight  toolBar的高度
 *  @param moreViewHeight 更多的View的高度
 *
 *  @return 实例
 */
- (instancetype)initWithFrame:(CGRect)frame toolBarHeight:(CGFloat)toolBarHeight moreViewHeight:(CGFloat)moreViewHeight;
/**
 *  回到最底部
 */
- (void)backOriginalHeight;
/**
 *  隐藏
 */
- (void)hide;
/**
 *  显示
 */
- (void)show;

代理的方法

/**
 *  刷新消息
 */
- (void)IMChatToolBar:(IMChatToolBar *)chatToolBar imBaseItem:(IMBaseItem *)messageItem;
/**
 *  发送多条
 *
 *  @param schoolChatToolBar 
 *  @param messageItem       消息体
 */
- (void)IMChatToolBar:(IMChatToolBar *)chatToolBar sendIMBaseItem:(IMBaseItem *)messageItem;

/*
 *  键盘弹出  更新外部高度
 */
- (void)IMChatToolBar:(IMChatToolBar *)schoolChatToolBar ReloadHeight:(CGFloat)reloadHeight;

主要说一下更新高度, 这个给一个代理方法, 这个高度, 是toolBar的顶部具体屏幕底部的距离, 控制器的View拿到这个高度做响应的增减即可

具体看看实现吧 ↘️⤵️↙️
demo更多里值有拍照, 选择照片, 还有视频, 这里偷懒了, 因为选择照片这些都需要一个控制器的, 也是因为我自己知道, 我的toolBar代理是控制器才敢这么写的😋
应该加一层isKindIfClass判断

@property(nonatomic, weak)UIViewController *viewController;

- (void)setDelegate:(id<IMChatToolBarDelegate>)delegate{
    _delegate = delegate;
    self.viewController = (UIViewController *)delegate;
}

这么写的好处就是选择照片上传的代码就不用放在控制器里了, toolBar就能搞定,当然不一定合理(好用的就是合理的😀, 开玩笑啦), 所以基本上, 发送消息的活都让toolBar干了 控制器只要刷新数据就好了

说一个监听textView发送键的时间

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    
    if ([text isEqualToString:@"\n"]) {
        
        [self sendText:[self emotionText]];
        
        return NO;
    }
    
    return YES;
}

说到发送消息, 想到了自定义键盘时候(这里的键盘用的袁崢),表情编码与解码, 也是一个坑, 写好的正则表达式,在网站里测试是正常的到代码里就不行了, 只能采用暴力的方法解决(性能不好, 有好的方法可以讨论),例如匹配[1]这样的中括号中间是数字的字符串的正则表达式该怎么写(会的请评论一下喔,感激不尽)
既然要要自定义键盘, 那肯定要切换键盘了, 改变inputView即可
感兴趣的可以研究一下袁峥的表情键盘

self.emoticonButton.selected = !self.emoticonButton.isSelected;

if (self.emoticonButton.selected) {
        self.audioButton.hidden = YES;
        self.recordButton.selected = NO;
        self.inputTextView.yz_emotionKeyboard = self.emotionKeyboard;
        [self.inputTextView becomeFirstResponder];
    } else {
        self.inputTextView.yz_emotionKeyboard = nil;
        [self reloadInputViews];
}

上传下载发送消息的到下一篇再说吧

再看一下录音时候的提示,完全模仿微信的提示写的

IMVoiceVolumeView

/**
 *  根据声音大小显示不同view
 *
 *  @param volumn 声音的分贝大小
 */
- (void)volunmeWithSound:(CGFloat)volumn;
/**
 *  取消录音的样式
 */
- (void)volunmeViewCancel;
/**
 *  正常的样式
 */
- (void)volunmeViewNormal;
/**
 *  倒计时时间样式
 */
- (void)volunmeViewCountDown;
/**
 *  开始倒计时的方法
 */
- (void)volunmeViewCountDownBegin;
/**
 *  显示录音太短
 */
- (void)showShortTimeModel;
/**
 *  说话过长
 */
- (void)showLongTimeModel;

试了一下微信(平时经常用,但还真没留意过),大概就这个几种模式吧
看模式前,看一下按钮的监听方法

// 开始录音
- (void)recordButtonTouchDown
{
    self.volumeView.hidden = NO;
    [self.volumeView volunmeViewNormal];
}
// 取消录音
- (void)recordButtonTouchUpOutside// 滑出  并不在按钮上
{
    self.volumeView.hidden = YES;
}
// 完成录音
- (void)recordButtonTouchUpInside
{
    self.volumeView.hidden = YES;
    [[IMAudioTool shareAudioTool] startEncode];
}
// 滑出按钮  但按钮还在响应点击事件
- (void)recordDragOutside
{
    [self.volumeView volunmeViewCancel];
}
// 滑入按钮范围
- (void)recordDragInside
{
    [self.volumeView volunmeViewNormal];
}
  • 正常的样式

就是会显示录音波动的效果, 大小声测试了一下, -30 - 0的取值范围, 5个音量级别(音量的分贝传过来是用IMAudioTool单例传值的, 具体就下一篇说说, 😋)

  • 录音过短模式

低于最短限制(避免误点)

  • 取消录音的模式

向上滑动松开取消,(超出按钮的范围显示这个模式, 没有松开滑入按钮的范围), 恢复正常的显示模式

  • 倒计时模式

当即将要超出录音最大时长的时候, 有倒计时的提示 , demo限制的60, 剩余10秒开始提示

  • 说话过长模式

超出最大限制的时间, 提示这个

具体的实现思路, 因为很多种样式, 每一种提示的控件基本上都不能复用, 所以我就用了好几个View, 显示隐藏来回切换, 控件数量确实挺多的, 暂时没想到其他的好办法, 如果说移除, 需要的时候再去实例化, 会有卡顿, 用内存换速度吧, 这也是最直接的办法了

要注意一点, 当滑动超出范围的时候, 给的是一个松开取消的时候, 当滑入按钮范围的时候, 要判断录音的时长, 看是需要显示哪一种模式, 是正常的模式, 还是倒计时的模式

具体的看代码吧, 比我说的清晰, 我是这么觉得的😀

下一篇说一下, 整个消息的发送过程, 以及本地缓存等等

感谢阅读!!! 感谢阅读!!! 感谢阅读!!!(重要的事情说三遍)😀

前篇
即时通讯整个页面的搭建(一)

相关文章

网友评论

本文标题:即时通讯整个页面的搭建(二)

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