没啥用但是又值得记录一下的工具类的封装。

先上一张鸡爱夫看看啥效果

个人觉得语音转文字是最鸡肋的一个功能,能发语音为什么要发文字呢???但是产品设计就是如此,当然得按着产品的思路来(⊙o⊙)…
然后是封装思路。封装的意义在于封装性和复用性。所以这里我想的是通过一个管理类+布局来操作。先看管理类:
class ChatInputManagerHelper(private val c:Context,private val container:RelativeLayout) {
private lateinit var voiceButton:ImageView
private lateinit var leftButton:ImageView
private lateinit var rightButton:ImageView
private lateinit var recordPlayButton:ImageView
private lateinit var loVoice:View
private lateinit var loWord:View
private lateinit var loRecord:View
private lateinit var voiceLong:TextView
private lateinit var tvWord:TextView
private lateinit var btCancelWord:View
private lateinit var btSendWord:TextView
private lateinit var replayTime:TextView
private lateinit var btCancelVoice:View
private lateinit var btSendVoice:TextView
private lateinit var level1:ImageView
private lateinit var level2:ImageView
private lateinit var tvProgress:TextView
private lateinit var tvHint:TextView
private lateinit var loProgress:View
private lateinit var bottomHint:TextView
private lateinit var tvChangeStatus:TextView
var callback: ShowInputCallBack?=null
private var leftBtX1=0
private var leftBtX2=0
private var leftBtY1=0
private var leftBtY2=0
private var centerBtX1=0
private var centerBtX2=0
private var centerBtY1=0
private var centerBtY2=0
private var rihgtBtX1=0
private var rightBtX2=0
private var rightBtY1=0
private var rightBtY2=0
private var recordTime=0
var mAudioRecorderUtils: AudioRecorderUtils? = null
private var voiceFile:String?=null
private var tag=-1//-1初始状态 0-按下状态 1-按下语音 2-按下转文字 3-按下取消
var type=1//1-在线咨询 2随访管理
private var isDown=false
private var aniCom: CompositeDisposable?=null //动画Com
private var isWordOk=true;//是否有文字
var messageSendListener: EmotionInputDetector.MessageSendListener? = null
private var isPlaying=false;
private var isLock=false
var isNotChat:Boolean?=false// true -不是聊天 false 是聊天
init {
voiceButton = container.findViewById(R.id.voiceButton)
leftButton = container.findViewById(R.id.buttonLeft)
rightButton = container.findViewById(R.id.buttonRight)
recordPlayButton=container.findViewById(R.id.recordButton)
loVoice=container.findViewById(R.id.loVoice)
loWord=container.findViewById(R.id.loWord)
loRecord=container.findViewById(R.id.loRecord)
voiceLong=container.findViewById(R.id.voiceLong)
tvWord=container.findViewById(R.id.tvWord)
btCancelWord=container.findViewById(R.id.btCancelWord)
btSendWord=container.findViewById(R.id.btSendWord)
replayTime=container.findViewById(R.id.replayTime)
btCancelVoice=container.findViewById(R.id.btCancelVoice)
btSendVoice=container.findViewById(R.id.btSendVoice)
level1=container.findViewById(R.id.level1)
level2=container.findViewById(R.id.level2)
tvProgress=container.findViewById(R.id.tvProgress)
tvHint=container.findViewById(R.id.tvHintVoice)
loProgress=container.findViewById(R.id.loProgress)
bottomHint=container.findViewById(R.id.bottomHint)
tvChangeStatus=container.findViewById(R.id.tvChangeStatus)
aniCom=CompositeDisposable()
enable()
}
private fun aning(){
aniCom?.clear()
tvChangeStatus.visibility=View.VISIBLE
Observable.intervalRange(1,100,0,500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : SimplerObserver2<Long>(c,false){
override fun onNext(t: Long) {
if (tvChangeStatus.text.toString().equals("正在识别.")){
tvChangeStatus.text="正在识别.."
}else if (tvChangeStatus.text.toString().equals("正在识别..")){
tvChangeStatus.text="正在识别..."
}else{
tvChangeStatus.text="正在识别."
}
}
override fun onSubscribe(d: Disposable) {
super.onSubscribe(d)
aniCom?.add(d)
}
})
}
fun enable() {
//初始化视图
val locationLeft = IntArray(2)
leftButton.getLocationOnScreen(locationLeft)
leftBtX1 = locationLeft[0];
leftBtX2 = locationLeft[0] + leftButton.width
leftBtY1 = locationLeft[1]
leftBtY2 = locationLeft[1] + leftButton.height
voiceButton.getLocationOnScreen(locationLeft)
centerBtX1 = locationLeft[0];
centerBtX2 = locationLeft[0] + voiceButton.width
centerBtY1 = locationLeft[1]
centerBtY2 = locationLeft[1] + voiceButton.height
rightButton.getLocationOnScreen(locationLeft)
rihgtBtX1 = locationLeft[0];
rightBtX2 = locationLeft[0] + rightButton.width
rightBtY1 = locationLeft[1]
rightBtY2 = locationLeft[1] + rightButton.height
//初始化功能
mAudioRecorderUtils = AudioRecorderUtils()
bottomHint.text="为了保障服务质量,请您吐字清晰,尽量说普通话"
mAudioRecorderUtils?.setOnAudioStatusUpdateListener(object :
AudioRecorderUtils.OnAudioStatusUpdateListener {
override fun onUpdate(db: Double, time: Long) {
if ((time/1000)>59){
mAudioRecorderUtils?.stopRecord()
return
}
if (tag==0){
mAudioRecorderUtils?.stopRecord()
goBackNormal()
}else{
val toInt = ( 200 * (db-35) ).toInt()
level1.drawable.level = (toInt)
level2.drawable.level = toInt
tvProgress.text = Utils.long2String(time)
if (tag!=2&&tag!=3){
loProgress.visibility= View.VISIBLE
tvHint.visibility=View.GONE
tvHint.text=""
bottomHint.text="为了保障服务质量,请您吐字清晰,尽量说普通话"
}
}
}
override fun onStop(time: Long, filePath: String?) {
recordTime = (time / 1000).toInt()
voiceFile=filePath
if (tag==3){
goBackNormal()
return
}
if (time < 1000) {
goBackNormal()
return
}
when (tag) {
1 -> {
//发送
loVoice.visibility = View.GONE
loWord.visibility = View.GONE
loRecord.visibility = View.VISIBLE
replayTime.text=
Utils.long2String(time)
}
2 -> {
//转文字 这里应该开启一个线程去操作转文字的业务 ,操作中先展示转换中。。。并且转换可能还会失败的状态
//先将语音部分隐藏,显示文字部分
loVoice.visibility = View.GONE
loRecord.visibility = View.GONE
loWord.visibility = View.VISIBLE
val min = recordTime / 60
val sec = recordTime % 60
if (min>0){
voiceLong.text = "${min}′${sec}″"
}else{
voiceLong.text = "${sec}″"
}
//然后应该先将转换结果隐藏
tvWord.visibility=View.GONE
//开始操作耗时业务
//开始操作耗时业务
// 先上传
aning()
btSendWord.isClickable=false
OssUpHelper.upFile(c,File(filePath?:""),object : OssUpHelper.OssUPCallBack{
override fun onError(msg: String) {
super.onError(msg)
aniCom?.clear()
//转换失败
isWordOk=false
tvChangeStatus.visibility=View.GONE
tvWord.visibility=View.VISIBLE
btSendWord.text="${if (isNotChat==true) "保存" else "发送"}语音"
btSendWord.isClickable=true
tvWord.text="未识别出文字"
}
override fun upResponse(url: String) {
Api.changeToWord(url)?.subscribe(object : CustomAction<String>(c){
override fun httpSuccess(t: String?) {
aniCom?.clear()
btSendWord.isClickable=true
if (!t.isNullOrEmpty()){
//成功
//完成之后 显示结果
isWordOk=true
btSendWord.text="${if (isNotChat==true) "保存文字" else "发送"}"
tvChangeStatus.visibility=View.GONE
tvWord.visibility=View.VISIBLE
tvWord.text=t?:""
}else{
//转换失败
isWordOk=false
tvChangeStatus.visibility=View.GONE
tvWord.visibility=View.VISIBLE
btSendWord.text="${if (isNotChat==true) "保存" else "发送"}语音"
tvWord.text="未识别出文字"
}
}
override fun httpErro(
code: Int,
message: String,
data: String?
): Boolean {
aniCom?.clear()
//转换失败
isWordOk=false
tvChangeStatus.visibility=View.GONE
tvWord.visibility=View.VISIBLE
btSendWord.text="${if (isNotChat==true) "保存" else "发送"}语音"
btSendWord.isClickable=true
tvWord.text="未识别出文字"
return false
}
})
}
})
}
3 -> {
//取消
loVoice.visibility = View.VISIBLE
loWord.visibility = View.GONE
loRecord.visibility = View.GONE
}
}
}
override fun onError() {
}
})
//按钮
recordPlayButton.setDelayClickListener {
if (isPlaying){
MediaManager.release()
recordPlayButton.setImageResource(R.mipmap.icon_chat_play)
isPlaying=false
}else{
recordPlayButton.setImageResource(R.mipmap.icon_chat_stop)
MediaManager.playSound(voiceFile, MediaPlayer.OnCompletionListener {
//播放完毕
isPlaying=false
replayTime.text= Utils.long2String(recordTime*1000L)
recordPlayButton.setImageResource(R.mipmap.icon_chat_play)
MediaManager.clearTimer()
}, object :MediaManager.PlayCallBack{
override fun onPro(pro: Int) {
(c as Activity).runOnUiThread{
isPlaying=true
replayTime.text= Utils.long2String((recordTime-pro)*1000L)
}
}
override fun onPro(progress: Float) {
}
})
}
}
btSendVoice.setDelayClickListener {
//发送语音
if (type == 1) {
//在线咨询发送
val bean = OnlineMessageBean()
bean.content = "语音"
bean.messageType = OnlineMessageBean.SendVoice
bean.url = voiceFile
bean.voiceLength = recordTime
bean.showVoiceLength =recordTime
bean.time =
TimeUtil.getYMdTime(System.currentTimeMillis())
if (bean.voiceLength < 1) {
"语音过短了".Toast()
} else {
messageSendListener?.sendOnlineMessage(bean)
}
}
goBackNormal()
}
btSendWord.setDelayClickListener {
isLock=false
if (type == 1) {
//在线咨询
if (isWordOk) {
//可以发文字
//在线咨询发送
val bean = OnlineMessageBean()
bean.content = tvWord.text.toString()
bean.messageType = OnlineMessageBean.SendText
bean.url = ""
bean.time = TimeUtil.getYMdTime(System.currentTimeMillis())
messageSendListener?.sendOnlineMessage(bean)
} else {
val bean = OnlineMessageBean()
bean.content = "语音"
bean.messageType = OnlineMessageBean.SendVoice
bean.url = voiceFile
bean.voiceLength = recordTime
bean.showVoiceLength = recordTime
bean.time = TimeUtil.getYMdTime(System.currentTimeMillis())
if (bean.voiceLength < 1) {
"语音过短了".Toast()
} else {
messageSendListener?.sendOnlineMessage(bean)
}
}
}
goBackNormal()
// hide()
}
btCancelVoice.setDelayClickListener {
goBackNormal()
}
btCancelWord.setDelayClickListener {
goBackNormal()
isLock=false
}
tvWord.setDelayClickListener {
isLock=true
callback?.isShow(true)
}
}
@SuppressLint("ClickableViewAccessibility")
fun initUtil(){
container.setOnTouchListener { v, event ->
val rawX = event.rawX
val rawY = event.rawY
if (event.action==MotionEvent.ACTION_DOWN){
//按下时
//如果按下语音按钮
if (rawX>=centerBtX1&&rawX<=centerBtX2&&rawY>=centerBtY1&&rawY<=centerBtY2){
SystemUtil.vibe(c)
voiceButton.scaleAnima {
leftButton.slowlyShow()
rightButton.slowlyShow()
voiceButton.setImageResource(R.mipmap.icon_oline_voice_green)
tag=1
isDown=true
Thread(Runnable {
if (!RxpermissionUtil.checkPer(Manifest.permission_group.STORAGE)||
!RxpermissionUtil.checkPer(Manifest.permission.RECORD_AUDIO)){
RxpermissionUtil.requestPer(arrayOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE))
?.subscribe {
b->
if (b){
mAudioRecorderUtils?.startRecord(c)
}
}
}else{
mAudioRecorderUtils?.startRecord(c)
}
}).start()
/* if (tag==0){
}else{
mAudioRecorderUtils?.stopRecord()
}*/
}
}
false
}else if (event.action==MotionEvent.ACTION_MOVE){
if (isDown){
//暗中语音 时 当按在左边
if (rawX>=leftBtX1&&rawX<=leftBtX2&&rawY>=leftBtY1&&rawY<=leftBtY2){
if (tag!=2){
loProgress.visibility= View.GONE
tvHint.visibility=View.VISIBLE
tvHint.text="松手转文字"
leftButton.setImageResource(R.mipmap.icon_chat_toword_blue)
SystemUtil.vibe(c)
}
bottomHint.text="为了保障服务质量,请您吐字清晰,尽量说普通话"
tag=2
}else{
leftButton.setImageResource(R.mipmap.icon_chat_toword)
//当没按在左边的时候 判断是否按在右边
if (rawX>=rihgtBtX1&&rawX<=rightBtX2&&rawY>=rightBtY1&&rawY<=rightBtY2){
if (tag!=3){
loProgress.visibility= View.GONE
tvHint.visibility=View.VISIBLE
tvHint.text="松手取消发送"
SystemUtil.vibe(c)
rightButton.setImageResource(R.mipmap.icon_chat_cancel_red)
}
tag=3
}else{
rightButton.setImageResource(R.mipmap.icon_chat_cancel)
//等于都没按
tag=1
loProgress.visibility= View.VISIBLE
tvHint.visibility=View.GONE
tvHint.text=""
leftButton.setImageResource(R.mipmap.icon_chat_toword)
}
}
}
}
else if (event.action==MotionEvent.ACTION_UP){
isDown=false
mAudioRecorderUtils?.stopRecord()
voiceButton.tag=null
if (tag==3){
//取消
}else if (tag==2){
//转文字
}else if (tag==1){
//发送
}
//恢复初始状态
voiceButton.setImageResource(R.mipmap.icon_oline_voice)
leftButton.setImageResource(R.mipmap.icon_chat_toword)
rightButton.setImageResource(R.mipmap.icon_chat_cancel)
tvProgress.text="00:00"
loProgress.visibility=View.GONE
tvHint.visibility=View.VISIBLE
tvHint.text="长按开始说话"
leftButton.slowlyGone()
rightButton.slowlyGone()
false
}
true
}
}
fun show(){
container.visibility=View.VISIBLE
isLock=false
}
fun hide(){
container.visibility=View.GONE
if (!isLock)
goBackNormal()
}
//回到初始状态
private fun goBackNormal() {
btSendWord.isClickable=true
loVoice.visibility=View.VISIBLE
loRecord.visibility=View.GONE
loWord.visibility=View.GONE
tvHint.text="长按开始说话"
tvHint.visibility=View.VISIBLE
loProgress.visibility=View.GONE
btSendWord.text= if (isNotChat==true) "确认" else "发送"
isWordOk=true
}
interface ShowInputCallBack{
fun isShow(b:Boolean)
}
}
其实代码还是比较简单,主要的思路就是对ontouch的action的追踪和状态的界定,这其实那张纸理一下就很清晰了。其他就不赘述了。对外暴露的东西比较少,需要的自己拿去改吧改吧应该还行。
下面上xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/white_5r"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="230dp">
<RelativeLayout
android:id="@+id/loVoice"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/loProgress"
android:orientation="horizontal"
android:layout_centerHorizontal="true"
android:visibility="gone"
android:layout_marginTop="12dp"
android:layout_width="wrap_content"
android:gravity="center_vertical"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/level1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="180"
android:src="@drawable/record_online_left" />
<TextView
android:id="@+id/tvProgress"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:text="00:00"
android:textSize="15dp"
android:textColor="@color/text_aaa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/level2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/record_online_left" />
</LinearLayout>
<TextView
android:id="@+id/tvHintVoice"
android:text="长按开始说话"
android:textColor="@color/text_777"
android:textSize="15dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="12dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/buttonLeft"
android:src="@mipmap/icon_chat_toword"
android:layout_marginTop="56dp"
android:visibility="invisible"
android:scaleType="centerInside"
android:layout_marginLeft="30dp"
android:layout_width="62dp"
android:layout_height="62dp"/>
<ImageView
android:id="@+id/voiceButton"
android:src="@mipmap/icon_oline_voice"
android:layout_centerHorizontal="true"
android:layout_marginTop="54dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/buttonRight"
android:src="@mipmap/icon_chat_cancel"
android:visibility="invisible"
android:layout_alignParentRight="true"
android:layout_marginRight="40dp"
android:layout_marginTop="56dp"
android:scaleType="centerInside"
android:layout_width="62dp"
android:layout_height="62dp"/>
<TextView
android:id="@+id/bottomHint"
android:textSize="12dp"
android:textColor="@color/text_aaa"
android:layout_centerHorizontal="true"
android:layout_below="@id/voiceButton"
android:layout_marginTop="13dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/loWord"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/voiceLong"
android:layout_marginTop="12dp"
android:layout_centerHorizontal="true"
android:background="@drawable/_f5_125r"
android:text="10″"
android:drawablePadding="4dp"
android:textSize="15dp"
android:drawableLeft="@mipmap/icon_bl"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingRight="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tvWord"
android:text="3213213213213"
android:textColor="@color/text_333"
android:textSize="14dp"
android:layout_below="@id/voiceLong"
android:layout_above="@id/lobt1"
android:layout_marginTop="7dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_width="match_parent"
android:layout_height="107dp"/>
<TextView
android:id="@+id/tvChangeStatus"
android:visibility="gone"
android:text="正在识别..."
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/lobt1"
android:orientation="horizontal"
android:layout_width="match_parent"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:background="@color/white"
android:paddingTop="9dp"
android:paddingBottom="14dp"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content">
<TextView
android:id="@+id/btCancelWord"
android:textSize="14dp"
android:gravity="center"
android:layout_marginRight="8dp"
android:textColor="@color/textBlue"
android:background="@drawable/f5_22r"
android:text="取消"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="36dp"/>
<TextView
android:id="@+id/btSendWord"
android:textSize="14dp"
android:gravity="center"
android:textColor="@color/white"
android:background="@drawable/_009aff_22r"
android:text="确认"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="36dp"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/loRecord"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/replayTime"
android:textColor="@color/text_777"
android:textSize="15dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="12dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/recordButton"
android:src="@mipmap/icon_chat_play"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/lobt2"
android:orientation="horizontal"
android:layout_width="match_parent"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:background="@color/white"
android:paddingTop="9dp"
android:paddingBottom="14dp"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content">
<TextView
android:id="@+id/btCancelVoice"
android:textSize="14dp"
android:gravity="center"
android:layout_marginRight="8dp"
android:textColor="@color/textBlue"
android:background="@drawable/f5_22r"
android:text="取消"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="36dp"/>
<TextView
android:id="@+id/btSendVoice"
android:textSize="14dp"
android:gravity="center"
android:textColor="@color/white"
android:background="@drawable/_009aff_22r"
android:text="确认"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="36dp"/>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
当然xml这只是看一下,OK这次就这样了

网友评论