Android自定義View實(shí)現(xiàn)微信語(yǔ)音界面
前言
因?yàn)樽罱捻?xiàng)目需要使用錄音功能,開始的想法是Button+OnTouchListener+Dialog實(shí)現(xiàn),在大部分手機(jī)中都沒問題,只有MI8會(huì)偶爾無(wú)法觸發(fā)MotionEvent.ACTION_UP,導(dǎo)致程序異常。所以就自己寫了個(gè)自定義View來實(shí)現(xiàn),主要也是通過監(jiān)聽
OnTouchListener+Dialog來實(shí)現(xiàn)。這里只實(shí)現(xiàn)了自定義View,并不涉及錄音和播放。效果圖如下:

代碼
代碼并不復(fù)雜,配合注釋應(yīng)該很容易理解。
/**
* Author : BlackHao
* Time : 2019/4/18 14:03
* Description : 自定義錄音按鈕布局界面
*/
public class PressedView extends View implements View.OnTouchListener {
private int normalRes;
private String normalText = "";
private int pressedRes;
private String pressedText = "";
//
private Paint paint;
private Rect rect;
//當(dāng)前是否是按下狀態(tài)
private boolean isPressed = false;
//
private PressCallback callback;
//按下的位置y坐標(biāo)
private int pressedY = 0;
//當(dāng)前是否是outSize
private boolean isOutSize = false;
//字體dp大小
private static int TEXT_SIZE = 20;
//對(duì)話框相關(guān)
private Dialog soundVolumeDialog = null;
//音量圖片
private ImageView soundVolumeImg = null;
//對(duì)話框背景
private RelativeLayout soundVolumeLayout = null;
public PressedView(Context context) {
super(context);
init();
}
public PressedView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public PressedView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
//
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(DensityUtil.dip2px(getContext(), TEXT_SIZE));
paint.setColor(Color.WHITE);
rect = new Rect();
//
normalRes = R.drawable.blue_btn_bk;
normalText = "按住 說話";
pressedRes = R.drawable.red_btn_bk;
pressedText = "松開 結(jié)束";
//
setOnTouchListener(this);
//
initSoundVolumeDlg();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rect.set(0, 0, getWidth(), getHeight());
if (!isPressed) {
setBackgroundResource(normalRes);
drawTextOnRect(canvas, rect, normalText);
} else {
setBackgroundResource(pressedRes);
drawTextOnRect(canvas, rect, pressedText);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
pressedY = (int) event.getRawY();
isOutSize = false;
if (!isPressed) {
isPressed = true;
postInvalidate();
if (callback != null) {
//回調(diào)
callback.onStartRecord();
//按下,彈出對(duì)話框
soundVolumeImg.setImageResource(R.mipmap.sound_volume_01);
soundVolumeImg.setVisibility(View.VISIBLE);
soundVolumeLayout.setBackgroundResource(R.mipmap.sound_volume_default_bk);
soundVolumeDialog.show();
}
}
break;
case MotionEvent.ACTION_UP:
if (isPressed) {
isPressed = false;
postInvalidate();
if (callback != null) {
int upY = (int) event.getRawY();
if (pressedY - upY < getHeight()) {
//錄音結(jié)束
if (soundVolumeDialog.isShowing()) {
soundVolumeDialog.dismiss();
}
callback.onStopRecord();
} else {
//錄音取消
if (soundVolumeDialog.isShowing()) {
soundVolumeDialog.dismiss();
}
callback.onCancelRecord();
}
}
}
break;
case MotionEvent.ACTION_MOVE:
if (isPressed && callback != null) {
int upY = (int) event.getRawY();
if (pressedY - upY < getHeight()) {
if (isOutSize) {
isOutSize = false;
soundVolumeLayout.setBackgroundResource(R.mipmap.sound_volume_default_bk);
}
} else {
if (!isOutSize) {
isOutSize = true;
soundVolumeLayout.setBackgroundResource(R.mipmap.sound_volume_cancel_bk);
}
}
}
break;
}
return true;
}
public void setCallback(PressCallback callback) {
this.callback = callback;
}
public interface PressCallback {
//開始錄音
void onStartRecord();
//停止錄音
void onStopRecord();
//取消錄音
void onCancelRecord();
}
/**
* 在指定矩形中間drawText
*
* @param canvas 畫布
* @param targetRect 指定矩形
* @param text 需要繪制的Text
*/
private void drawTextOnRect(Canvas canvas, Rect targetRect, String text) {
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
// 獲取baseLine
int baseline = targetRect.top + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
// 下面這行是實(shí)現(xiàn)水平居中,drawText對(duì)應(yīng)改為傳入targetRect.centerX()
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text, targetRect.centerX(), baseline, paint);
}
/**
* 初始化音量信息對(duì)話框
*/
private void initSoundVolumeDlg() {
soundVolumeDialog = new Dialog(getContext(), R.style.SoundVolumeStyle);
soundVolumeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
soundVolumeDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
soundVolumeDialog.setContentView(R.layout.tt_sound_volume_dialog);
soundVolumeDialog.setCanceledOnTouchOutside(true);
soundVolumeImg = (ImageView) soundVolumeDialog.findViewById(R.id.sound_volume_img);
soundVolumeLayout = (RelativeLayout) soundVolumeDialog.findViewById(R.id.sound_volume_bk);
}
/**
* 根據(jù)分貝值設(shè)置錄音時(shí)的音量動(dòng)畫
*/
public void setVolume(int voiceValue) {
if (voiceValue < 200.0) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_01);
} else if (voiceValue > 200.0 && voiceValue < 600) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_02);
} else if (voiceValue > 600.0 && voiceValue < 1200) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_03);
} else if (voiceValue > 1200.0 && voiceValue < 2400) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_04);
} else if (voiceValue > 2400.0 && voiceValue < 10000) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_05);
} else if (voiceValue > 10000.0 && voiceValue < 28000.0) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_06);
} else if (voiceValue > 28000.0) {
soundVolumeImg.setImageResource(R.mipmap.sound_volume_07);
}
}
}
結(jié)語(yǔ)
源碼github地址:仿微信語(yǔ)音界面
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android仿微信語(yǔ)音對(duì)講錄音功能
- Android仿微信錄制語(yǔ)音功能
- Android實(shí)現(xiàn)錄音方法(仿微信語(yǔ)音、麥克風(fēng)錄音、發(fā)送語(yǔ)音、解決5.0以上BUG)
- Android仿微信語(yǔ)音消息的錄制和播放功能
- Android仿微信發(fā)送語(yǔ)音消息的功能及示例代碼
- Android仿微信語(yǔ)音聊天界面設(shè)計(jì)
- android仿微信聊天界面 語(yǔ)音錄制功能
- Android自定義UI實(shí)現(xiàn)微信語(yǔ)音
- Android 高仿微信語(yǔ)音聊天頁(yè)面高斯模糊(毛玻璃效果)
- Android仿微信語(yǔ)音聊天功能
相關(guān)文章
android實(shí)現(xiàn)程序自動(dòng)升級(jí)到安裝示例分享(下載android程序安裝包)
這篇文章主要介紹了android實(shí)現(xiàn)下載android程序安裝包自動(dòng)升級(jí)的示例,大家參考使用吧2014-01-01
Android自定義View實(shí)現(xiàn)星星評(píng)分效果
這篇文章主要為大家詳細(xì)介紹了Android如何利用自定義View實(shí)現(xiàn)一個(gè)星星評(píng)分的控件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-11-11
Android中DrawerLayout實(shí)現(xiàn)側(cè)滑菜單效果
這篇文章主要為大家詳細(xì)介紹了Android中DrawerLayout實(shí)現(xiàn)側(cè)滑菜單效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
android ListView自動(dòng)滾動(dòng)方法
直接在Layout中寫即可,注意下面的stackFromBottom以及transcriptMode這兩個(gè)屬性2013-01-01
Android利用Chronometer實(shí)現(xiàn)倒計(jì)時(shí)功能
這篇文章主要為大家詳細(xì)介紹了Android利用Chronometer實(shí)現(xiàn)倒計(jì)時(shí)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
recycleview實(shí)現(xiàn)拼多多首頁(yè)水平滑動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了recycleview實(shí)現(xiàn)拼多多首頁(yè)水平滑動(dòng)效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
Android Studio 通過登錄功能介紹SQLite數(shù)據(jù)庫(kù)的使用流程
SQLite是一款輕型的數(shù)據(jù)庫(kù),是遵守ACID的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),它包含在一個(gè)相對(duì)小的C庫(kù)中。這篇文章主要介紹了Android Studio 通過登錄功能介紹SQLite數(shù)據(jù)庫(kù)的使用流程,需要的朋友可以參考下2018-09-09
Android6.0獲取動(dòng)態(tài)權(quán)限代碼示例
這篇文章主要介紹了Android6.0以上獲取動(dòng)態(tài)權(quán)限代碼示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11

