最近要实现一个长按录音,松开手指结束录音的功能,在项目中,弄来弄去绕晕了,写个demo来梳理下。顺便研究下android事件调用机制。


Android onTouch、OnLongClick、onClick及ScrollView滑动事件冲突_控件

布局:


[html]  ​​view plain​​​ ​​​copy​​​ ​​​​​​ ​​​​



  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">

  5. <Button
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"
  8. android:id="@+id/btn"
  9. android:layout_centerInParent="true"
  10. android:background="@drawable/microp_btn_normal" />

  11. </RelativeLayout>



代码:



[java]  ​​view plain​​​ ​​​copy​​​ ​​​​​​ ​​​​



  1. package com.example.androidtest;

  2. import android.os.Bundle;
  3. import android.util.Log;
  4. import android.view.LayoutInflater;
  5. import android.view.MotionEvent;
  6. import android.view.View;
  7. import android.view.View.OnClickListener;
  8. import android.view.View.OnLongClickListener;
  9. import android.view.View.OnTouchListener;
  10. import android.widget.Button;
  11. import android.widget.ImageView;
  12. import android.app.Activity;
  13. import android.app.Dialog;
  14. import android.content.Intent;

  15. public class MainActivity extends Activity {

  16. private Button btn;
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. btn = (Button) findViewById(R.id.btn);

  22. new OnTouchListener() {

  23. @Override
  24. public boolean onTouch(View arg0, MotionEvent arg1) {
  25. "TAG", "onTouch is called.............");
  26. return false;
  27. }
  28. });

  29. new OnLongClickListener() {

  30. @Override
  31. public boolean onLongClick(View arg0) {
  32. "TAG", "onLongClick is called.............");
  33. return false;
  34. }
  35. });

  36. new OnClickListener() {

  37. @Override
  38. public void onClick(View v) {
  39. "TAG", "onClick is called.............");
  40. }
  41. });
  42. }


  43. }



在代码中,我们监听了onTouch、onLongClick、onClick事件,其中onTouch和OnLongClick有返回值,onClick没有返回值。

现运行以上代码,长按按钮,我们可以看到调用顺序为

onTouch->onLongClick->onClick


现将OnTouch的返回值改为true,可发现onLongClick和onClick事件没有调用。说明onTouch返回true,后续事件没有传递。

接下来我们看下onTouch具体触发了哪些事件(只长按)


[java]  ​​view plain​​​ ​​​copy​​​ ​​​​​​ ​​​​



  1. btn.setOnTouchListener(new OnTouchListener() {

  2. @Override
  3. public boolean onTouch(View arg0, MotionEvent arg1) {
  4. //Log.d("TAG", "onTouch is called.............");
  5. switch (arg1.getAction()) {
  6. case MotionEvent.ACTION_DOWN:
  7. "TAG", "ACTION_DOWN.............");
  8. break;
  9. case MotionEvent.ACTION_MOVE:
  10. "TAG", "ACTION_MOVE.............");
  11. break;
  12. case MotionEvent.ACTION_CANCEL:
  13. "TAG", "ACTION_CANCEL.............");
  14. break;
  15. case MotionEvent.ACTION_UP:
  16. "TAG", "ACTION_UP.............");
  17. break;
  18. default:
  19. break;
  20. }
  21. return false;
  22. }
  23. });



看下日志截图

Android onTouch、OnLongClick、onClick及ScrollView滑动事件冲突_ide_02


我只是按住,并未滑动。

我们将onLongClick返回true,可以预见,onClick事件不会被触发。但ACTION_UP呢?

经验证ACTION_UP被触发了。


接下来我们换下布局文件:


[html]  ​​view plain​​​ ​​​copy​​​ ​​​​​​ ​​​​



  1. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <LinearLayout android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical">
  8. <View android:layout_width="match_parent"
  9. android:layout_height="1000dp"/>
  10. <Button
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"
  13. android:id="@+id/btn"
  14. android:layout_gravity="center_horizontal"
  15. android:background="@drawable/microp_btn_normal" />

  16. </LinearLayout>
  17. </ScrollView>



意图很简单,让我们的按钮在滚动条的底部,日志截图


Android onTouch、OnLongClick、onClick及ScrollView滑动事件冲突_控件_03

这时,我们的ACTION_UP没被触发,最后触发的是ACTION_CANCLE,而且我按了好几次才让它触发onLongClick事件,大多数只触发了DOWN/MOVE/CANCLE事件。

我怀疑是ScrollView滑动事件与onTouch事件冲突

在onTouch加上一句防冲突代码


[java]  ​​view plain​​​ ​​​copy​​​ ​​​​​​ ​​​​



  1. btn.setOnTouchListener(new OnTouchListener() {

  2. @Override
  3. public boolean onTouch(View arg0, MotionEvent arg1) {
  4. //Log.d("TAG", "onTouch is called.............");
  5. true);//通知父控件勿拦截本控件touch事件
  6. switch (arg1.getAction()) {
  7. case MotionEvent.ACTION_DOWN:
  8. "TAG", "ACTION_DOWN.............");
  9. break;
  10. case MotionEvent.ACTION_MOVE:
  11. "TAG", "ACTION_MOVE.............");
  12. break;
  13. case MotionEvent.ACTION_CANCEL:
  14. "TAG", "ACTION_CANCEL.............");
  15. break;
  16. case MotionEvent.ACTION_UP:
  17. "TAG", "ACTION_UP.............");

  18. btn.setBackgroundResource(R.drawable.microp_btn_normal);
  19. break;
  20. default:
  21. break;
  22. }
  23. return false;
  24. }
  25. });


arg0.getParent().requestDisallowInterceptTouchEvent(true);//通知父控件勿拦截本控件touch事件

这样我们就和我们预期一样。

总结:

因为我的长按录制音频在ScrollView中,没有做onTouch冲突处理,所以出现很多莫名其妙的问题。

现在要实现我们的要求,只要在onLongClick中录制,ACTION_UP结束即可。

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