Android 触屏事件 OnTouch onClick onTouchEvent对于触屏事件的处理和分发
Android 触屏事件 OnTouch onClick onTouchEvent对于触屏事件的处理和分发
<FrameLayout 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" android:background="#FFFFFF"> <com.example.empty.MyFrameLayout android:id="@+id/mFrame" android:layout_width="300dp" android:layout_gravity="center" android:layout_height="300dp" android:background="#00FFFF" > <com.example.empty.MyImageView android:id="@+id/mImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/image_128" android:background="#00FF00" android:layout_gravity="center" /> </com.example.empty.MyFrameLayout> </FrameLayout>
package com.example.empty; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.MotionEvent; import android.widget.FrameLayout; public class MyFrameLayout extends FrameLayout implements OnClickListener,OnTouchListener{ private static final String TAG = "Event"; public MyFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub Log.d(TAG,"MyFrameLayout init"); setOnClickListener(this); setOnTouchListener(this); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d(TAG,"MyFrameLayout dispatchTouchEvent"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d(TAG,"MyFrameLayout onTouchEvent"); return super.onTouchEvent(event); } @Override public void onClick(View view) { // TODO Auto-generated method stub Log.d(TAG,"MyFrameLayout onClick"); } @Override public boolean onTouch(View view, MotionEvent event) { // TODO Auto-generated method stub Log.d(TAG,"MyFrameLayout onTouch"); return false; } }
package com.example.empty; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.ImageView; public class MyImageView extends ImageView implements OnClickListener,OnTouchListener{ private static final String TAG = "Event"; public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub Log.d(TAG,"MyImageView init"); setOnClickListener(this); setOnTouchListener(this); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d(TAG,"MyImageView dispatchTouchEvent"); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d(TAG,"MyImageView onTouchEvent"); return super.onTouchEvent(event); } @Override public boolean onTouch(View arg0, MotionEvent arg1) { // TODO Auto-generated method stub Log.d(TAG,"MyImageView onTouch"); return false; } @Override public void onClick(View arg0) { // TODO Auto-generated method stub Log.d(TAG,"MyImageView onClick"); } }
例子很简单,下面我们让Log来告诉我们一些东西
public abstract class ViewGroup extends View
所以从底层来看我们的所有事件最终都是交给我们的View
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { ...... public interface OnClickListener { /** * Called when a view has been clicked. * * @param v The view that was clicked. */ void onClick(View v); } ...... public interface OnTouchListener { /** * Called when a touch event is dispatched to a view. This allows listeners to * get a chance to respond before the target view. * * @param v The view the touch event has been dispatched to. * @param event The MotionEvent object containing full information about * the event. * @return True if the listener has consumed the event, false otherwise. */ boolean onTouch(View v, MotionEvent event); } ...... public boolean dispatchTouchEvent(MotionEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } if (DBG_MOTION) { Xlog.d(VIEW_LOG_TAG, "(View)dispatchTouchEvent: event = " + event + ",this = " + this); } if (onFilterTouchEventForSecurity(event)) { //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { return true; } if (onTouchEvent(event)) { return true; } } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } return false; } /** * Filter the touch event to apply security policies. * * @param event The motion event to be filtered. * @return True if the event should be dispatched, false if the event should be dropped. * * @see #getFilterTouchesWhenObscured */ public boolean onFilterTouchEventForSecurity(MotionEvent event) { //noinspection RedundantIfStatement if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { // Window is obscured, drop this touch. return false; } return true; } ..... public boolean onTouchEvent(MotionEvent event) { final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { /// M: we need to reset the pressed state or remove prepressed callback either up or cancel event happens. final int action = event.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if ((mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } else if ((mPrivateFlags & PFLAG_PREPRESSED) != 0) { Xlog.d(VIEW_LOG_TAG, "View onTouch event, if view is DISABLED & PFLAG_PREPRESSED, remove callback mPrivateFlags = " + mPrivateFlags + ", this = " + this); removeTapCallback(); } } // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; if (DBG_MOTION) { Xlog.d(VIEW_LOG_TAG, "(View)Touch up: prepressed = " + prepressed + ",this = " + this); } if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { // take focus if we don't have it already and we should in // touch mode. boolean focusTaken = false; if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { focusTaken = requestFocus(); } if (prepressed) { // The button is being released before we actually // showed it as pressed. Make it show the pressed // state now (before scheduling the click) to ensure // the user sees it. setPressed(true); } if (!mHasPerformedLongPress) { // This is a tap, so remove the longpress check removeLongPressCallback(); // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } } if (mUnsetPressedState == null) { mUnsetPressedState = new UnsetPressedState(); } if (prepressed) { postDelayed(mUnsetPressedState, ViewConfiguration.getPressedStateDuration()); } else if (!post(mUnsetPressedState)) { // If the post failed, unpress right now mUnsetPressedState.run(); } removeTapCallback(); } break; case MotionEvent.ACTION_DOWN: mHasPerformedLongPress = false; if (performButtonActionOnTouchDown(event)) { break; } // Walk up the hierarchy to determine if we're inside a scrolling container. boolean isInScrollingContainer = isInScrollingContainer(); if (DBG_MOTION) { Xlog.d(VIEW_LOG_TAG, "(View)Touch down: isInScrollingContainer = " + isInScrollingContainer + ",this = " + this); } // For views inside a scrolling container, delay the pressed feedback for // a short period in case this is a scroll. if (isInScrollingContainer) { mPrivateFlags |= PFLAG_PREPRESSED; if (mPendingCheckForTap == null) { mPendingCheckForTap = new CheckForTap(); } postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); } else { // Not inside a scrolling container, so show the feedback right away setPressed(true); checkForLongClick(0); } break; case MotionEvent.ACTION_CANCEL: if (DBG_MOTION) { Xlog.d(VIEW_LOG_TAG, "(View)Touch cancel: this = " + this); } setPressed(false); removeTapCallback(); removeLongPressCallback(); break; case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); if (DBG_MOTION) { Xlog.d(VIEW_LOG_TAG, "(View)Touch move: x = " + x + ",y = " + y + ",mTouchSlop = " + mTouchSlop + ",this = " + this); } // Be lenient about moving outside of buttons if (!pointInView(x, y, mTouchSlop)) { // Outside button removeTapCallback(); if ((mPrivateFlags & PFLAG_PRESSED) != 0) { // Remove any future long press/tap checks removeLongPressCallback(); setPressed(false); } } break; } return true; } return false; } }
public boolean dispatchTouchEvent(MotionEvent event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } if (DBG_MOTION) { Xlog.d(VIEW_LOG_TAG, "(View)dispatchTouchEvent: event = " + event + ",this = " + this); } if (onFilterTouchEventForSecurity(event)) { //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { return true; } if (onTouchEvent(event)) { return true; } } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } return false; } /** * Filter the touch event to apply security policies. * * @param event The motion event to be filtered. * @return True if the event should be dispatched, false if the event should be dropped. * * @see #getFilterTouchesWhenObscured */ public boolean onFilterTouchEventForSecurity(MotionEvent event) { //noinspection RedundantIfStatement if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { // Window is obscured, drop this touch. return false; } return true; }这里重点说明一下onFilterTouchEventForSecurity这个函数
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。