仿微信语音语音聊天

来源:互联网 发布:四川人怎么样知乎 编辑:程序博客网 时间:2024/04/29 09:20

仿微信语音聊天,录音结束后显示在listview上,点击item可进行播放。

一。效果图


二、代码

2.1  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" >


    <ListView
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1" >
    </ListView>


    <Button
        android:id="@+id/button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="测试录音" />


</LinearLayout>

2.2 mainactivity.java的编写

     package com.recorderactivity;


import java.util.ArrayList;
import java.util.List;


import com.recorderactivity.AudioManager.AudioStateListener;


import android.R.integer;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;


@SuppressLint({ "ClickableViewAccessibility", "HandlerLeak" })
public class MainActivity extends Activity {
private Button button;
private ListView listview;
private ListViewAdapter mAdapter;
private List<RecorderEntity> mDatas = new ArrayList<RecorderEntity>();


/**
* 录音的三种状态
*/
private static final int STATE_NORMAL = 1;// 默认状态
private static final int STATE_RECORDING = 2;// 录音状态
private static final int STATE_CANCEL = 3;// 取消状态
private int mCurState = STATE_NORMAL;// 默认状态


private boolean isRecording = false;// 判断是否录音


private static final int DISTANCE_TO_CANCEL = 50;


private DialogManager mDialogManager;
private AudioManager mAudioManager;


private String dir = Environment.getExternalStorageDirectory()
+ "/RecordActivity";


private static final int MSG_AUDIO_PREPARED = 0X110;
private static final int MSG_VOICE_CHANGED = 0X111;
private static final int MSG_DIALOG_DIMISS = 0X112;
private Handler mHandler;


private float mTime;
private boolean mReady;// 是否触发onlongclick
private View mAnimView;// 播放动画view


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
initDate();
setListener();
}


/**
* @Description:初始化控件
* @author :吴雄峰

*/


private void initView() {
// TODO 自动生成的方法存根
button = (Button) findViewById(R.id.button);
listview = (ListView) findViewById(R.id.listview);


}


/**
* @Description:初始化数据
* @author :吴雄峰

*/


private void initDate() {
mDialogManager = new DialogManager(MainActivity.this);
mAudioManager = AudioManager.getInstance(dir);


mAdapter = new ListViewAdapter(getApplicationContext(), mDatas);
listview.setAdapter(mAdapter);


mHandler = new Handler() {


@Override
public void handleMessage(Message msg) {
// TODO 自动生成的方法存根


switch (msg.what) {
case MSG_AUDIO_PREPARED:
mDialogManager.showRecordingDialog();
isRecording = true;
new Thread(mGetVoiceLevelRunnable).start();
break;
case MSG_VOICE_CHANGED:
mDialogManager.updateVoiceLevel(mAudioManager
.getVoiceLevel(7));
break;
case MSG_DIALOG_DIMISS:
mDialogManager.dimissDialog();
break;
default:
break;
}
}
};
}


/**
* @Description:设置监听
* @author :吴雄峰

*/


private void setListener() {
// TODO 自动生成的方法存根
button.setOnLongClickListener(new OnLongClickListener() {


@Override
public boolean onLongClick(View v) {
mReady = true;
mAudioManager.prepareAudio();
return false;
}
});


button.setOnTouchListener(new OnTouchListener() {


@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO 自动生成的方法存根
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) {// 已经开始录音
// 根据x,y的坐标判断是否想要取消
if (wantToCancel(x, y)) {
changeState(STATE_CANCEL);
} else {
changeState(STATE_RECORDING);
}


}


break;
case MotionEvent.ACTION_UP:
if (!mReady) {
reSet();
return onTouchEvent(event);


}
if (!isRecording || mTime < 0.6f) {// 时间过短,录音还没开始
mDialogManager.tooShort();
mAudioManager.cancel();
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS,
1300);
} else if (mCurState == STATE_RECORDING) {// 正常结束
mDialogManager.dimissDialog();
mAudioManager.release();


// 添加数据到listview中
RecorderEntity mEntity = new RecorderEntity(mTime,
mAudioManager.getCurrentFilePath());
mDatas.add(mEntity);
mAdapter.notifyDataSetChanged();
listview.setSelection(mDatas.size() - 1);


} else if (mCurState == STATE_CANCEL) {// 取消
mDialogManager.dimissDialog();
mAudioManager.cancel();
}


reSet();
break;


default:
break;
}
return false;
}
});


mAudioManager.setOnAudioStateListener(new AudioStateListener() {


@Override
public void wellPrepared() {
// TODO 自动生成的方法存根
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);


}
});


listview.setOnItemClickListener(new OnItemClickListener() {


@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (mAnimView != null) {
mAnimView.setBackgroundResource(R.drawable.adj);
mAnimView = null;
}
// 播放动画,帧动画去实现
mAnimView = view.findViewById(R.id.id_recorder_anim);
mAnimView.setBackgroundResource(R.drawable.play_anim);
AnimationDrawable animationDrawable = (AnimationDrawable) mAnimView
.getBackground();
animationDrawable.start();
// 播放音频
MediaManager.playSound(mDatas.get(position).getmFilePath(),
new MediaPlayer.OnCompletionListener() {


@Override
public void onCompletion(MediaPlayer mp) {
mAnimView.setBackgroundResource(R.drawable.adj);
}
});
}
});


}


@Override
protected void onPause() {
// TODO 自动生成的方法存根
super.onPause();
MediaManager.pause();
}


@Override
protected void onResume() {
// TODO 自动生成的方法存根
super.onResume();
MediaManager.resume();
}


@Override
protected void onDestroy() {
// TODO 自动生成的方法存根
super.onDestroy();
MediaManager.release();
}


/**
* 获取音量大小的runnable
*/
private Runnable mGetVoiceLevelRunnable = new Runnable() {


@Override
public void run() {
// TODO 自动生成的方法存根
while (isRecording) {
try {
Thread.sleep(100);
mTime += 0.1f;
mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);
} catch (Exception e) {
// TODO: handle exception
}
}
}
};


/**
* @Description: 恢复状态及标志位
* @author :吴雄峰

*/


protected void reSet() {
// TODO 自动生成的方法存根
isRecording = false;
changeState(STATE_NORMAL);
mTime = 0;
mReady = false;


}


/**
* @Description: 根据坐标判断是否要取消
* @author :吴雄峰

*/


protected boolean wantToCancel(int x, int y) {


if (x < 0 || x > button.getWidth()) {
return true;
}
if (y < -DISTANCE_TO_CANCEL
|| y > button.getHeight() + DISTANCE_TO_CANCEL) {
return true;
}
return false;
}


/**
* @Description:改变状态
* @author :吴雄峰

*/


protected void changeState(int state) {
// TODO 自动生成的方法存根
if (mCurState != state) {
mCurState = state;
switch (state) {
case STATE_NORMAL:
button.setBackgroundResource(R.drawable.button_recorder_normal);
button.setText(R.string.str_recorder_normal);
break;
case STATE_RECORDING:
button.setBackgroundResource(R.drawable.button_recorder_recording);
button.setText(R.string.str_recorder_recordering);
if (isRecording) {
mDialogManager.recording();
}
break;
case STATE_CANCEL:
button.setBackgroundResource(R.drawable.button_recorder_recording);
button.setText(R.string.str_recorder_want_to_cancel);
if (isRecording) {
mDialogManager.wantToCancel();
}
break;


default:
break;
}
}


}


}


2.3  dialogManager.java的编写

   package com.recorderactivity;


import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;


/**
 * @ClassName:DialogManager
 * @Description:TODO
 * @author :吴雄峰
 * @Date :2015 2015年5月22日 下午8:34:32
 *
 */
public class DialogManager {


private Dialog dialog;


private ImageView mIcon, mVoice;
private TextView mLable;


@SuppressWarnings("unused")
private Context mContext;


/**
* @Description:TODO
* @author :吴雄峰
* @Date : 2015年5月22日 下午9:16:24

*/
public DialogManager(Context context) {


this.mContext = context;
}


public void showRecordingDialog() {
dialog = new Dialog(mContext, R.style.Theme_AudioDialog);
LayoutInflater mInflater = LayoutInflater.from(mContext);
View view = mInflater.inflate(R.layout.dialog_recorder, null);
dialog.setContentView(view);


mIcon = (ImageView) dialog.findViewById(R.id.id_dialog_recorder_icon);
mVoice = (ImageView) dialog.findViewById(R.id.id_dialog_recorder_voice);
mLable = (TextView) dialog.findViewById(R.id.id_recorder_dialog_label);


dialog.show();


}


public void recording() {
if (dialog != null && dialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.VISIBLE);
mLable.setVisibility(View.VISIBLE);


mIcon.setImageResource(R.drawable.recorder);
mLable.setText("手指上滑,取消发送");


}
}


public void wantToCancel() {
if (dialog != null && dialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLable.setVisibility(View.VISIBLE);


mIcon.setImageResource(R.drawable.cancel);
mLable.setText("松开手指,取消发送");


}


}


public void tooShort() {
if (dialog != null && dialog.isShowing()) {
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.GONE);
mLable.setVisibility(View.VISIBLE);


mIcon.setImageResource(R.drawable.voice_to_short);
mLable.setText("录音时间过短");
}


}


public void dimissDialog() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
dialog = null;


}
}


/**

* @Description:通过Level去更新图片
* @author :吴雄峰
*
*/
public void updateVoiceLevel(int level) {
if (dialog != null && dialog.isShowing()) {
int resId = mContext.getResources().getIdentifier("v" + level,
"drawable", mContext.getPackageName());
mVoice.setImageResource(resId);
}
}


}


2.4 AudioManager.java 的编写

package com.recorderactivity;


import java.io.File;
import java.io.IOException;
import java.util.UUID;


import android.media.MediaRecorder;


/**
 * @ClassName:AudioManager
 * @Description:TODO
 * @author :吴雄峰
 * @Date :2015 2015年5月23日 下午10:17:45
 *
 */
public class AudioManager {
private MediaRecorder mMediaRecorder;
private String mDir;
private String mCurrentPath;


private static AudioManager mInstance;


private String mCurrentFilePath;// 文件路径


private boolean isPrepared;


public AudioManager(String dir) {
mDir = dir;
}


public interface AudioStateListener {
void wellPrepared();
}


public AudioStateListener mListener;


public void setOnAudioStateListener(AudioStateListener listener) {
mListener = listener;
}


public static AudioManager getInstance(String dir) {
if (mInstance == null) {
synchronized (AudioManager.class) {
if (mInstance == null) {
mInstance = new AudioManager(dir);
}
}
}
return mInstance;
}


// 准备
public void prepareAudio() {


try {
isPrepared = false;
// 创建文件夹
File dir = new File(mDir);
if (!dir.exists()) {
dir.mkdirs();
}


String fileName = generateFileName();
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.AMR_NB);
// 设置音频编码
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);


mMediaRecorder.prepare();
mMediaRecorder.start();


// 准备结束
isPrepared = true;
if (mListener != null) {
mListener.wellPrepared();
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}


}


/**
* @Description:随机生成文件的名称
* @author :吴雄峰

*/


private String generateFileName() {
return UUID.randomUUID().toString() + ".amr";
}


public int getVoiceLevel(int maxLevel) {
if (isPrepared) {
try {
// getMaxAmplitude() 1-32767
return maxLevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;
} catch (Exception e) {
// TODO: handle exception
}
}
return 1;
}


public void release() {


mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;


}


public void cancel() {
release();
if (mCurrentFilePath != null) {
File file = new File(mCurrentFilePath);
file.delete();
mCurrentFilePath = null;
}


}


/**
* @Description:
* @author :吴雄峰

*/

public String getCurrentFilePath() {
// TODO 自动生成的方法存根
return mCurrentFilePath;
}


}

2.5 MediaManager.java的编写

package com.recorderactivity;


import java.io.IOException;


import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;


/**
 * @ClassName:MediaManager
 * @Description:TODO
 * @author :吴雄峰
 * @Date :2015 2015年5月24日 下午3:20:14
 *
 */
public class MediaManager {


private static MediaPlayer mMediaPlayer;
private static boolean isPause;


public static void playSound(String filePath, OnCompletionListener listener) {


if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnErrorListener(new OnErrorListener() {


@Override
public boolean onError(MediaPlayer mp, int what, int extra) {


mMediaPlayer.reset();
return false;
}
});
} else {
mMediaPlayer.reset();
}
try {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnCompletionListener(listener);
mMediaPlayer.setDataSource(filePath);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IllegalArgumentException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (SecurityException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}


}


// 暂停
public static void pause() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
isPause = true;
}


}


// 继续播放
public static void resume() {
if (mMediaPlayer != null && isPause) {
mMediaPlayer.start();
isPause = false;
}
}


// 释放
public static void release() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
}


}


2.6 ViewHolder.java 的编写 (封装了,直接贴起来用,不用每次在adapter中写viewholder)

package com.recorderactivity;




import android.R.integer;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;


/**
 * @ClassName:Viewholder
 * @Description:TODO viewholder基类
 * @author :吴雄峰
 * @Date :2015 2015年5月14日 下午3:51:59
 *
 */
public class Viewholder {


private SparseArray<View> mViews;
private int mPosition;
private View mConvertView;


/**
* @Description:TODO
* @author :吴雄峰
* @Date : 2015年5月14日 下午3:53:37

*/
public Viewholder(Context context, ViewGroup parent, int layoutId,
int position) {
this.mPosition = position;
this.mViews = new SparseArray<View>();
mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,
false);
mConvertView.setTag(this);


}


/**

* @Description:初始化viewholder
* @author :吴雄峰
*
*/
public static Viewholder get(Context context, View convertView,
ViewGroup parent, int layoutId, int position) {


if (convertView == null) {
return new Viewholder(context, parent, layoutId, position);
} else {
Viewholder viewholder = (Viewholder) convertView.getTag();
viewholder.mPosition=position;
return viewholder;
}
}


/**

* @Description:通过viewID获取控件
* @author :吴雄峰
*
*/
public <T extends View> T getView(int viewId) {
View view = mViews.get(viewId);
if (view == null) {
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}


return (T) view;
}


public View getConvertView() {
return mConvertView;
}

/**

* @Description:设置textview 的值
* @author :吴雄峰
*
*/
public Viewholder setText(int viewId,String text)
{
TextView tv=getView(viewId);
tv.setText(text);
return this;

}

/**

* @Description:用setImageResource方法设置imageview的图片
* @author :吴雄峰
*
*/
public Viewholder setImageViewResource(int viewId,int  resId)
{
ImageView imageView=getView(viewId);
imageView.setImageResource(resId);
return this;

}

/**

* @Description:用setImageBitmap方法设置imageview的图片
* @author :吴雄峰
*
*/
public Viewholder setImageViewBitmap(int viewId,Bitmap  bitmap)
{
ImageView imageView=getView(viewId);
imageView.setImageBitmap(bitmap);
return this;

}

public Viewholder setImageViewUri(int viewId,String uri)
{
ImageView imageView=getView(viewId);
//imageLoader.getInstance().load(view,uri);
return this;

}
}


2.7 listview 适配器的编写

package com.recorderactivity;


import java.util.List;


import android.content.Context;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.BaseAdapter;


/**
 * @ClassName:ListViewAdapter
 * @Description:TODO
 * @author :吴雄峰
 * @Date :2015 2015年5月24日 下午1:12:35
 *
 */
public class ListViewAdapter extends BaseAdapter {


private int mMinItemWidth;
private int mMaxItemWidth;
private Context mContext;
private List<RecorderEntity> mDatas;


public ListViewAdapter(Context context, List<RecorderEntity> data) {
// TODO 自动生成的构造函数存根
this.mContext = context;
this.mDatas = data;


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);
}


/**
* @author :吴雄峰
* @Date : 2015年5月24日 下午2:33:19
* @Description:
*/
@Override
public int getCount() {
// TODO 自动生成的方法存根
return mDatas.size();
}


/**
* @author :吴雄峰
* @Date : 2015年5月24日 下午2:33:19
* @Description:
*/
@Override
public Object getItem(int position) {
// TODO 自动生成的方法存根
return mDatas.get(position);
}


/**
* @author :吴雄峰
* @Date : 2015年5月24日 下午2:33:19
* @Description:
*/
@Override
public long getItemId(int position) {
// TODO 自动生成的方法存根
return position;
}


/**
* @author :吴雄峰
* @Date : 2015年5月24日 下午2:33:19
* @Description:
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {


Viewholder viewholder = new Viewholder(mContext, parent,
R.layout.item_recorder, position);
viewholder.setText(R.id.id_recorder_time,
Math.round(mDatas.get(position).getmTime()) + "\"");


//控制长度
View lengh = viewholder.getView(R.id.id_recorder_lengh);
ViewGroup.LayoutParams lp = lengh.getLayoutParams();
lp.width = (int) (mMinItemWidth + mMaxItemWidth / 60f
* mDatas.get(position).getmTime());
return viewholder.getConvertView();
}
}


2.8 listview的实体类编写

package com.recorderactivity;


/**
 * @ClassName:RecorderEntity
 * @Description:TODO
 * @author :吴雄峰
 * @Date :2015 2015年5月24日 下午1:07:53
 *
 */
public class RecorderEntity {
private float mTime;
private String mFilePath;


/**
* @Description:TODO
* @author :吴雄峰
* @Date : 2015年5月24日 下午1:09:12

*/
public RecorderEntity(float time, String filePath) {


super();
this.mFilePath = filePath;
this.mTime = time;
}


/**
* @return mTime
*/
public float getmTime() {
return mTime;
}


/**
* @param mTime
*            要设置的 mTime
*/
public void setmTime(float mTime) {
this.mTime = mTime;
}


/**
* @return mFilePath
*/
public String getmFilePath() {
return mFilePath;
}


/**
* @param mFilePath
*            要设置的 mFilePath
*/
public void setmFilePath(String mFilePath) {
this.mFilePath = mFilePath;
}


}

dialog的布局编写

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    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_dialog_recorder_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/recorder"
            android:visibility="visible" />


        <ImageView
            android:id="@+id/id_dialog_recorder_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_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="手指上滑,取消发送"
        android:textColor="#FFFFFF"
        android:visibility="visible" />


</LinearLayout>


listview的item编写

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    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_lengh"
        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_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginRight="3dp"
        android:layout_toLeftOf="@id/id_recorder_lengh"
        android:text=""
        android:textColor="#777777" />


</RelativeLayout>

话说源代码怎么上传。有需要的朋友找我要把,QQ: 540886047

0 0