如何创建一个带有滑动取消的录音按钮的whatsapp
How to create a whatsapp like recording button with slide to cancel
因为在 whatsapp 中我需要一个重新编码按钮和一个幻灯片来取消和淡化动画,我已经搜索了类似的代码但没有找到。
我是 android 编程新手任何帮助或 link 可能会有帮助。
我创建了一个githubproject.You可以看看https://github.com/sarathnk/Audio
audioSendButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText
.getLayoutParams();
params.leftMargin = dp(30);
slideText.setLayoutParams(params);
ViewProxy.setAlpha(slideText, 1);
startedDraggingX = -1;
// startRecording();
startrecord();
audioSendButton.getParent()
.requestDisallowInterceptTouchEvent(true);
recordPanel.setVisibility(View.VISIBLE);
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP
|| motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
startedDraggingX = -1;
stoprecord();
// stopRecording(true);
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
float x = motionEvent.getX();
if (x < -distCanMove) {
stoprecord();
// stopRecording(false);
}
x = x + ViewProxy.getX(audioSendButton);
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText
.getLayoutParams();
if (startedDraggingX != -1) {
float dist = (x - startedDraggingX);
params.leftMargin = dp(30) + (int) dist;
slideText.setLayoutParams(params);
float alpha = 1.0f + dist / distCanMove;
if (alpha > 1) {
alpha = 1;
} else if (alpha < 0) {
alpha = 0;
}
ViewProxy.setAlpha(slideText, alpha);
}
if (x <= ViewProxy.getX(slideText) + slideText.getWidth()
+ dp(30)) {
if (startedDraggingX == -1) {
startedDraggingX = x;
distCanMove = (recordPanel.getMeasuredWidth()
- slideText.getMeasuredWidth() - dp(48)) / 2.0f;
if (distCanMove <= 0) {
distCanMove = dp(80);
} else if (distCanMove > dp(80)) {
distCanMove = dp(80);
}
}
}
if (params.leftMargin > dp(30)) {
params.leftMargin = dp(30);
slideText.setLayoutParams(params);
ViewProxy.setAlpha(slideText, 1);
startedDraggingX = -1;
}
}
view.onTouchEvent(motionEvent);
return true;
}
});
我已经在 whatsapp 应用程序中实现了发送按钮,它可以处于发送状态或记录状态。您可以在我的 blog post.
上查看它
用法很简单
<com.gunhansancar.android.animbutton.AnimButton
android:id="@+id/animButton"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_width="50dp"
android:layout_height="50dp"
app:first="@drawable/ic_mic"
app:second="@drawable/ic_send" />
您只需设置第一个和第二个可绘制对象。而且你还必须通过调用 goToState() 方法来设置状态。
你可以使用我制作的库RecordView
它很容易设置,并且模拟与 WhatsApp 相同的行为。
只需添加视图 RecordView
和 RecordButton
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.devlomi.recordview.MainActivity">
<com.devlomi.record_view.RecordView
android:id="@+id/record_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/record_button"
app:slide_to_cancel_arrow="@drawable/ic_keyboard_arrow_left"
app:slide_to_cancel_text="Slide To Cancel"
app:slide_to_cancel_margin_right="10dp"/>
<com.devlomi.record_view.RecordButton
android:id="@+id/record_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/bg_mic"
android:scaleType="centerInside"
app:src="@drawable/ic_mic_white"
/>
然后在你的 Activity
RecordView recordView = (RecordView) findViewById(R.id.record_view);
RecordButton recordButton = (RecordButton)
findViewById(R.id.record_button);
//IMPORTANT
recordButton.setRecordView(recordView);
最后你可以处理记录状态
- onStart 开始录制时
- onCancel 滑动取消时
- onFinish 完成记录时 returns 以毫秒为单位的记录时间
onLessThanSecond当记录时间<=1秒
recordView.setOnRecordListener(this);
@Override
public void onStart() {
//Start Recording..
Log.d("RecordView", "onStart");
}
@Override
public void onCancel() {
//On Swipe To Cancel
Log.d("RecordView", "onCancel");
}
@Override
public void onFinish(long recordTime) {
//Stop Recording..
String time = getHumanTimeText(recordTime);
Log.d("RecordView", "onFinish");
Log.d("RecordTime", time);
}
@Override
public void onLessThanSecond() {
//When the record time is less than One Second
Log.d("RecordView", "onLessThanSecond");
}
您可以在按钮和触摸手势上放一个比例动画来检测用户的动作..
在此处查看示例..
https://github.com/varunjohn/Audio-Recording-Animation
这个示例也有类似whatsapp的删除动画和锁定功能..
在此处检查示例代码
imageViewAudio.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (isDeleting) {
return true;
}
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
cancelOffset = (float) (imageViewAudio.getX() / 2.8);
lockOffset = (float) (imageViewAudio.getX() / 2.5);
if (firstX == 0) {
firstX = motionEvent.getRawX();
}
if (firstY == 0) {
firstY = motionEvent.getRawY();
}
startRecord();
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP
|| motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
stopRecording(RecordingBehaviour.RELEASED);
}
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
if (stopTrackingAction) {
return true;
}
UserBehaviour direction = UserBehaviour.NONE;
float motionX = Math.abs(firstX - motionEvent.getRawX());
float motionY = Math.abs(firstY - motionEvent.getRawY());
if (motionX > directionOffset &&
motionX > directionOffset &&
lastX < firstX && lastY < firstY) {
if (motionX > motionY && lastX < firstX) {
direction = UserBehaviour.CANCELING;
} else if (motionY > motionX && lastY < firstY) {
direction = UserBehaviour.LOCKING;
}
} else if (motionX > motionY && motionX > directionOffset && lastX < firstX) {
direction = UserBehaviour.CANCELING;
} else if (motionY > motionX && motionY > directionOffset && lastY < firstY) {
direction = UserBehaviour.LOCKING;
}
if (direction == UserBehaviour.CANCELING) {
if (userBehaviour == UserBehaviour.NONE || motionEvent.getRawY() + imageViewAudio.getWidth() / 2 > firstY) {
userBehaviour = UserBehaviour.CANCELING;
}
if (userBehaviour == UserBehaviour.CANCELING) {
translateX(-(firstX - motionEvent.getRawX()));
}
} else if (direction == UserBehaviour.LOCKING) {
if (userBehaviour == UserBehaviour.NONE || motionEvent.getRawX() + imageViewAudio.getWidth() / 2 > firstX) {
userBehaviour = UserBehaviour.LOCKING;
}
if (userBehaviour == UserBehaviour.LOCKING) {
translateY(-(firstY - motionEvent.getRawY()));
}
}
lastX = motionEvent.getRawX();
lastY = motionEvent.getRawY();
}
view.onTouchEvent(motionEvent);
return true;
}
});
我使用@3llomi 提供的代码创建了一个 class,它只生成展开按钮而没有取消幻灯片动画。因为我想将我的按钮放在回收视图中,所以取消动画只会让东西过于拥挤。我的代码附带一个回调,在录制完成时传送存储在缓存中的音频文件
这些是必要的类和 xml:
public class RecordButton extends AppCompatImageView implements View.OnTouchListener{
private ScaleAnim scaleAnim;
private boolean listenForRecord = true;
private int commId;
private MediaRecorder recorder = null;
private boolean isRecording;
private static SoundPool soundPool = null;
private static int soundStart,soundEnd;
public RecordButton(Context context, int id) {
super(context);
init(context, null);
commId=id;
}
public RecordButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RecordButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordButton);
int imageResource = typedArray.getResourceId(R.styleable.RecordButton_mic_icon, -1);
if (imageResource != -1) {
setTheImageResource(imageResource);
}
typedArray.recycle();
}
if (soundPool==null){
soundPool = new SoundPool.Builder()
.setMaxStreams(5)
.build();
//these are just two wav files with short intro and exit sounds
soundStart=soundPool.load(getContext(),R.raw.start_recording_sound,0);
soundEnd=soundPool.load(getContext(),R.raw.end_recording_sound,0);
}
scaleAnim = new ScaleAnim(this);
this.setOnTouchListener(this);
}
private void setTheImageResource(int imageResource) {
Drawable image = AppCompatResources.getDrawable(getContext(), imageResource);
setImageDrawable(image);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setClip(this);
}
public void setClip(View v) {
if (v.getParent() == null) {
return;
}
if (v instanceof ViewGroup) {
((ViewGroup) v).setClipChildren(false);
((ViewGroup) v).setClipToPadding(false);
}
if (v.getParent() instanceof View) {
setClip((View) v.getParent());
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isListenForRecord()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
((RecordButton) v).startScale();
soundPool.play(soundStart,1,1,0,0,1);
startRecording();
break;
case MotionEvent.ACTION_UP:
stopRecording();
soundPool.play(soundEnd,1,1,0,0,1);
((RecordButton) v).stopScale();
break;
}
}
return isListenForRecord();
}
File file;
//audio recording tools
private void startRecording() {
if (isRecording){
stopRecording();
}
String fileName=getContext().getExternalCacheDir().getAbsolutePath()+"/"+commId+"_"+new Date().getTime()+".amr";
file=new File(fileName);
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB);
recorder.setAudioSamplingRate(8000);
recorder.setAudioChannels(1);
recorder.setAudioEncodingBitRate(12000);
try {
recorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getContext(),fileName,Toast.LENGTH_LONG).show();
recorder.start();
setIsRecording(true);
}
private void stopRecording() {
if (isRecording) {
recorder.stop();
recorder.release();
setIsRecording(false);
recordingFinishedListener.onRecordingFinished(file);
recorder = null;
}
}
private void setIsRecording(boolean isRecording){
this.isRecording=isRecording;
}
protected void startScale() {
scaleAnim.start();
}
protected void stopScale() {
scaleAnim.stop();
}
public void setListenForRecord(boolean listenForRecord) {
this.listenForRecord = listenForRecord;
}
public boolean isListenForRecord() {
return listenForRecord;
}
//callback for when a recording has been made
public interface RecordingFinishedListener{
void onRecordingFinished(File file);
}
RecordingFinishedListener recordingFinishedListener;
public void setRecordingFinishedListener(RecordingFinishedListener recordingFinishedListener) {
this.recordingFinishedListener = recordingFinishedListener;
}
}
然后 class 负责动画,允许您定义扩展程度
public class ScaleAnim {
private View view;
public ScaleAnim(View view) {
this.view = view;
}
void start() {
AnimatorSet set = new AnimatorSet();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.3f);
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.3f);
set.setDuration(150);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.playTogether(scaleY, scaleX);
set.start();
}
void stop() {
AnimatorSet set = new AnimatorSet();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
// scaleY.setDuration(250);
// scaleY.setInterpolator(new DecelerateInterpolator());
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
// scaleX.setDuration(250);
// scaleX.setInterpolator(new DecelerateInterpolator());
set.setDuration(150);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.playTogether(scaleY, scaleX);
set.start();
}
}
和 attrs.xml 文件。其余的只是一个麦克风图标和一些你可以自己找到的声音
<resources>
<declare-styleable name="RecordButton">
<attr name="mic_icon" format="reference" />
</declare-styleable>
</resources>
通过在录音按钮上设置 RecordingFinishedListener,您可以继续处理录制的声音。
因为在 whatsapp 中我需要一个重新编码按钮和一个幻灯片来取消和淡化动画,我已经搜索了类似的代码但没有找到。 我是 android 编程新手任何帮助或 link 可能会有帮助。
我创建了一个githubproject.You可以看看https://github.com/sarathnk/Audio
audioSendButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText
.getLayoutParams();
params.leftMargin = dp(30);
slideText.setLayoutParams(params);
ViewProxy.setAlpha(slideText, 1);
startedDraggingX = -1;
// startRecording();
startrecord();
audioSendButton.getParent()
.requestDisallowInterceptTouchEvent(true);
recordPanel.setVisibility(View.VISIBLE);
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP
|| motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
startedDraggingX = -1;
stoprecord();
// stopRecording(true);
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
float x = motionEvent.getX();
if (x < -distCanMove) {
stoprecord();
// stopRecording(false);
}
x = x + ViewProxy.getX(audioSendButton);
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) slideText
.getLayoutParams();
if (startedDraggingX != -1) {
float dist = (x - startedDraggingX);
params.leftMargin = dp(30) + (int) dist;
slideText.setLayoutParams(params);
float alpha = 1.0f + dist / distCanMove;
if (alpha > 1) {
alpha = 1;
} else if (alpha < 0) {
alpha = 0;
}
ViewProxy.setAlpha(slideText, alpha);
}
if (x <= ViewProxy.getX(slideText) + slideText.getWidth()
+ dp(30)) {
if (startedDraggingX == -1) {
startedDraggingX = x;
distCanMove = (recordPanel.getMeasuredWidth()
- slideText.getMeasuredWidth() - dp(48)) / 2.0f;
if (distCanMove <= 0) {
distCanMove = dp(80);
} else if (distCanMove > dp(80)) {
distCanMove = dp(80);
}
}
}
if (params.leftMargin > dp(30)) {
params.leftMargin = dp(30);
slideText.setLayoutParams(params);
ViewProxy.setAlpha(slideText, 1);
startedDraggingX = -1;
}
}
view.onTouchEvent(motionEvent);
return true;
}
});
我已经在 whatsapp 应用程序中实现了发送按钮,它可以处于发送状态或记录状态。您可以在我的 blog post.
上查看它用法很简单
<com.gunhansancar.android.animbutton.AnimButton
android:id="@+id/animButton"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_width="50dp"
android:layout_height="50dp"
app:first="@drawable/ic_mic"
app:second="@drawable/ic_send" />
您只需设置第一个和第二个可绘制对象。而且你还必须通过调用 goToState() 方法来设置状态。
你可以使用我制作的库RecordView
它很容易设置,并且模拟与 WhatsApp 相同的行为。
只需添加视图 RecordView
和 RecordButton
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.devlomi.recordview.MainActivity">
<com.devlomi.record_view.RecordView
android:id="@+id/record_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/record_button"
app:slide_to_cancel_arrow="@drawable/ic_keyboard_arrow_left"
app:slide_to_cancel_text="Slide To Cancel"
app:slide_to_cancel_margin_right="10dp"/>
<com.devlomi.record_view.RecordButton
android:id="@+id/record_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/bg_mic"
android:scaleType="centerInside"
app:src="@drawable/ic_mic_white"
/>
然后在你的 Activity
RecordView recordView = (RecordView) findViewById(R.id.record_view);
RecordButton recordButton = (RecordButton)
findViewById(R.id.record_button);
//IMPORTANT
recordButton.setRecordView(recordView);
最后你可以处理记录状态
- onStart 开始录制时
- onCancel 滑动取消时
- onFinish 完成记录时 returns 以毫秒为单位的记录时间
onLessThanSecond当记录时间<=1秒
recordView.setOnRecordListener(this); @Override public void onStart() { //Start Recording.. Log.d("RecordView", "onStart"); } @Override public void onCancel() { //On Swipe To Cancel Log.d("RecordView", "onCancel"); } @Override public void onFinish(long recordTime) { //Stop Recording.. String time = getHumanTimeText(recordTime); Log.d("RecordView", "onFinish"); Log.d("RecordTime", time); } @Override public void onLessThanSecond() { //When the record time is less than One Second Log.d("RecordView", "onLessThanSecond"); }
您可以在按钮和触摸手势上放一个比例动画来检测用户的动作..
在此处查看示例..
https://github.com/varunjohn/Audio-Recording-Animation
这个示例也有类似whatsapp的删除动画和锁定功能..
在此处检查示例代码
imageViewAudio.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (isDeleting) {
return true;
}
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
cancelOffset = (float) (imageViewAudio.getX() / 2.8);
lockOffset = (float) (imageViewAudio.getX() / 2.5);
if (firstX == 0) {
firstX = motionEvent.getRawX();
}
if (firstY == 0) {
firstY = motionEvent.getRawY();
}
startRecord();
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP
|| motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
stopRecording(RecordingBehaviour.RELEASED);
}
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
if (stopTrackingAction) {
return true;
}
UserBehaviour direction = UserBehaviour.NONE;
float motionX = Math.abs(firstX - motionEvent.getRawX());
float motionY = Math.abs(firstY - motionEvent.getRawY());
if (motionX > directionOffset &&
motionX > directionOffset &&
lastX < firstX && lastY < firstY) {
if (motionX > motionY && lastX < firstX) {
direction = UserBehaviour.CANCELING;
} else if (motionY > motionX && lastY < firstY) {
direction = UserBehaviour.LOCKING;
}
} else if (motionX > motionY && motionX > directionOffset && lastX < firstX) {
direction = UserBehaviour.CANCELING;
} else if (motionY > motionX && motionY > directionOffset && lastY < firstY) {
direction = UserBehaviour.LOCKING;
}
if (direction == UserBehaviour.CANCELING) {
if (userBehaviour == UserBehaviour.NONE || motionEvent.getRawY() + imageViewAudio.getWidth() / 2 > firstY) {
userBehaviour = UserBehaviour.CANCELING;
}
if (userBehaviour == UserBehaviour.CANCELING) {
translateX(-(firstX - motionEvent.getRawX()));
}
} else if (direction == UserBehaviour.LOCKING) {
if (userBehaviour == UserBehaviour.NONE || motionEvent.getRawX() + imageViewAudio.getWidth() / 2 > firstX) {
userBehaviour = UserBehaviour.LOCKING;
}
if (userBehaviour == UserBehaviour.LOCKING) {
translateY(-(firstY - motionEvent.getRawY()));
}
}
lastX = motionEvent.getRawX();
lastY = motionEvent.getRawY();
}
view.onTouchEvent(motionEvent);
return true;
}
});
我使用@3llomi 提供的代码创建了一个 class,它只生成展开按钮而没有取消幻灯片动画。因为我想将我的按钮放在回收视图中,所以取消动画只会让东西过于拥挤。我的代码附带一个回调,在录制完成时传送存储在缓存中的音频文件 这些是必要的类和 xml:
public class RecordButton extends AppCompatImageView implements View.OnTouchListener{
private ScaleAnim scaleAnim;
private boolean listenForRecord = true;
private int commId;
private MediaRecorder recorder = null;
private boolean isRecording;
private static SoundPool soundPool = null;
private static int soundStart,soundEnd;
public RecordButton(Context context, int id) {
super(context);
init(context, null);
commId=id;
}
public RecordButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RecordButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecordButton);
int imageResource = typedArray.getResourceId(R.styleable.RecordButton_mic_icon, -1);
if (imageResource != -1) {
setTheImageResource(imageResource);
}
typedArray.recycle();
}
if (soundPool==null){
soundPool = new SoundPool.Builder()
.setMaxStreams(5)
.build();
//these are just two wav files with short intro and exit sounds
soundStart=soundPool.load(getContext(),R.raw.start_recording_sound,0);
soundEnd=soundPool.load(getContext(),R.raw.end_recording_sound,0);
}
scaleAnim = new ScaleAnim(this);
this.setOnTouchListener(this);
}
private void setTheImageResource(int imageResource) {
Drawable image = AppCompatResources.getDrawable(getContext(), imageResource);
setImageDrawable(image);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setClip(this);
}
public void setClip(View v) {
if (v.getParent() == null) {
return;
}
if (v instanceof ViewGroup) {
((ViewGroup) v).setClipChildren(false);
((ViewGroup) v).setClipToPadding(false);
}
if (v.getParent() instanceof View) {
setClip((View) v.getParent());
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isListenForRecord()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
((RecordButton) v).startScale();
soundPool.play(soundStart,1,1,0,0,1);
startRecording();
break;
case MotionEvent.ACTION_UP:
stopRecording();
soundPool.play(soundEnd,1,1,0,0,1);
((RecordButton) v).stopScale();
break;
}
}
return isListenForRecord();
}
File file;
//audio recording tools
private void startRecording() {
if (isRecording){
stopRecording();
}
String fileName=getContext().getExternalCacheDir().getAbsolutePath()+"/"+commId+"_"+new Date().getTime()+".amr";
file=new File(fileName);
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB);
recorder.setAudioSamplingRate(8000);
recorder.setAudioChannels(1);
recorder.setAudioEncodingBitRate(12000);
try {
recorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getContext(),fileName,Toast.LENGTH_LONG).show();
recorder.start();
setIsRecording(true);
}
private void stopRecording() {
if (isRecording) {
recorder.stop();
recorder.release();
setIsRecording(false);
recordingFinishedListener.onRecordingFinished(file);
recorder = null;
}
}
private void setIsRecording(boolean isRecording){
this.isRecording=isRecording;
}
protected void startScale() {
scaleAnim.start();
}
protected void stopScale() {
scaleAnim.stop();
}
public void setListenForRecord(boolean listenForRecord) {
this.listenForRecord = listenForRecord;
}
public boolean isListenForRecord() {
return listenForRecord;
}
//callback for when a recording has been made
public interface RecordingFinishedListener{
void onRecordingFinished(File file);
}
RecordingFinishedListener recordingFinishedListener;
public void setRecordingFinishedListener(RecordingFinishedListener recordingFinishedListener) {
this.recordingFinishedListener = recordingFinishedListener;
}
}
然后 class 负责动画,允许您定义扩展程度
public class ScaleAnim {
private View view;
public ScaleAnim(View view) {
this.view = view;
}
void start() {
AnimatorSet set = new AnimatorSet();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.3f);
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.3f);
set.setDuration(150);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.playTogether(scaleY, scaleX);
set.start();
}
void stop() {
AnimatorSet set = new AnimatorSet();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
// scaleY.setDuration(250);
// scaleY.setInterpolator(new DecelerateInterpolator());
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
// scaleX.setDuration(250);
// scaleX.setInterpolator(new DecelerateInterpolator());
set.setDuration(150);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.playTogether(scaleY, scaleX);
set.start();
}
}
和 attrs.xml 文件。其余的只是一个麦克风图标和一些你可以自己找到的声音
<resources>
<declare-styleable name="RecordButton">
<attr name="mic_icon" format="reference" />
</declare-styleable>
</resources>
通过在录音按钮上设置 RecordingFinishedListener,您可以继续处理录制的声音。