系列文章
安卓原生聊天面板开发(一)整体规划
安卓原生聊天面板开发(二)emoji功能实现
安卓原生聊天面板开发(三)录音交互实现
安卓原生聊天面板开发(四)整体交互实现
背景
产品喝大了,说开发一个聊天界面,功能参照微信即可。
这是应了那句话:新人一开口,便知有没有~~真是风趣幽默。
问题分析
其实仔细看微信的聊天面板,功能拆分出来,主要有以下几点:
(1)emoji表情,自定义表情等等。这里可以归类为"表情"tab。
(2)语音交互,音频录制播放压缩。
(3)媒体交互,选择图片,视频,文件等等。
核心就是上面的内容,锦上添花的功能就不再叙述了。
实现效果
开发环境
win10
jdk8+
as2024+
本文内容
本文将会讲解实现录音动画的最核心思路。文末将会有源码地址。
先看效果图
思路大纲
对于实现这种需求,正常的做法就是拆分,看看到底有哪些状态。
(1)没有录音
(2)录音中--手指在移动范围
(2)录音中--手指在超过范围
(4)录音结束
总体就是这四个小状态。而其中,难点就是动画的播放,特别是黑色提示框的显示与收起(插件是一个view,而提示框是一个全局的,可以是任何位置的view,有可能覆盖在输入框上面)
核心实现
(一)动画
动画的播放,这里选择的是svga,因为其轻量,保真度高,所以选这个。官方提供的示例代码中,有两种方式可以实现动画的播放:
(1)使用提供的控件,在xml布局中声明好相关属性,进行播放
(2)先加载资源文件生成一个svgadrawable,然后动态设置到控件中,进行处理。
博主选择了第二种。第二种的好处就是,可以复用,也可以按需加载,定制度高,而且还能有自己的动画对象管理。
加载svga文件核心代码如下:
mSvgaAnimManager.loadAssets(getContext(), ChatInputResConst.SVGA_RECORD, null, new SVGALoadListener() {
@Override
public void complete(SVGAVideoEntity entity) {
//播放完成
mSvgaDrawable = new SVGADrawable(entity);
mSvgaInit = true;
}
@Override
public void error() {
//错误
}
});
暂停,开始播放相关代码:
private void startAnim() {
if (!mSvgaInit || mSvgaAnimView == null) {
return;
}
stopAnim();
mSvgaAnimView.setImageDrawable(mSvgaDrawable);
mSvgaAnimView.startAnimation();
}
private void stopAnim() {
if (mSvgaAnimView == null) {
return;
}
mSvgaAnimView.stopAnimation();
mSvgaAnimView.setImageDrawable(null);
}
在初始化的时候,就进行svga的资源获取,至于什么使用进行播放,就按需处理。这样做的最大好处,就是能够统一管理播放资源。
(二)黑色提示框
这个提示框,其实并不是在当前布局中实现的,因为不能贴合需求。
那么怎样能够让这个提示框,不再收到当前布局的约束?
答案就是decoreview
通过activity context,可以获取到一个DecoreView。至于DecoreView是什么,请自行百度,因为细节有很多细节。
那么有了这个DecoreView,我们是不是可以在里面,添加view(AddView),和移除view(removeView)了?
再者,结合view.getViewWindowLocation方法,就可以获取你想要显示的位置了。当然要注意的是,宽高获取以及处理。
请注意svga控件的用法,如播放完清空画布等操作
就是这么简单~~
(三)触摸事件的分发
需求就是,点击录音按钮,就做动画,移动超过了范围,就另作处理。
核心就是,子控件(录音按钮)只做一个触发,当收到按下的事件时,就开始录音,然后其父控件,做全部的事件分发处理,这些事件,都可以在父控件中捕获,前提是重写了父控件的事件分发方法。核心代码如下:
父控件分发:
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
ChatLogUtils.log("root ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
dealMoveEvent(event);
break;
case MotionEvent.ACTION_UP:
ChatLogUtils.log("root ACTION_UP");
stopRecordEvent(mIsIntRange);
break;
case MotionEvent.ACTION_CANCEL:
ChatLogUtils.log("root ACTION_CANCEL");
stopRecordEvent(mIsIntRange);
break;
}
return true;
}
子控件分发:
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
ChatLogUtils.log("button ACTION_DOWN");
if (mListener != null) {
mListener.click();
}
break;
case MotionEvent.ACTION_MOVE:
ChatLogUtils.log("button ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
ChatLogUtils.log("button ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
ChatLogUtils.log("button ACTION_CANCEL");
break;
}
return super.onTouchEvent(event);
}
(四)倒计时的实现
那么上面的事件分发,我们可以做到:开始,播放中,停止。这些周期的监听,那么倒计时也是一样的,在这些周期方法中,进行停止计时,开始计时,即可。
注意一个点,在按下的过程中,倒计时到头了,那么,也要处理好一个调整到初始状态的操作。
上述就是整个录音交互实现的思路,详细源码,文末可获取。
源码
源码获取方式,关注回复: 安卓原生聊天面板源码
即可获得: