SoFunction
Updated on 2025-03-11

Android imitation WeChat voice chat interface design

I haven't watched the video for a while. I took some time last night, watched the video tutorial of Master Hongyang, and took time to write a study record. The code is basically the same as what the teacher said, and there are many similar blogs on the Internet. I just wrote it in AndroidStudio environment.

——Main interface code—

 public class MainActivity extends Activity {
 private ListView mListView;
 private ArrayAdapter<Recorder> mAdapter;
 private List<Recorder> mDatas = new ArrayList<Recorder>();
 private AudioRecorderButton mAudioRecorderButton;
 private View animView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  (savedInstanceState);
  setContentView(.activity_main);
  mListView = (ListView) findViewById(.id_listview);
  mAudioRecorderButton = (AudioRecorderButton) findViewById(.id_recorder_button);
  (new () {

   public void onFinish(float seconds, String filePath) {
    Recorder recorder = new Recorder(seconds, filePath);
    (recorder);
    //Update data    ();
    //Set the location    (() - 1);
   }
  });

  mAdapter = new RecoderAdapter(this, mDatas);
  (mAdapter);

  //listView item click event  (new OnItemClickListener() {

   public void onItemClick(AdapterView<?> arg0, View view, int position, long id) {
    // Sound playback animation    if (animView != null) {
     ();
     animView = null;
    }
    animView = (.id_recoder_anim);
    (.play_anim);
    AnimationDrawable animation = (AnimationDrawable) ();
    ();
    // Play recording    ((position).filePath, new () {

     public void onCompletion(MediaPlayer mp) {
      //Modify the picture after playback is completed      ();
     }
    });
   }
  });
 }

 @Override
 protected void onPause() {
  ();
  ();
 }

 @Override
 protected void onResume() {
  ();
  ();
 }

 @Override
 protected void onDestroy() {
  ();
  ();
 }

—Custom Button ——

/**
  * @param
  * @author ldm
  * @description Custom Button
  * @time 2016/6/25 9:26
  */
public class AudioRecorderButton extends Button {
 // button normal state (default state) private static final int STATE_NORMAL = 1;
 //Recording status private static final int STATE_RECORDING = 2;
 //Recording cancellation status private static final int STATE_CANCEL = 3;
 //Record the current status private int mCurrentState = STATE_NORMAL;
 //Does the recording start sign private boolean isRecording = false;
 //Judge the sliding distance on the Button to determine whether to cancel private static final int DISTANCE_Y_CANCEL = 50;
 //Dialog box management tool class private DialogManager mDialogManager;
 //Recording management tool category private AudioManager mAudioManager;
 //Record recording time private float mTime;
 // Whether to trigger longClick private boolean mReady;
 //Recording preparation private static final int MSG_AUDIO_PREPARED = 0x110;
 //The volume has changed private static final int MSG_VOICE_CHANGED = 0x111;
 //Cancel the prompt dialog private static final int MSG_DIALOG_DIMISS = 0x112;

 /**
   * @description The thread that gets the volume size
   * @author ldm
   * @time 2016/6/25 9:30
   * @param
   */
 private Runnable mGetVoiceLevelRunnable = new Runnable() {

  public void run() {
   while (isRecording) {//Judge that the recording is being performed    try {
     (100);
     mTime += 0.1f;//Calculate recording time     (MSG_VOICE_CHANGED);//Send a message every 0.1 seconds    } catch (InterruptedException e) {
     ();
    }
   }
  }
 };

 private Handler mHandler = new Handler() {

  @Override
  public void handleMessage(Message msg) {
   switch () {
    case MSG_AUDIO_PREPARED:
     //Show dialog box     ();
     isRecording = true;
     // Turn on a thread to calculate recording time     new Thread(mGetVoiceLevelRunnable).start();
     break;
    case MSG_VOICE_CHANGED:
     //Update the sound     ((7));
     break;
    case MSG_DIALOG_DIMISS:
     //Cancel dialog     ();
     break;
   }
   (msg);
  }
 };


 public AudioRecorderButton(Context context, AttributeSet attrs) {
  super(context, attrs);
  mDialogManager = new DialogManager(context);
  //Storage address of recording file  String dir = () + "/ldm_voice";
  mAudioManager = (dir);
  (new () {
   public void wellPrepared() {
    (MSG_AUDIO_PREPARED);
   }
  });

  // Since this class is a button, add listening events in the constructor  setOnLongClickListener(new OnLongClickListener() {

   public boolean onLongClick(View v) {
    mReady = true;
    ();
    return false;
   }
  });
 }

 public AudioRecorderButton(Context context) {
  this(context, null);
 }

 /**
   * @description Callback after recording is completed
   * @author ldm
   * @time 2016/6/25 11:18
   * @param
  */
 public interface AudioFinishRecorderCallBack {
  void onFinish(float seconds, String filePath);
 }

 private AudioFinishRecorderCallBack finishRecorderCallBack;

 public void setFinishRecorderCallBack(AudioFinishRecorderCallBack listener) {
  finishRecorderCallBack = listener;
 }

 /**
   * @param
   * @description Handle Button's OnTouchEvent event
   * @author ldm
   * @time 2016/6/25 9:35
   */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //Get the TouchEvent status  int action = ();
  // Obtain x-axis coordinates  int x = (int) ();
  // Obtain the y-axis coordinates  int y = (int) ();

  switch (action) {
   case MotionEvent.ACTION_DOWN://Press your finger    changeState(STATE_RECORDING);
    break;
   case MotionEvent.ACTION_MOVE://Finger movement    if (isRecording) {
     //Judge whether it is necessary to cancel based on the coordinates of x and y     if (wantToCancle(x, y)) {
      changeState(STATE_CANCEL);
     } else {
      changeState(STATE_RECORDING);
     }
    }

    break;
   case MotionEvent.ACTION_UP://Let your fingers go    if (!mReady) {
     reset();
     return (event);
    }
    if (!isRecording || mTime < 0.6f) {//If the time is less than 0.6s, it is prompted that the recording is too short     ();
     ();
     // Delay display dialog box     (MSG_DIALOG_DIMISS, 1000);
    } else if (mCurrentState == STATE_RECORDING) {
     //If the status is recording, the recording ends     ();
     ();

     if (finishRecorderCallBack != null) {
      (mTime, ());
     }

    } else if (mCurrentState == STATE_CANCEL) { // Want to cancel     ();
     ();
    }
    reset();
    break;

  }
  return (event);
 }

 /**
   * Recovery status and flag bits
   */
 private void reset() {
  isRecording = false;
  mTime = 0;
  mReady = false;
  changeState(STATE_NORMAL);
 }

 private boolean wantToCancle(int x, int y) {
  // More than the width of the button  if (x < 0 || x > getWidth()) {
   return true;
  }
  // exceeds the height of the button  if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
   return true;
  }

  return false;
 }


 /**
   * @param
   * @description Change Button display according to state
   * @author ldm
   * @time 2016/6/25 9:36
   */
 private void changeState(int state) {
  if (mCurrentState != state) {
   mCurrentState = state;
   switch (state) {
    case STATE_NORMAL:
     setBackgroundResource(.btn_recorder_normal);
     setText(.str_recorder_normal);
     break;

    case STATE_RECORDING:
     setBackgroundResource(.btn_recorder_recording);
     setText(.str_recorder_recording);
     if (isRecording) {
      ();
     }
     break;

    case STATE_CANCEL:
     setBackgroundResource(.btn_recorder_recording);
     ();
     setText(.str_recorder_want_cancel);
     break;
   }
  }
 }
}

——Dialogue management tool class—

/**
   * @description Dialog Management Tool Class
   * @author ldm
   * @time 2016/6/25 11:53
   * @param
  */
public class DialogManager {
 //The dialog box pops up private Dialog mDialog;
 //Record icon private ImageView mIcon;
 //Volume Display Icon private ImageView mVoice;
 //The text prompted on the dialog box private TextView mLable;
 //Context object private Context mContext;


 public DialogManager(Context context) {
   = context;
 }

 /**
   * @param
   * @description Display dialog box
   * @author ldm
   * @time 2016/6/25 9:56
   */
 public void showRecordingDialog() {
  //Instantiate Dialog according to the specified sytle  mDialog = new Dialog(mContext, );
  LayoutInflater inflater = (mContext);
  View view = (.dialog_recorder, null);
  (view);
  mIcon = (ImageView) (.id_recorder_dialog_icon);
  mVoice = (ImageView) (.id_recorder_dialog_voice);
  mLable = (TextView) (.id_recorder_dialog_label);
  ();
 }

 /**
   * @param
   * @description Dialog box for recording status
   * @author ldm
   * @time 2016/6/25 10:08
   */
 public void recording() {
  if (mDialog != null && ()) {
   ();
   ();
   ();
   ();
   ("Swipe your fingers, cancel sending");
  }
 }

 /**
   * @param
   * @description Cancel the recording status dialog box
   * @author ldm
   * @time 2016/6/25 10:08
   */
 public void wantToCancel() {
  if (mDialog != null && ()) {
   ();
   ();
   ();
   ();
   ("Relax your finger and cancel sending");
  }
 }

 /**
   * @param
   * @description dialog box with too short time
   * @author ldm
   * @time 2016/6/25 10:09
   */
 public void tooShort() {
  if (mDialog != null && ()) { //Show status   ();
   ();
   ();
   (.voice_to_short);
   ("The recording time is too short");
  }
 }

 /**
   * @param
   * @description
   * @author ldm
   * @time 2016/6/25 Cancel (close) dialog box
   */
 public void dimissDialog() {
  if (mDialog != null && ()) { //Show status   ();
   mDialog = null;
  }
 }

 // Display the dialog box for updating volume level public void updateVoiceLevel(int level) {
  if (mDialog != null && ()) { //Show status   ();
   ();
   ();
   //Set the id of the picture. The sound image we put in the drawable is in v+number format   int resId = ().getIdentifier("v" + level, "drawable", ());
   (resId);
  }
 }

}

——Sound playback tools—

/**
  * @param
  * @author ldm
  * @description Play sound tool class
  * @time 2016/6/25 11:29
  */
public class MediaPlayerManager {
 //Play audio API class: MediaPlayer private static MediaPlayer mMediaPlayer;
 //Whether to pause private static boolean isPause;

 /**
   * @param
   * filePath: file path
   * onCompletionListener: Playback complete listening
   * @description Play sound
   * @author ldm
   * @time 2016/6/25 11:30
   */
 public static void playSound(String filePath,  onCompletionListener) {
  if (mMediaPlayer == null) {
   mMediaPlayer = new MediaPlayer();
   //Set an error listener   (new () {

    public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
     ();
     return false;
    }
   });
  } else {
   ();
  }

  try {
   (.STREAM_MUSIC);
   (onCompletionListener);
   (filePath);
   ();
   ();
  } catch (Exception e) {

  }
 }

 /**
   * @param
   * @description Pause playback
   * @author ldm
   * @time 2016/6/25 11:31
   */
 public static void pause() {
  if (mMediaPlayer != null && ()) { //When it's playing   ();
   isPause = true;
  }
 }

 /**
   * @param
   * @description Replay
   * @author ldm
   * @time 2016/6/25 11:31
   */
 public static void resume() {
  if (mMediaPlayer != null && isPause) {
   ();
   isPause = false;
  }
 }

 /**
   * @param
   * @description Release operation
   * @author ldm
   * @time 2016/6/25 11:32
   */
 public static void release() {
  if (mMediaPlayer != null) {
   ();
   mMediaPlayer = null;
  }
 }

——Recording operation tools category——

/**
  * @param
  * @author ldm
  * @description Recording Management Tool Class
  * @time 2016/6/25 9:39
  */
public class AudioManager {
 //AudioRecord: It mainly implements recording and broadcasting (AudioRecord+AudioTrack) and real-time audio processing. // Advantages: It can be processed in real time with various audio packaging private MediaRecorder mMediaRecorder;
 //Recording File private String mDir;
 //Current recording file directory private String mCurrentFilePath;
 //Singleton Mode private static AudioManager mInstance;
 //Are you ready private boolean isPrepare;

 //Private construction method private AudioManager(String dir) {
  mDir = dir;
 }

 //Announce the method to obtain examples public static AudioManager getInstance(String dir) {
  if (mInstance == null) {
   synchronized () {
    if (mInstance == null) {
     mInstance = new AudioManager(dir);
    }
   }
  }
  return mInstance;
 }

 /**
   * @param
   * @author ldm
   * @description Recording preparation work complete callback interface
   * @time 2016/6/25 11:14
   */
 public interface AudioStateListener {
  void wellPrepared();
 }

 public AudioStateListener mAudioStateListener;

 /**
   * @param
   * @description Set callback method for external class call
   * @author ldm
   * @time 2016/6/25 11:14
   */
 public void setOnAudioStateListener(AudioStateListener listener) {
  mAudioStateListener = listener;
 }

 /**
   * @param
   * @description Recording preparation
   * @author ldm
   * @time 2016/6/25 11:15
   */
 public void prepareAudio() {
  try {
   isPrepare = false;
   File dir = new File(mDir);
   if (!()) {
    ();//The file does not exist, then create a file   }
   String fileName = generateFileName();
   File file = new File(dir, fileName);
   mCurrentFilePath = ();
   mMediaRecorder = new MediaRecorder();
   // Set the output file path   (());
   // Set the audio source of MediaRecorder to microphone   ();
   // Set the audio format to RAW_AMR   (.RAW_AMR);
   // Set the audio encoding to AMR_NB   (.AMR_NB);
   // Prepare for recording   ();
   // Start, you must call after prepare()   ();
   // Prepare to be completed   isPrepare = true;
   if (mAudioStateListener != null) {
    ();
   }
  } catch (Exception e) {
   ();
  }
 }

 /**
   * @param
   * @description Randomly generated recording file name
   * @author ldm
   * @time 2016/6/25,
   */
 private String generateFileName() {
  //Randomly generate different UUIDs  return ().toString() + ".amr";
 }

 /**
   * @param
   * @description Get the volume value
   * @author ldm
   * @time 2016/6/25 9:49
   */
 public int getVoiceLevel(int maxlevel) {
  if (isPrepare) {
   try {
    // The maximum value returned by getMaxAmplitude is 32767    return maxlevel * () / 32768 + 1;//Return results between 1-7   } catch (Exception e) {
    ();
   }
  }
  return 1;
 }

 /**
   * @param
   * @description Free resource
   * @author ldm
   * @time 2016/6/25 9:50
   */
 public void release() {
  ();
  ();
  mMediaRecorder = null;
 }

 /**
   * @param
   * @description Recording Cancel
   * @author ldm
   * @time 2016/6/25 9:51
   */
 public void cancel() {
  release();
  if (mCurrentFilePath != null) {
   //Cancel the recording and delete the corresponding file   File file = new File(mCurrentFilePath);
   ();
   mCurrentFilePath = null;
  }

 }

 /**
   * @param
   * @description Get the current file path
   * @author ldm
   * @time 2016/6/25 9:51
   */
 public String getCurrentFilePath() {

  return mCurrentFilePath;
 }
}

If there are comments in the code, you won’t sticker. It’s the same as the WeChat voice chat interface, so it’s called imitating WeChat, haha. You can also see the effect after running. All codes can be downloaded from here:http://xiazai./201611/yuanma/AndroidWXchat().rar

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.