Android中的Touch事件处理

主要内容

  Activity或View类的onTouchEvent()回调函数会接收到touch事件。

  一个完整的手势是从ACTION_DOWN开始,到ACTION_UP结束。

  简单的情况下,我们只需要在onTouchEvent()中写个switch case语句,处理各种事件(Touch Down、 Touch Move、 Touch Up等),但是比较复杂的动作就需要更多的处理了。

  ViewGroup作为一个parent是可以截获传向它的child的touch事件的。

  如果一个ViewGroup的onInterceptTouchEvent()方法返回true,说明Touch事件被截获,子View不再接收到Touch事件,而是转向本ViewGroup的 onTouchEvent()方法处理。从Down开始,之后的Move,Up都会直接在onTouchEvent()方法中处理。

  先前还在处理touch event的child view将会接收到一个 ACTION_CANCEL

  如果onInterceptTouchEvent()返回false,则事件会交给child view处理。

  Android中提供了ViewGroup、View、Activity三个层次的Touch事件处理。

  处理过程是按照Touch事件从上到下传递,再按照是否消费的返回值,从下到上返回,即如果View的onTouchEvent返回false,将会向上传给它的parent的ViewGroup,如果ViewGroup不处理,将会一直向上返回到Activity。

  即隧道式向下分发,然后冒泡式向上处理

Activity的Touch事件分发

  Activity的dispatchTouchEvent (MotionEvent ev):

    /*** Called to process touch screen events.  You can override this to* intercept all touch screen events before they are dispatched to the* window.  Be sure to call this implementation for touch screen events* that should be handled normally.** @param ev The touch screen event.** @return boolean Return true if this event was consumed.*/public boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {onUserInteraction();}if (getWindow().superDispatchTouchEvent(ev)) {return true;}return onTouchEvent(ev);}

  处理屏幕触摸事件,你可以覆写这个方法来截获所有的触摸屏幕事件,是在它们分发到窗口之前截获。

  对于要正常处理的触摸屏幕事件,要确认调用这个实现。

  返回值为true的时候,表明这个事件被消费。

  Activity的onTouchEvent (MotionEvent event):

  

  

    /*** Called when a touch screen event was not handled by any of the views* under it.  This is most useful to process touch events that happen* outside of your window bounds, where there is no view to receive it.** @param event The touch screen event being processed.** @return Return true if you have consumed the event, false if you haven't.* The default implementation always returns false.*/public boolean onTouchEvent(MotionEvent event) {if (mWindow.shouldCloseOnTouch(this, event)) {finish();return true;}return false;}

  如果一个屏幕触摸事件没有被这个Activity下的任何View所处理,Activity的onTouchEvent将会调用。

  这对于处理window边界之外的Touch事件非常有用,因为通常是没有View会接收到它们的。

  返回值为true表明你已经消费了这个事件,false则表示没有消费,默认实现中返回false。

View的Touch事件

  View的dispatchTouchEvent (MotionEvent event):

    /*** Pass the touch screen motion event down to the target view, or this* view if it is the target.** @param event The motion event to be dispatched.* @return True if the event was handled by the view, false otherwise.*/public boolean dispatchTouchEvent(MotionEvent event) {if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);}if (onFilterTouchEventForSecurity(event)) {//noinspection SimplifiableIfStatementListenerInfo 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;}

View --> dispatchTouchEvent

  将touch屏幕的事件向下传递到目标View,或者传递到本View,如果它就是目标View。

  如果事件被这个View处理,则返回true,否则返回false。

  onTouchEvent (MotionEvent event):

 /*** Implement this method to handle touch screen motion events.** @param event The motion event.* @return True if the event was handled, false otherwise.*/public boolean onTouchEvent(MotionEvent event) {final int viewFlags = mViewFlags;if ((viewFlags & ENABLED_MASK) == DISABLED) {if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {setPressed(false);}// 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 ((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 stateif (!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();// 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 awaysetPressed(true);checkForLongClick(0);}break;case MotionEvent.ACTION_CANCEL:setPressed(false);removeTapCallback();removeLongPressCallback();break;case MotionEvent.ACTION_MOVE:final int x = (int) event.getX();final int y = (int) event.getY();// Be lenient about moving outside of buttonsif (!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;}

View --> onTouchEvent

  实现这个方法来处理touch屏幕的事件。

  返回true如果这个事件被处理了。

ViewGroup的Touch事件

  因为ViewGroup是View的子类,所以它覆写方法时会加上Override注解,如果没有覆写,则沿用父类实现,如onTouchEvent()。

  dispatchTouchEvent (MotionEvent ev): 

/*** {@inheritDoc}*/@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(ev, 1);}boolean handled = false;if (onFilterTouchEventForSecurity(ev)) {final int action = ev.getAction();final int actionMasked = action & MotionEvent.ACTION_MASK;// Handle an initial down.if (actionMasked == MotionEvent.ACTION_DOWN) {// Throw away all previous state when starting a new touch gesture.// The framework may have dropped the up or cancel event for the previous gesture// due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);resetTouchState();}// Check for interception.final boolean intercepted;if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;if (!disallowIntercept) {intercepted = onInterceptTouchEvent(ev);ev.setAction(action); // restore action in case it was changed} else {intercepted = false;}} else {// There are no touch targets and this action is not an initial down// so this view group continues to intercept touches.intercepted = true;}// Check for cancelation.final boolean canceled = resetCancelNextUpFlag(this)|| actionMasked == MotionEvent.ACTION_CANCEL;// Update list of touch targets for pointer down, if needed.final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;TouchTarget newTouchTarget = null;boolean alreadyDispatchedToNewTouchTarget = false;if (!canceled && !intercepted) {if (actionMasked == MotionEvent.ACTION_DOWN|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {final int actionIndex = ev.getActionIndex(); // always 0 for downfinal int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex): TouchTarget.ALL_POINTER_IDS;// Clean up earlier touch targets for this pointer id in case they// have become out of sync.
                    removePointersFromTouchTargets(idBitsToAssign);final int childrenCount = mChildrenCount;if (newTouchTarget == null && childrenCount != 0) {final float x = ev.getX(actionIndex);final float y = ev.getY(actionIndex);// Find a child that can receive the event.// Scan children from front to back.final View[] children = mChildren;final boolean customOrder = isChildrenDrawingOrderEnabled();for (int i = childrenCount - 1; i >= 0; i--) {final int childIndex = customOrder ?getChildDrawingOrder(childrenCount, i) : i;final View child = children[childIndex];if (!canViewReceivePointerEvents(child)|| !isTransformedTouchPointInView(x, y, child, null)) {continue;}newTouchTarget = getTouchTarget(child);if (newTouchTarget != null) {// Child is already receiving touch within its bounds.// Give it the new pointer in addition to the ones it is handling.newTouchTarget.pointerIdBits |= idBitsToAssign;break;}resetCancelNextUpFlag(child);if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {// Child wants to receive touch within its bounds.mLastTouchDownTime = ev.getDownTime();mLastTouchDownIndex = childIndex;mLastTouchDownX = ev.getX();mLastTouchDownY = ev.getY();newTouchTarget = addTouchTarget(child, idBitsToAssign);alreadyDispatchedToNewTouchTarget = true;break;}}}if (newTouchTarget == null && mFirstTouchTarget != null) {// Did not find a child to receive the event.// Assign the pointer to the least recently added target.newTouchTarget = mFirstTouchTarget;while (newTouchTarget.next != null) {newTouchTarget = newTouchTarget.next;}newTouchTarget.pointerIdBits |= idBitsToAssign;}}}// Dispatch to touch targets.if (mFirstTouchTarget == null) {// No touch targets so treat this as an ordinary view.handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);} else {// Dispatch to touch targets, excluding the new touch target if we already// dispatched to it.  Cancel touch targets if necessary.TouchTarget predecessor = null;TouchTarget target = mFirstTouchTarget;while (target != null) {final TouchTarget next = target.next;if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {handled = true;} else {final boolean cancelChild = resetCancelNextUpFlag(target.child)|| intercepted;if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {handled = true;}if (cancelChild) {if (predecessor == null) {mFirstTouchTarget = next;} else {predecessor.next = next;}target.recycle();target = next;continue;}}predecessor = target;target = next;}}// Update list of touch targets for pointer up or cancel, if needed.if (canceled|| actionMasked == MotionEvent.ACTION_UP|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {resetTouchState();} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {final int actionIndex = ev.getActionIndex();final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);removePointersFromTouchTargets(idBitsToRemove);}}if (!handled && mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);}return handled;}

ViewGroup --> dispatchTouchEvent

  将Touch事件向下传递到目标View,因为自身也是View,所以目标View如果是自己,则传递给自己。

  返回true,如果这个事件是被本View所处理。

  onInterceptTouchEvent (MotionEvent ev)

  ViewGroup中比较特殊的一个方法。默认实现如下:

    public boolean onInterceptTouchEvent(MotionEvent ev) {return false;}

  这个方法注释很长:

    /*** Implement this method to intercept all touch screen motion events.  This* allows you to watch events as they are dispatched to your children, and* take ownership of the current gesture at any point.** <p>Using this function takes some care, as it has a fairly complicated* interaction with {@link View#onTouchEvent(MotionEvent)* View.onTouchEvent(MotionEvent)}, and using it requires implementing* that method as well as this one in the correct way.  Events will be* received in the following order:** <ol>* <li> You will receive the down event here.* <li> The down event will be handled either by a child of this view* group, or given to your own onTouchEvent() method to handle; this means* you should implement onTouchEvent() to return true, so you will* continue to see the rest of the gesture (instead of looking for* a parent view to handle it).  Also, by returning true from* onTouchEvent(), you will not receive any following* events in onInterceptTouchEvent() and all touch processing must* happen in onTouchEvent() like normal.* <li> For as long as you return false from this function, each following* event (up to and including the final up) will be delivered first here* and then to the target's onTouchEvent().* <li> If you return true from here, you will not receive any* following events: the target view will receive the same event but* with the action {@link MotionEvent#ACTION_CANCEL}, and all further* events will be delivered to your onTouchEvent() method and no longer* appear here.* </ol>** @param ev The motion event being dispatched down the hierarchy.* @return Return true to steal motion events from the children and have* them dispatched to this ViewGroup through onTouchEvent().* The current target will receive an ACTION_CANCEL event, and no further* messages will be delivered here.*/

ViewGroup onInterceptTouchEvent

  实现这个方法可以截获所有的Touch事件。这样你就可以控制向child分发的Touch事件。

  一般实现这个方法,需要同时实现View.onTouchEvent(MotionEvent)方法。

  事件是按照如下的顺序被接收的:

  1.首先在onInterceptTouchEvent()中接收到Down事件。

  2.Down事件将会:要么给这个ViewGroup的一个child view处理,要么是这个ViewGroup自己的onTouchEvent()处理。

  处理意味着你应该在onTouchEvent()的实现中返回true,这样你就可以继续看到这个gesture的其他部分,如果返回false,将会返回寻找一个parent view去处理它。

  如果在onTouchEvent()中返回true,你将不会再在onInterceptTouchEvent()再收到接下来的事件,所有的Touch处理必须放在onTouchEvent()中正常处理。

  3.如果你在onInterceptTouchEvent()中返回false,接下来的每一个事件都会先传到onInterceptTouchEvent(),之后传递到目标view的onTouchEvent()中。

  4.如果你在onInterceptTouchEvent()中返回true,将不会再接收到手势中的其他事件,当前的目标view将会接收到同一个事件,但是动作是 ACTION_CANCEL。其他所有的事件将会被直接传递到onTouchEvent()中,并且不再在onInterceptTouchEvent()中出现。

  

  onInterceptTouchEvent()的返回值:true将会从子view中偷取运动事件,把它们分配到这个ViewGroup的onTouchEvent()中,当前目标view将会接收到取消动作,并且接下来的动作都不会再经过onInterceptTouchEvent()。

  ViewGroup的onTouchEvent()是采用父类View的默认实现,有需要的话可以覆写。

代码示例

  写了一个Demo观察输出和调用关系,代码如下:

package com.mengdd.hellotouch;import android.util.Log;
import android.view.MotionEvent;public class Utils {public static void showMotionEventType(MotionEvent event, String logTag,String methodName) {final int action = event.getActionMasked();switch (action) {case MotionEvent.ACTION_DOWN:Log.i(logTag, methodName + ": " + action + ": ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:Log.i(logTag, methodName + ": " + action + ": ACTION_MOVE");break;case MotionEvent.ACTION_UP:Log.i(logTag, methodName + ": " + action + ": ACTION_UP");break;case MotionEvent.ACTION_CANCEL:Log.i(logTag, methodName + ": " + action + ": ACTION_CANCEL");break;default:break;}}public static void showReturnValue(boolean returnValue, String logTag,String methodName) {Log.w(logTag, methodName + " return: " + returnValue);}public static void showInfo(String info, String logTag, String methodName) {Log.e(logTag, methodName + " info: " + info);}
}

Utils

package com.mengdd.hellotouch;import com.example.helloscroller.R;import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;public class HelloTouchActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_hello_scroller);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {Utils.showMotionEventType(ev, "Activity", "dispatchTouchEvent");boolean result = super.dispatchTouchEvent(ev);Utils.showReturnValue(result, "Activity", "dispatchTouchEvent");return result;}@Overridepublic boolean onTouchEvent(MotionEvent event) {Utils.showMotionEventType(event, "Activity", "onTouchEvent");boolean result = super.onTouchEvent(event);Utils.showReturnValue(result, "Activity", "onTouchEvent");return result;}}

Activity

package com.mengdd.hellotouch;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;public class MyViewGroup extends LinearLayout {public MyViewGroup(Context context, AttributeSet attrs) {super(context, attrs);init();}public MyViewGroup(Context context) {super(context);init();}private void init() {setOnClickListener(mOnClickListener);setOnLongClickListener(mOnLongClickListener);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {Utils.showMotionEventType(event, "ViewGroup", "onInterceptTouchEvent");boolean returnValue = super.onInterceptTouchEvent(event);// This method JUST determines whether we want to intercept the motion.// If we return true, onTouchEvent will be called
Utils.showReturnValue(returnValue, "ViewGroup", "onInterceptTouchEvent");return returnValue;}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {Utils.showMotionEventType(event, "ViewGroup", "dispatchTouchEvent");boolean returnValue = super.dispatchTouchEvent(event);Utils.showReturnValue(returnValue, "ViewGroup", "dispatchTouchEvent");return returnValue;}// ViewGroup自己的Touch事件处理,如果在onInterceptTouchEvent返回true,则会到这里处理,不传入child
    @Overridepublic boolean onTouchEvent(MotionEvent event) {Utils.showMotionEventType(event, "ViewGroup", "onTouchEvent");boolean returnValue = super.onTouchEvent(event);Utils.showReturnValue(returnValue, "ViewGroup", "onTouchEvent");return returnValue;}private OnClickListener mOnClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {Utils.showInfo("onClick", "ViewGroup", "mOnClickListener");// onClick是ACTION_UP后调用的
}};private OnLongClickListener mOnLongClickListener = new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {// onLongClick按下到一定的时间就调用了Utils.showInfo("onLongClick", "ViewGroup", "mOnLongClickListener");// 如果返回false,则长按结束的ACTION_UP调用onClick// 如果返回true,onLongClick后不再调用onClickreturn true;}};}

ViewGroup

package com.mengdd.hellotouch;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;public class MyView extends TextView {public MyView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}public MyView(Context context, AttributeSet attrs) {super(context, attrs);init();}public MyView(Context context) {super(context);}private void init() {setOnClickListener(mOnClickListener);setOnLongClickListener(mOnLongClickListener);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {Utils.showMotionEventType(event, "View", "dispatchTouchEvent");boolean returnValue = super.dispatchTouchEvent(event);Utils.showReturnValue(returnValue, "View", "dispatchTouchEvent");return returnValue;}@Overridepublic boolean onTouchEvent(MotionEvent event) {Utils.showMotionEventType(event, "View", "onTouchEvent");boolean returnValue = super.onTouchEvent(event);Utils.showReturnValue(returnValue, "View", "onTouchEvent");return returnValue;}private OnClickListener mOnClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {Utils.showInfo("onClick", "View", "mOnClickListener");}};private OnLongClickListener mOnLongClickListener = new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {Utils.showInfo("onLongClick", "View", "mOnLongClickListener");// 如果返回false,则长按结束的ACTION_UP调用onClickreturn false;}};}

View

<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"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".HelloTouchActivity" ><com.mengdd.hellotouch.MyViewGroupandroid:layout_width="match_parent"android:layout_height="match_parent" android:orientation="vertical"><com.mengdd.hellotouch.MyViewandroid:layout_width="100dp"android:layout_height="100dp"android:layout_gravity="center"android:text="Hello"android:background="#FFBBFFBB" /></com.mengdd.hellotouch.MyViewGroup></RelativeLayout>

layout

Click事件处理

  Click事件:View的短按和长按都是注册监听器的(setListener):

  onClick是在ACTION_UP之后执行的。

  onLongClick则是按下到一定时间之后执行的,这个时间是ViewConfiguration中的:

  private static final int TAP_TIMEOUT = 180; //180毫秒

  这里需要注意onLongClick的返回值,如果是false,则onLongClick之后,手指抬起,ACTION_UP之后还是回执行到onClick;但是如果onLongClick返回true,则不会再调用onClick。

参考资料

  本博客中:

  Android 触摸手势基础 官方文档概览

  http://www.cnblogs.com/mengdd/p/3335508.html

  Android的Touch事件处理机制

  http://www.cnblogs.com/frydsh/archive/2012/11/08/2760408.html

  Android FrameWork——Touch事件派发过程详解

  http://blog.csdn.net/stonecao/article/details/6759189

  Android事件传递机制【Touch事件】

  http://orgcent.com/android-touch-event-mechanism/

  Android 编程下 Touch 事件的分发和消费机制

  http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html

转载于:https://www.cnblogs.com/mengdd/p/3394345.html

Android中的Touch事件相关推荐

  1. Android 编程下 Touch 事件的分发和消费机制

    Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev). ...

  2. 深入cocos2d-x中的touch事件

    深入cocos2d-x中的touch事件 在文章cocos2d-x中处理touch事件中简单讨论过怎样处理touch事件, 那么今天来深入了解下cocos2d-x中是怎样分发touch事件的. 我们最 ...

  3. Android中加载事件的方式

    Android中加载事件的方式 通过内部类的方式实现 通过外部类的方式实现 通过属性的方式实现 通过自身实现接口的方式实现 通过内部类的方式实现 Demo btn_Login.setOnClickLi ...

  4. android 触摸事件 取消,如何禁用/重新启用Android中的触摸事件?

    快速,可能很简单,问题.我有一个视图,其背景是动画,在那段时间,我想禁止用户与视图交互.我的视图是一个FrameLayout,我用onTouchEvent()捕获触摸事件.我试过的解决方案:如何禁用/ ...

  5. Android中ListView选中事件setOnItemSelectedListener无反应不生效问题

    Android中ListView选中事件setOnItemSelectedListener无反应不生效问题 在学习Android中ListView组件时,android模拟器运行app时,发现点击有反 ...

  6. android viewgroup 事件,android中viewgroup的事件传递分析

    在上一篇中我们分析了从view的dispatchTouchEvent到onTouchListener的onTouch回调到onTouchEvent到onClickLisener的onClickandr ...

  7. Android中使用EventBus事件发布/订阅框架实现事件传递

    场景 EventBus EventBus是一种用于Android的事件发布-订阅总线.它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多 ...

  8. Android中的Touch事件处理流程

    1.当触摸屏幕时,最先执行的是Activity中的      public boolean dispatchTouchEvent (MotionEvent ev) {         if (ev.g ...

  9. android+无触摸操作,如何在Android中模拟触摸事件?

    这是一个monkeyrunner脚本,用于将触摸和拖动操作发送到应用程序.我一直在使用它来测试我的应用程序可以处理快速重复的滑动手势. # This is a monkeyrunner jython ...

最新文章

  1. 鲁棒,抗遮挡的对柔性手抓取的物体6D姿态估计
  2. Android调用WebService系列之对象构建传递
  3. git-stash用法小结
  4. MySQL 优化之 index merge(索引合并)
  5. Javaweb-AJAX快速入门及案例实战
  6. python交互模式切换_Python 交互式窗口 (REPL) - Visual Studio | Microsoft Docs
  7. 基于像素聚类的分割方法基于slic的方法_博士论文摘要 | 张荣春:数码影像与TLS点云数据融合提取地质结构面方法研究...
  8. 给下拉框加上可输入查询特性,包括中文与拼音首字母
  9. ASP.NET MVC3 系列教程 – Web Pages 1.0
  10. 《JAVA与模式》之观察者模式
  11. Java MyBaties 映射配置文件 mapper
  12. 中文只占一个字符_长寿的人,3个部位可能“发红”,哪怕只占一个,身体还算健康...
  13. 【图像处理】MATLAB:彩色图像处理
  14. python是什么类型的语言-编程语言分类及python所属类型
  15. Web 实时通信 WebRTC
  16. Ajax Control Toolkit 控件介绍
  17. 4000亿市值迈瑞医疗的虚火与真金
  18. 【视频】老外拍的阿里巴巴纪录片,讲述淘宝怎么打败eBay
  19. knex 找不到mysql_转义knex mysql查询语句
  20. 实战:从零开始制作一个跑步微信小程序

热门文章

  1. MySQL事件调度器(Event Scheduler)介绍
  2. HTTP长连接、短连接
  3. Ansj中文分词Java开发小记
  4. VC对话框最小化到托盘
  5. VB Mid函数作用
  6. atomic底层实现是基于无锁算法cas
  7. 常用基础参数PrintGCDetails回收前后对比讲解
  8. spring核心功能结构
  9. WAF果真是个好东西
  10. jQuery中的slideUp()、slideDown()、hide()、show()