Android自定義UI實現(xiàn)微信語音
本文實例為大家分享了java獲取不同路徑的方法,供大家參考,具體內(nèi)容如下
思路:
自定義Button
獲取DialogManager、AudioManager setOnLongClickListener長按事件--做好AudioManager的錄音準備工作
AudioManager.setOnAudioStateListener(this)實現(xiàn)錄音準備完畢的接口回調方法,方法中去發(fā)送MSG_AUDIO_PREPARE消息代表錄音準備工作完畢
在mHandler中接收消息,開始開啟線程錄音,并且計時,計時的過程中,去發(fā)送MSG_VOICE_CHANGED消息,去updateVoiceLeve更新音量圖標,另外在MotionEvent.ACTION_UP事件中,去定義audioFinishRecorderListener.onFinish接口方法,方法是錄音完畢的回調方法,在MainActivity中,mAudioRecorderButton.setAudioFinishRecorderListener實現(xiàn)錄音完畢回調方法去更新listViewUi界面
點擊listViewItem條目播放動畫, MediaManager.playSound并且播放音頻
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.imooc_recorder.MainActivity" > <ListView android:id="@+id/id_listview" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#ebebeb" android:divider="@null" android:dividerHeight="10dp" > </ListView> <FrameLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <View android:background="#ccc" android:layout_width="fill_parent" android:layout_height="1dp" /> <com.example.recorder_view.AudioRecorderButton android:id="@+id/id_recorder_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="7dp" android:layout_marginLeft="50dp" android:layout_marginRight="50dp" android:layout_marginTop="6dp" android:background="@drawable/button_recorder_normal" android:gravity="center" android:minHeight="0dp" android:padding="5dp" android:text="@string/str_recorder_nomal" android:textColor="#727272" > </com.example.recorder_view.AudioRecorderButton> </FrameLayout> </LinearLayout>
dialog_recorder.xml---dialog布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/dialog_loading_bg" android:gravity="center" android:orientation="vertical" android:padding="20dp" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/id_recorder_dialog_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/recorder" android:visibility="visible" /> <ImageView android:id="@+id/id_recorder_dialog_voice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/v1" android:visibility="visible" /> </LinearLayout> <TextView android:id="@+id/id_recorder_dialog_label" android:layout_marginTop="5dp" android:text="手指上滑,取消發(fā)送" android:textColor="#ffffff" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
item_recorder.xml--listview中的每個item
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="#eeeeee" android:layout_height="60dp" android:layout_marginTop="5dp" > <ImageView android:id="@+id/id_icon" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="5dp" android:src="@drawable/icon" /> <FrameLayout android:id="@+id/id_recorder_length" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toLeftOf="@id/id_icon" android:background="@drawable/chatto_bg_focused" > <View android:id="@+id/id_recorder_anim" android:layout_width="25dp" android:layout_height="25dp" android:layout_gravity="center_vertical|right" android:background="@drawable/adj" /> </FrameLayout> <TextView android:id="@+id/id_recorder_time" android:layout_centerVertical="true" android:layout_toLeftOf="@id/id_recorder_length" android:layout_marginRight="3dp" android:textColor="#ff777777" android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
styles.xml
<style name="Theme_AudioDialog" parent="@android:Theme.Dialog"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowFrame">@null</item> <item name="android:windowIsFloating">true</item> <item name="android:windowIsTranslucent">true</item> <item name="android:backgroundDimEnabled">false</item> </style>
button_recorder_normal.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#ffffff"/> <stroke android:width="1px" android:color="#9b9b9b"/> <corners android:radius="3dp"/> </shape>
button_recorder_recording.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#ffffff"/> <stroke android:width="1px" android:color="#eeeeee"/> <corners android:radius="3dp"/> </shape>
play_anim.xml
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/v_anim1" android:duration="300"> </item> <item android:drawable="@drawable/v_anim2" android:duration="300"> </item> <item android:drawable="@drawable/v_anim3" android:duration="300"> </item> </animation-list>
MainActivity
package com.example.imooc_recorder;
import java.util.ArrayList;
import java.util.List;
import com.example.recorder_view.AudioRecorderButton;
import com.example.recorder_view.AudioRecorderButton.AudioFinishRecorderListener;
import com.example.recorder_view.MediaManager;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MainActivity extends Activity {
private ListView mListView;
private ArrayAdapter<Recorder> mAdapter;
private List<Recorder> mDatas = new ArrayList<MainActivity.Recorder>();
private AudioRecorderButton mAudioRecorderButton;
private View animView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.id_listview);
mAudioRecorderButton = (AudioRecorderButton) findViewById(R.id.id_recorder_button);
//錄音完畢,回調
mAudioRecorderButton.setAudioFinishRecorderListener(new AudioFinishRecorderListener() {
@Override
public void onFinish(float seconds, String filePath) {
// TODO Auto-generated method stub
Recorder recorder = new Recorder(seconds, filePath);
mDatas.add(recorder);
mAdapter.notifyDataSetChanged();
mListView.setSelection(mDatas.size()-1);
}
});
mAdapter = new RecorderAdapter(this, mDatas);
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (animView !=null) {
animView.setBackgroundResource(R.drawable.adj);
animView = null;
}
//播放動畫
animView = view.findViewById(R.id.id_recorder_anim);
animView.setBackgroundResource(R.drawable.play_anim);
AnimationDrawable anim = (AnimationDrawable) animView.getBackground();
anim.start();
//播放音頻
MediaManager.playSound(mDatas.get(position).filePath,new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
animView.setBackgroundResource(R.drawable.adj);
}
});
}
});
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
MediaManager.pause();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
MediaManager.resume();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
MediaManager.release();
}
/**內(nèi)部類*/
class Recorder{
float time;
String filePath;
public Recorder(float time, String filePath) {
super();
this.time = time;
this.filePath = filePath;
}
public float getTime() {
return time;
}
public void setTime(float time) {
this.time = time;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
}
}
RecorderAdapter
package com.example.imooc_recorder;
import java.util.List;
import com.example.imooc_recorder.MainActivity.Recorder;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
public class RecorderAdapter extends ArrayAdapter<Recorder> {
// private List<Recorder> mDatas;
// private Context mContext;
private int mMinItemWidth;
private int mMaxItemWidth;
private LayoutInflater mInflater;
public RecorderAdapter(Context context, List<Recorder> datas) {
super(context, -1, datas);
// mContext = context;
// mDatas = datas;
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mMaxItemWidth = (int) (outMetrics.widthPixels * 0.7f);
mMinItemWidth = (int) (outMetrics.widthPixels * 0.15f);
mInflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_recorder, parent,
false);
holder = new ViewHolder();
holder.seconds = (TextView) convertView.findViewById(R.id.id_recorder_time);
holder.length = convertView.findViewById(R.id.id_recorder_length);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
holder.seconds.setText(Math.round(getItem(position).time)+"\"");
ViewGroup.LayoutParams lp = holder.length.getLayoutParams();
lp.width = (int) (mMinItemWidth +(mMaxItemWidth/60f*getItem(position).time));
return convertView;
}
private class ViewHolder {
private TextView seconds;
private View length;
}
}
AudioRecorderButton
package com.example.recorder_view;
import com.example.imooc_recorder.R;
import com.example.recorder_view.AudioManager.AudioStateListener;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.telephony.SignalStrength;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
public class AudioRecorderButton extends Button implements AudioStateListener {
private static final int DISTANCE_Y_CANCEL = 50;
/** 提示框管理工具類 */
private DialogManager mDialogManager;
/** 正常、松開手指取消發(fā)送、手指上滑取消發(fā)送 */
private static final int STATE_NORMAL = 1;
private static final int STATE_RECORDING = 2;
private static final int STATE_WANT_TO_CANCEL = 3;
/** 初始狀態(tài):正常 */
private int mCurState = STATE_NORMAL;
/** 當前是否正在錄音 */
private boolean isRecording = false;
/** 錄音工具類 */
private AudioManager mAudioManager;
/** 錄音總時間 */
private float mTime;
/** 是否觸發(fā)button */
private boolean mReady;
/** *****************自定義Button************************************* */
public AudioRecorderButton(Context context) {
super(context);
}
public AudioRecorderButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public AudioRecorderButton(Context context, AttributeSet attrs) {
super(context, attrs);
mDialogManager = new DialogManager(getContext());
String dir = Environment.getExternalStorageDirectory()
+ "/imooc_recorder_audios";
mAudioManager = AudioManager.getInstance(dir);
mAudioManager.setOnAudioStateListener(this);
/** 監(jiān)聽回調 */
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mReady = true;
// 錄音準備--準備好后,有實現(xiàn)接口方法
mAudioManager.prepareAndio();
return false;
}
});
}
/******************************************************
* 完成錄音準備的回調函數(shù)
*/
@Override
public void wellPrepared() {
// 準備完畢,發(fā)送消息
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARE);
}
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_AUDIO_PREPARE:
mDialogManager.showRecordingDailog();
isRecording = true;
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (isRecording) {
try {
Thread.sleep(100);
// 錄音計時
mTime += 0.1f;
mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
break;
case MSG_VOICE_CHANGED:
mDialogManager.updateVoiceLeve(mAudioManager.getVoiceLevel(7));
break;
case MSG_DIALOG_DIMISS:
mDialogManager.dimissDailog();
break;
default:
break;
}
super.handleMessage(msg);
};
};
private static final int MSG_AUDIO_PREPARE = 0x110;
private static final int MSG_VOICE_CHANGED = 0x111;
private static final int MSG_DIALOG_DIMISS = 0x112;
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
changeState(STATE_RECORDING);
break;
case MotionEvent.ACTION_MOVE:
if (isRecording) {
// 根據(jù)xy坐標。判斷是否想要取消
if (wantToCancel(x, y)) {
changeState(STATE_WANT_TO_CANCEL);
} else {
changeState(STATE_RECORDING);
}
}
break;
case MotionEvent.ACTION_UP:
if (!mReady) {
// 沒有觸發(fā)onclick
reset();
return super.onTouchEvent(event);
}
if (!isRecording || mTime < 0.6f) {
// prapred沒有完成已經(jīng)up了
mDialogManager.tooShort();
mAudioManager.cancel();
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);
} else if (mCurState == STATE_RECORDING) {
mDialogManager.dimissDailog();
mAudioManager.release();
if (audioFinishRecorderListener != null) {
audioFinishRecorderListener.onFinish(mTime,
mAudioManager.getCurrentFilePath());
}
} else if (mCurState == STATE_WANT_TO_CANCEL) {
mDialogManager.dimissDailog();
mAudioManager.cancel();
}
// 恢復標志位
reset();
break;
default:
break;
}
return super.onTouchEvent(event);
}
private void reset() {
// TODO Auto-generated method stub
mReady = false;
mTime = 0;
isRecording = false;
changeState(STATE_NORMAL);
}
private boolean wantToCancel(int x, int y) {
// x<0代表來到按鈕的范圍以外
if (x < 0 || x > getWidth()) {
return true;
}
if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
return true;
}
return false;
}
private void changeState(int state) {
// TODO Auto-generated method stub
if (mCurState != state) {
mCurState = state;
switch (state) {
case STATE_NORMAL:
setBackgroundResource(R.drawable.button_recorder_normal);
setText(R.string.str_recorder_nomal);
break;
case STATE_RECORDING:
setBackgroundResource(R.drawable.button_recorder_recording);
setText(R.string.str_recorder_recording);
if (isRecording) {
// to do
mDialogManager.recording();
}
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.button_recorder_recording);
setText(R.string.str_recorder_want_cancel);
mDialogManager.wantToCancle();
break;
default:
break;
}
}
}
/** 完成錄音回調 */
public interface AudioFinishRecorderListener {
void onFinish(float seconds, String filePath);
}
private AudioFinishRecorderListener audioFinishRecorderListener;
public void setAudioFinishRecorderListener(
AudioFinishRecorderListener audioFinishRecorderListener) {
this.audioFinishRecorderListener = audioFinishRecorderListener;
}
}
DialogManager
package com.example.recorder_view;
import com.example.imooc_recorder.R;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
public class DialogManager {
private Dialog mDialog;
private ImageView mIcon;
private ImageView mVoice;
private TextView mLabel;
private Context mContext;
public DialogManager(Context context) {
this.mContext = context;
}
public void showRecordingDailog() {
mDialog = new Dialog(mContext, R.style.Theme_AudioDialog);
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.dialog_recorder, null);
mDialog.setContentView(view);
mIcon = (ImageView) mDialog.findViewById(R.id.id_recorder_dialog_icon);
mVoice = (ImageView) mDialog
.findViewById(R.id.id_recorder_dialog_voice);
mLabel = (TextView) mDialog.findViewById(R.id.id_recorder_dialog_label);
mDialog.show();
}
public void recording() {
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.VISIBLE);
mLabel.setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.recorder);
mLabel.setText("手指上滑,取消發(fā)送");
}
}
public void wantToCancle() {
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLabel.setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.cancel);
mLabel.setText("松開手指,取消發(fā)送");
}
}
public void tooShort() {
if (mDialog != null && mDialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLabel.setVisibility(View.VISIBLE);
mIcon.setImageResource(R.drawable.voice_to_short);
mLabel.setText("錄音時間過短");
}
}
public void dimissDailog() {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
mDialog = null;
}
}
public void updateVoiceLeve(int level) {
if (mDialog != null && mDialog.isShowing()) {
// mIcon.setVisibility(View.VISIBLE);
// mVoice.setVisibility(View.VISIBLE);
// mLabel.setVisibility(View.VISIBLE);
// 通過方法名字,找到資源
int resId = mContext.getResources().getIdentifier("v" + level,
"drawable", mContext.getPackageName());
mVoice.setImageResource(resId);
}
}
}
AudioManager
package com.example.recorder_view;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import javax.security.auth.PrivateCredentialPermission;
import android.R.integer;
import android.media.MediaRecorder;
public class AudioManager {
private MediaRecorder mMediaRecorder;
private String mDir;
private String mCurrentFilepath;
private static AudioManager mInstance;
private boolean isPrepare;
/** 接口回調 */
public interface AudioStateListener {
void wellPrepared();
}
public AudioStateListener mAudioStateListener;
public void setOnAudioStateListener(AudioStateListener audioStateListener) {
mAudioStateListener = audioStateListener;
}
private AudioManager(String dir) {
this.mDir = dir;
}
public static AudioManager getInstance(String dir) {
if (mInstance == null) {
synchronized (AudioManager.class) {
if (mInstance == null) {
mInstance = new AudioManager(dir);
}
}
}
return mInstance;
}
public void prepareAndio() {
isPrepare = false;
File dir = new File(mDir);
if (!dir.exists()) {
dir.mkdirs();
}
String fileName = geneFileName();
File file = new File(dir, fileName);
mCurrentFilepath = file.getAbsolutePath();
mMediaRecorder = new MediaRecorder();
// 設置輸出文件
mMediaRecorder.setOutputFile(file.getAbsolutePath());
// 音頻源頭
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 設置音頻格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
// 設置音頻編碼
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mMediaRecorder.prepare();
mMediaRecorder.start();
isPrepare = true;
if (mAudioStateListener != null) {
mAudioStateListener.wellPrepared();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String geneFileName() {
return UUID.randomUUID().toString() + ".amr";
}
public int getVoiceLevel(int maxLevel) {
if (isPrepare) {
try {
// mMediaRecorder.getMaxAmplitude() 1~32767
// return maxlevel*mMediaRecorder.getMaxAmplitude()/32768+1;
return maxLevel * new MediaRecorder().getMaxAmplitude() / 32768
+ 1;
} catch (Exception e) {
}
}
return 1;
}
public void release() {
mMediaRecorder.release();
mMediaRecorder = null;
}
public void cancel() {
release();
if (mCurrentFilepath != null) {
File file = new File(mCurrentFilepath);
file.delete();
mCurrentFilepath = null;
}
}
public String getCurrentFilePath() {
// TODO Auto-generated method stub
return mCurrentFilepath;
}
}
MediaManager
package com.example.recorder_view;
import java.io.IOException;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
public class MediaManager {
private static MediaPlayer mediaPlayer;
private static boolean isPause;
public static void playSound(String filePath,
OnCompletionListener onCompletionListener) {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mediaPlayer.reset();
return false;
}
});
}else {
mediaPlayer.reset();
}
try {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnCompletionListener(onCompletionListener);
mediaPlayer.setDataSource(filePath);
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
mediaPlayer.start();
}
public static void pause(){
if (mediaPlayer!=null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
isPause = true;
}
}
public static void resume(){
if (mediaPlayer!=null && isPause) {
mediaPlayer.start();
isPause = false;
}
}
public static void release(){
if (mediaPlayer!=null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
}
本文已被整理到了《Android微信開發(fā)教程匯總》,歡迎大家學習閱讀。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android?Jetpack庫重要組件WorkManager的使用
WorkManager是Android?Jetpack的一個強大的組件,用于處理后臺耗時任務。后臺任務可以是一次性的,也可以是重復的,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08
Android實現(xiàn)錄音功能實現(xiàn)實例(MediaRecorder)
本篇文章主要介紹了Android實現(xiàn)錄音的實例代碼(MediaRecorder),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
Android開發(fā)之組件GridView簡單使用方法示例
這篇文章主要介紹了Android開發(fā)之組件GridView簡單使用方法,涉及Android GridView組件圖片瀏覽及保存圖片等相關操作技巧,需要的朋友可以參考下2019-03-03
android端微信支付V3版本地簽名統(tǒng)一下單詳解
本篇文章主要介紹了android端微信支付V3版本地簽名統(tǒng)一下單,具有一定的參考價值,有興趣的同學可以了解一下。2016-11-11
Android實現(xiàn)上拉加載更多以及下拉刷新功能(ListView)
這篇文章主要介紹了Android實現(xiàn)上拉加載更多功能以及下拉刷新功能的相關資料,需要的朋友可以參考下2016-01-01

