編輯:關於Android編程
了解Android控件的觸摸事件傳遞與處理對我們日常開發中自定義控件和觸摸事件沖突解決有重大意義。Android控件的觸摸事件傳遞和處理主要有以下幾個方法,下面一一介紹。
一、與觸摸事件有關的幾個方法
boolean dispatchTouchEvent(MotionEvent ev);
接收到觸摸事件時,是否分發事件到下面的View
返回true:分發觸摸事件
返回false:不分發,下面的View就拿不到觸摸事件
boolean onInterceptTouchEvent(MotionEvent ev);
接收到觸摸事件時,是否攔截事件
返回true:攔截,則調用onTouchEvent方法處理事件
返回false:不攔截,事件繼續往子View傳
boolean onTouchEvent(MotionEvent ev);
是否響應事件
返回true:響應
返回false:不響應
boolean onTouch(View v, MotionEvent event);
是否響應事件,當View調用了setOnTouchListener方法設置了觸摸監聽器,則事件響應的時候先調用onTouch方法
返回true:響應,則onTouchEvent方法不執行
返回false:不響應,並調用onTouchEvent方法
void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
請求父控件是否不攔截事件
返回true:不允許父控件的onInterceptTouchEvent調用
返回false:允許調用
二、擁有這些方法的類
父類
子類
擁有的方法
Activity
Activity
dispatchTouchEvent、onTouchEvent
ViewGroup
RelativeLayout, LinearLayout...
dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent、requestDisallowInterceptTouchEvent
View
Button、TextView...
dispatchTouchEvent、onTouchEvent
三、事件處理規則
觸摸事件是從Activity分發(只是分發,還沒有處理)到父控件,父控件先判斷是否攔截,如果不攔截事件,則繼續分發到子控件,然後一直往下分發。但處理就剛好相反,由子控件先處理事件,如果子控件沒有處理事件,則交給到父控件處理,一直往上處理,直到哪個控件處理了觸摸事件,就事件處理就到此結束。
1.當用戶觸摸屏幕的時候,從按下到移動,最後到抬起,會依次產生ACTION_DOWN、ACTION_MOVE、ACTION_UP三種觸摸事件,事件先傳到Activity,然後Activity調用分發事件方法dispatchTouchEvent,如果返回true,則事件就會傳給Activity的第一個父控件。
2.父控件拿到事件之後,也會調用分發事件方法dispatchTouchEvent,如果返回true,則繼續調用攔截方法onInterceptTouchEvent,如果返回true,則父控件攔截了事件,並調用父控件的onTouchEvent方法,下面的子控件就不會再響應onTouchEvent,onTouch的方法。
3.子控件拿到事件之後,先判斷是否設置了OnTouchListener, 如果設置了,則調用OnTouchListener的onTouch方法,如果返回true,事件已經處理到此結束,則跳過onTouchEvent方法,否則調用onTouchEvent方法,當onTouchEvent方法返回true,則事件處理到此結束,上面的父控件就不會再調用onTouchEvent方法。
4.如果某一個控件響應了ACTION_DOWN事件,則後續的ACTION_MOVE、ACTION_UP事件就會直接交給該控件處理,除非它的父控件攔截了後續的事件,但可以在處理ACTION_DOWN事件時,調用requestDisallowInterceptTouchEvent禁止父控件的攔截。如果控件沒有處理ACTION_DOWN事件,則後續的事件就不會再傳到該控件中,當下一次的ACTION_DOWN事件產生時,還是會傳給該View的。
四、下面來做一個演示
定義MainActivity、ParentView、ChildView,OnTouchListener
MainActivity——>媽媽
ParentView——>爸爸
ChildView——>我
OnTouchListener——>老婆
Event——>蘋果(一次來三個蘋果,模擬ACITON_DWON、ACTION_MOVE、ACTION_UP事件)
用一家人吃蘋果這個案例,模擬觸摸事件的處理。
媽媽MainActivity源碼:
package com.test.activity; import com.example.javawebtest.R; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.app.Activity; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub boolean eat = false; Log.i(getClass().getSimpleName(), "媽媽" + (eat ? "吃了蘋果" : "沒有吃,扔了")); return eat; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub Log.i(getClass().getSimpleName(), "媽媽想分給爸爸蘋果"); return super.dispatchTouchEvent(ev); } }
爸爸ParentView的源碼:
package com.test.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.RelativeLayout; public class ParentView extends RelativeLayout { public ParentView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override public boolean dispatchTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub Log.i(getClass().getSimpleName(), "爸爸想分給我蘋果"); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub boolean intercept = false; Log.i(getClass().getSimpleName(), "爸爸" + (intercept ? "想吃" : "不想吃") + "蘋果"); return intercept ? true : super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub boolean eat = false; Log.i(getClass().getSimpleName(), "爸爸" + (eat ? "吃了蘋果" : "沒有吃,給了媽媽")); return eat; } }
我ChildView、老婆OnTouchListener的源碼:
package com.test.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; public class ChildView extends View implements OnTouchListener { public ChildView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub setOnTouchListener(this); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub boolean eat = false; Log.i(getClass().getSimpleName(), "我" + (eat ? "吃了蘋果" : "沒有吃蘋果,給了爸爸")); return eat; } @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub boolean eat = false; Log.i(getClass().getSimpleName(), "老婆" + (eat ? "吃了蘋果" : "沒有吃蘋果,給了我")); return eat; } }
場景一:大家誰也沒吃蘋果,效果如下圖
剛開始,第一個蘋果一直往下傳,誰也沒吃,後面媽媽知道我們都不喜歡吃蘋果,第二、第三個蘋果都沒有傳給我們,就扔了...
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+IAogs6G+sLb+o7rO0rPUwcvGu7n7o6y9q0NoaWxkVmlld7XEb25Ub3VjaEV2ZW50tcRlYXTWw86qdHJ1ZTwvcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20141221/2014122109040324.png" alt="\">
我吃了蘋果,不過每次吃之前都要詢問老婆,要是老婆吃了,我就不能吃...
場景三:爸爸搶了蘋果,將onInterceptTouchEvent的intercept置為true
結果蘋果被老爸吃了,然後再沒有我的事情了...
Android官方入門文檔[13]暫停和恢復一個Activity活動 Pausing and Resuming an Activity 暫停和恢復一個Activity活
ROOT幾乎成了安卓手機發燒友不可不做的一道程序。常在河邊走,哪能不濕鞋。即使是老手,也能碰到root失敗的情況。那為什麼手機root失敗?刷機精靈root
學習目的: 1、掌握在Android中如何建立Gallery 2、初步理解Android適配器的原理 3、實現簡單的控件縮放動畫 簡介: 1、Gallery是Androi
前言android 自定義控件之ViewGroup生命周期執行步驟。了解ViewGroup的生命周期的執行步驟對於自己自定義ViewGroup的時候十分重要,清楚了整個流