Android自定义View实现微信语音界面

 更新时间:2019年11月16日 10:30:53   作者:Black_Hao  
这篇文章主要为大家详细介绍了Android自定义View实现微信语音界面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

因为最近的项目需要使用录音功能,开始的想法是Button+OnTouchListener+Dialog实现,在大部分手机中都没问题,只有MI8会偶尔无法触发MotionEvent.ACTION_UP,导致程序异常。所以就自己写了个自定义View来实现,主要也是通过监听
OnTouchListener+Dialog来实现。这里只实现了自定义View,并不涉及录音和播放。效果图如下:

代码

代码并不复杂,配合注释应该很容易理解。

/**
 * 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;
  //当前是否是按下状态
  private boolean isPressed = false;
  //
  private PressCallback callback;
  //按下的位置y坐标
  private int pressedY = 0;
  //当前是否是outSize
  private boolean isOutSize = false;
  //字体dp大小
  private static int TEXT_SIZE = 20;
  //对话框相关
  private Dialog soundVolumeDialog = null;
  //音量图片
  private ImageView soundVolumeImg = null;
  //对话框背景
  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 = "松开 结束";
    //
    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) {
            //回调
            callback.onStartRecord();
            //按下,弹出对话框
            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()) {
              //录音结束
              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;
    // 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
    paint.setTextAlign(Paint.Align.CENTER);
    canvas.drawText(text, targetRect.centerX(), baseline, paint);
  }

  /**
   * 初始化音量信息对话框
   */
  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);
  }

  /**
   * 根据分贝值设置录音时的音量动画
   */
  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);
    }
  }

}

结语

源码github地址:仿微信语音界面

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Andriod Studio实现保存QQ密码功能(案例代码详解)

    Andriod Studio实现保存QQ密码功能(案例代码详解)

    这篇文章主要介绍了Andriod Studio实现保存QQ密码功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • Android如何获取QQ与微信的聊天记录并保存到数据库详解

    Android如何获取QQ与微信的聊天记录并保存到数据库详解

    这篇文章主要给大家介绍了关于Android如何获取QQ与微信的聊天记录并保存到数据库的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2018-04-04
  • Kotlin协程基础元素梳理分析

    Kotlin协程基础元素梳理分析

    这篇文章我们来讲协程的基础元素,毕竟协程是一个很强大的设计模式,深入了解需要花很多的时间,我们先从简单开始,其实学会了简单的使用,基本已经可以满足我们平时的开发需要了,话不多说,开始
    2022-11-11
  • Android Mms之:草稿管理的应用

    Android Mms之:草稿管理的应用

    本篇文章是对Android中的草稿管理进行了详细的分析与介绍,需要的朋友参考下
    2013-05-05
  • Android中ActionBar以及menu的代码设置样式

    Android中ActionBar以及menu的代码设置样式

    这篇文章主要介绍了Android中ActionBar以及menu的代码设置样式的相关资料,需要的朋友可以参考下
    2015-07-07
  • Android 使用ViewPager实现轮播图效果

    Android 使用ViewPager实现轮播图效果

    这篇文章主要介绍了Android 使用ViewPager实现轮播图效果,通过实例代码给大家讲解了适配器和各个方法的作用介绍,需要的朋友可以参考下
    2017-05-05
  • FFmpeg 音频可视化解码流程详解

    FFmpeg 音频可视化解码流程详解

    这篇文章主要为大家介绍了FFmpeg 音频可视化解码流程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • Android开发笔记SQLite优化记住密码功能

    Android开发笔记SQLite优化记住密码功能

    这篇文章主要为大家详细介绍了Android开发笔记SQLite优化记住密码功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Android实现网易严选标签栏滑动效果

    Android实现网易严选标签栏滑动效果

    这篇文章主要为大家详细介绍了Android实现网易严选标签栏滑动效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Android实现控件的缩放移动功能

    Android实现控件的缩放移动功能

    这篇文章主要介绍了android控件的缩放,移动功能,本文图文并茂给大家介绍的非常详细,需要的朋友可以参考下
    2018-01-01

最新评论