最近要实现一个长按录音,松开手指结束录音的功能,在项目中,弄来弄去绕晕了,写个demo来梳理下。顺便研究下android事件调用机制。
先上效果界面:
布局:
- <RelativeLayout 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">
-
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/btn"
- android:layout_centerInParent="true"
- android:background="@drawable/microp_btn_normal" />
-
- </RelativeLayout>
代码:
- package com.example.androidtest;
-
- import android.os.Bundle;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.View.OnLongClickListener;
- import android.view.View.OnTouchListener;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.app.Activity;
- import android.app.Dialog;
- import android.content.Intent;
-
- public class MainActivity extends Activity {
-
- private Button btn;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- btn = (Button) findViewById(R.id.btn);
-
- btn.setOnTouchListener(new OnTouchListener() {
-
- @Override
- public boolean onTouch(View arg0, MotionEvent arg1) {
- Log.d("TAG", "onTouch is called.............");
- return false;
- }
- });
-
- btn.setOnLongClickListener(new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View arg0) {
- Log.d("TAG", "onLongClick is called.............");
- return false;
- }
- });
-
- btn.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Log.d("TAG", "onClick is called.............");
- }
- });
- }
-
-
- }
在代码中,我们监听了onTouch、onLongClick、onClick事件,其中onTouch和OnLongClick有返回值,onClick没有返回值。
现运行以上代码,长按按钮,我们可以看到调用顺序为
onTouch->onLongClick->onClick
现将OnTouch的返回值改为true,可发现onLongClick和onClick事件没有调用。说明onTouch返回true,后续事件没有传递。
接下来我们看下onTouch具体触发了哪些事件(只长按)
- btn.setOnTouchListener(new OnTouchListener() {
-
- @Override
- public boolean onTouch(View arg0, MotionEvent arg1) {
-
- switch (arg1.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Log.d("TAG", "ACTION_DOWN.............");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d("TAG", "ACTION_MOVE.............");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d("TAG", "ACTION_CANCEL.............");
- break;
- case MotionEvent.ACTION_UP:
- Log.d("TAG", "ACTION_UP.............");
- break;
- default:
- break;
- }
- return false;
- }
- });
看下日志截图
我只是按住,并未滑动。
我们将onLongClick返回true,可以预见,onClick事件不会被触发。但ACTION_UP呢?
经验证ACTION_UP被触发了。
接下来我们换下布局文件:
- <ScrollView 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">
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <View android:layout_width="match_parent"
- android:layout_height="1000dp"/>
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/btn"
- android:layout_gravity="center_horizontal"
- android:background="@drawable/microp_btn_normal" />
-
- </LinearLayout>
- </ScrollView>
意图很简单,让我们的按钮在滚动条的底部,日志截图
这时,我们的ACTION_UP没被触发,最后触发的是ACTION_CANCLE,而且我按了好几次才让它触发onLongClick事件,大多数只触发了DOWN/MOVE/CANCLE事件。
我怀疑是ScrollView滑动事件与onTouch事件冲突
在onTouch加上一句防冲突代码
- btn.setOnTouchListener(new OnTouchListener() {
-
- @Override
- public boolean onTouch(View arg0, MotionEvent arg1) {
-
- arg0.getParent().requestDisallowInterceptTouchEvent(true);
- switch (arg1.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Log.d("TAG", "ACTION_DOWN.............");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d("TAG", "ACTION_MOVE.............");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d("TAG", "ACTION_CANCEL.............");
- break;
- case MotionEvent.ACTION_UP:
- Log.d("TAG", "ACTION_UP.............");
-
- btn.setBackgroundResource(R.drawable.microp_btn_normal);
- break;
- default:
- break;
- }
- return false;
- }
- });
arg0.getParent().requestDisallowInterceptTouchEvent(true);//通知父控件勿拦截本控件touch事件
这样我们就和我们预期一样。
总结:
因为我的长按录制音频在ScrollView中,没有做onTouch冲突处理,所以出现很多莫名其妙的问题。
现在要实现我们的要求,只要在onLongClick中录制,ACTION_UP结束即可。
demo下载:http://download.csdn.net/detail/msl0903/7224487
如果实在解决不了,直接不处理控件的
OnClick事件,直接在onTouch的抬起事件(
MotionEvent.
ACTION_UP
)中加上你想做的事情就可以了!
pickPictureImage.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("lzx", "taskPicImage onTouch ");
/*arg0.getParent().requestDisallowInterceptTouchEvent(true);//通知父控件勿拦截本控件touch事件
arg0.performClick();*/
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
Log.d("lzx", "ACTION_UP.............");
mHandler.sendEmptyMessage(PerformTasdkActivity.PICK_PIC_FROM_PHOTO);
break;
default:
break;
}
return false;
}
});