Android onTouch、OnLongClick、onClick及ScrollView滑動事件衝突
最近要實現一個長按錄音,鬆開手指結束錄音的功能,在專案中,弄來弄去繞暈了,寫個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) { //Log.d("TAG", "onTouch is called............."); 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) {
//Log.d("TAG", "onTouch is called.............");
arg0.getParent().requestDisallowInterceptTouchEvent(true);//通知父控制元件勿攔截本控制元件touch事件
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