您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Android如何擴大View的點擊區域”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Android如何擴大View的點擊區域”這篇文章吧。
為了更清楚的說明整個機制,采用如下的視圖來說明點擊的事件分發機制。下圖是一個 FrameLayout (ViewGroup) 里面包含著一個 ImageView (View)。
先自定義一個 MyFrameLayout,繼承FrameLayout,并實現兩個點擊相關的接口;具體代碼如下:
public class MyFrameLayout extends FrameLayout implements OnClickListener, OnTouchListener { private static final String TAG = "Event"; public MyFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); Log.d(TAG, "MyFrameLayout init"); setOnClickListener(this); setOnTouchListener(this); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d(TAG, "MyFrameLayout dispatchTouchEvent " + event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d(TAG, "MyFrameLayout onTouchEvent " + event.getAction() ); return super.onTouchEvent(event); } @Override public void onClick(View view) { Log.d(TAG, "MyFrameLayout onClick"); } @Override public boolean onTouch(View view, MotionEvent event) { Log.d(TAG, "MyFrameLayout onTouch " + event.getAction()); return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.d(TAG, "MyFrameLayout onInterceptTouchEvent " + ev.getAction()); return super.onInterceptTouchEvent(ev); } }
接著,對于 ImageView 也做類似的操作,具體代碼如下:
public class MyImageView extends ImageView implements OnClickListener, OnTouchListener { private static final String TAG = "Event"; public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); Log.d(TAG, "MyImageView init"); setOnClickListener(this); setOnTouchListener(this); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d(TAG, "MyImageView dispatchTouchEvent "+ event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d(TAG, "MyImageView onTouchEvent "+ event.getAction()); return super.onTouchEvent(event); } @Override public boolean onTouch(View arg0, MotionEvent arg1) { Log.d(TAG, "MyImageView onTouch " + arg1.getAction()); return false; } @Override public void onClick(View arg0) { Log.d(TAG, "MyImageView onClick"); } }
這里要說明的是,只有ViewGroup才有 onInterceptTouchEvent 方法的,普通的 View 是沒有的,它是不能對事件進行攔截的。
那這時候,如果我們點擊里面的 ImageView,會有怎樣的輸出呢?結果如下圖。
那如果點擊外層呢?
0,1,2分別是代表 ACTION_DOWN,ACTION_UP,ACTION_MOVE;從中也可以看出一個點擊動作包含一個Down,一個Up,還有多個Move操作。
再來看一段源碼:
public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume = false; if(onInterceptTouchEvent(ev)){ consume = onTouchEvent(ev); } else{ consume = child.dispatchTouchEvent(ev); } return consume; }
上述的代碼把三者的關系說得很清楚了,對于一個對于一個 ViewGroup 來說,點擊事件產生后,首先會傳遞給它,這時候會調用 dispatchTouchEvent,如果這個 ViewGroup 的 onInterceptTouchEvent 返回 true ,則表示它要攔截該事件,也就會交給它的 onTouchEvent 來進行處理。如果這個 ViewGroup 的 onInterceptTouchEvent 返回 false 則會傳給子元素,子元素的 dispatchTouchEvent 就會被調用,如此反復循環。這與上面一張圖打出的結果是一致的。
這里還有說明的是,如果代碼設置了 OnTouchListener,那么就會先調用 onTouch 方法,然后在調用 onTouchEvent。OnClickListener 是優先級最低的,所以最后才會調用 onClick。
因此,從第二張結果圖也可以看出,當存在 onTouch 之后,onTouchEvent 和 onClick 兩個方法都不會在調用了。
相信到這里,大家對于View的事件分發機制有一定的了解了。
這里回到開頭提的那個問題,那么有什么辦法可以擴大 View 的點擊區域呢?
答案:在父 View 設置 OnTouchListener 對點擊事件進行攔截,通過判斷點擊的位置,來決定是相應子 View 的事件,還是父 View 的事件。
具體實現代碼如下:
public class TouchFactory { /** 擴展垂直方向點擊區域尺寸 */ private static final int EXT_V_SIZE = 200; public static View.OnTouchListener creatTouchListener(){ return new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (expendTouchSize(v, event)) { return true; } return false; } }; } public static boolean expendTouchSize(View root, MotionEvent event) { if (root instanceof MyFrameLayout) { ImageView view = ((MyFrameLayout) root).getMyImageView(); if (view != null && view.getVisibility() == View.VISIBLE) { Rect touchRect = new Rect(); view.getGlobalVisibleRect(touchRect); int action = event.getAction(); float x = event.getRawX(); float y = event.getRawY(); if ((y >= touchRect.top - EXT_V_SIZE) && (y <= touchRect.bottom + EXT_V_SIZE)) { if (x >= touchRect.left) { if (action == MotionEvent.ACTION_UP) { Toast.makeText(view.getContext(), "touch", Toast.LENGTH_SHORT).show(); } return true; } } } } return false; } }
TouchFactory 對點擊事件進行了封裝,并通過對點擊區域的判斷,來決定要不要攔截點擊事件。
下面是 MyFrameLayout 的具體實現。由于是一個自定義 view, 因此,變量 myImageView 是一定為空的,所以要對其進行賦值。
public class MyFrameLayout extends FrameLayout { private static final String TAG = "Event"; private MyImageView myImageView; public MyFrameLayout(Context context) { this(context, null); } public MyFrameLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyFrameLayout(Context context, AttributeSet attrs, int def) { super(context, attrs, def); init(); } public void init() { this.setOnTouchListener(TouchFactory.creatTouchListener()); } public MyImageView getMyImageView() { if (myImageView == null) { myImageView = findViewById(R.id.mImage); } return myImageView; } }
注意事項: 當對子 View 設置 OnClickListener,點擊區域剛好是子 View 內部的時候,就會消耗此事見,父 View 的攔截處理就無效了,因此,一旦選擇攔截來擴大點擊區域,就不要再去子 View 設置點擊回調來消耗點擊事件了。
以上是“Android如何擴大View的點擊區域”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。