Android事件分发机制(上)View部分

Android事件分发机制 开始的开始 当我手指触摸到手机屏幕后,给我所见即所得的触控体验,它的背后发生了什么?出于对它的好奇,就有了这篇文章。因为本人不喜欢大段大段的源码分析,所以本文尽量从设计的角度去把把事件分发机制的脉络,少贴源码是我的目标之一,虽然这么说,但当我把文章写完后最后发现依然贴了不少代码,想删减却没法减少,都是很核心的部分。本博客的主要内容如下: 事件分发的整体设计 ViewRootImpl的创建 应用层级的事件分发流程 为了后面更容易的理解事件分发机制,在介绍核心内容前,准备了一些前置知识。 前置知识:View 阅读详情

前言:如果害怕被拒绝,那让我们尝试拥抱拒绝,不要逃跑,不断去尝试。


记得曾今一直想弄懂Android的事件分发机制,觉得那是一个很酷的事。但想要弄懂安卓的分发机制就必定要深入到源码中去理解,每次在阅读长长的源码产生敬畏的同时也会迷失在源码之中。想要写一篇关于事件分发机制的博客,来完成当初自己的梦想,也希望能够在今后帮助和我一样的同学。

今天我们便先从Android中的View的源码先入手深入浅出,了解事件分发机制中最终消耗事件的View。关于GroupView的事件分发的分析,如果大家觉得好,我会尽快抽空给大家整理出来。(因为有点懒而且水平有限,所以写的会比较慢)


当我们去触碰一个控件的时候,那么就会调用该控件的dispatchTouchEvent方法。首先我们来先记住几个关键点:


1、 同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏慕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最后以up结束。


2、  View的事件到来时,会先调用他的dispatchTouchEvent方法。


3、对于View,OnTouch的优先级高于OnTouchEvent高于OnClick,这就意味着setOnTouchListener的onTouch方法中返回true,那么onTouchEvent和OnClick方法不会调用。这样做到好处就是方便在外界处理点击事件。


4、view的onTouchEvent默认都会消耗事件(返回true),除非它是不可点击的(clickable和longClickable同时为false),View的longClickable属性默认都为false,clickable属性要分情况,比如Button的clickable属性默认为true,而TextView的clickable属性默认为false。


先有个印象,我们接下来去分析。

 

dispatchTouchEvent源码分析:


以上几个点都好理解,很好去证实。


对于第一点,我们其实只要自定义一个Button继承于Button,然后重写它的onTouchEvent方法,并对事件进行打印就能证实。


对于第二点,再我们写的Button中重写它的dispatchTouchEvent方法,然后打印log,你就会发现dispatchTouchEvent先于OnTouchEvent和OnTouch方法执行。


对于第三点,我们就需要从源码中去搜寻答案,去证实我们的假设。既然我们知道我们触碰一个控件,那么就会调用该控件的dispatchTouchEvent方法。

 

我们来看看dispatchTouchEvent方法的源码:

public boolean dispatchTouchEvent(MotionEvent event) {
        // If the event should be handled by accessibility focus first.
        if (event.isTargetAccessibilityFocus()) {
            // We don't have focus or no virtual descendant has it, do not handle the event.
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            // We have focus and got the event, then use normal event dispatch.
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

        // Clean up after nested scrolls if this is the end of a gesture;
        // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
        // of the gesture.
        if (actionMasked == MotionEvent.ACTION_UP ||
                actionMasked == MotionEvent.ACTION_CANCEL ||
                (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
            stopNestedScroll();
        }

        return result;
    }

在以上的源码中有很多内容我们只需要看关键部分:

             ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            if (!result && onTouchEvent(event)) {
                result = true;
            }

这里的逻辑很简单,我们先对ListenerInfo进行判断!=null&&ListenerInfo的mOnTouchListener!=null && View的状态是Enable && mOnTouchListener的onTouch方法返回了true,那么result就被赋值为true。

那么这个 mOnTouchListener是在哪里设置的呢?

 

public void setOnTouchListener(OnTouchListener l) {
    getListenerInfo().mOnTouchListener = l;
}

从这里我们可以看出,我们再setOnTouchListener的时候就对 mOnTouchListener进行了赋值。

当result被赋值了true,那么!result && onTouchEvent(event)这个判断的!result就是false,所以OnTouchEvent就不会被调用。

所以在这里我们可以得出结论,如果setOnTouchListener的onTouch方法返回了true,那么onTouchEvent就不会被调用,如果返回了false,那么onTouch会被调用而且onTouchEvent也会被调用。


分析完dispatchTouchEvent我们接着分析一下onTouchEvent的源码:

public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        final int viewFlags = mViewFlags;
        final int action = event.getAction();

        if ((viewFlags & ENABLED_MASK) == DISABLED) {
            if (action == 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)
                    || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
        }
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }

        if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
            switch (action) {
                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, x, y);
                       }

                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            // 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();
                    }
                    mIgnoreNextUpEvent = false;
                    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();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true, x, y);
                        checkForLongClick(0, x, y);
                    }
                    break;

                case MotionEvent.ACTION_CANCEL:
                    setPressed(false);
                    removeTapCallback();
                    removeLongPressCallback();
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    break;

                case MotionEvent.ACTION_MOVE:
                    drawableHotspotChanged(x, y);

                    // 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;
    }

onTouchEvent的源码很长,但不要担心,我们也挑重点进行分析。

对于第四点,我们可以分步去分析。
  if ((viewFlags & ENABLED_MASK) == DISABLED) {
            if (action == 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)
                    || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
        }


通过上面的代码我们可以明白当View是Enable的时候也不会影响onTouchEvent消耗事件,即返回true。只要CLICKABLE和LONG_CLICKABLE和

CONTEXT_CLICKABLE中有一个为true,那么就会return true,后面的代码都不会执行。

而且需要注意的是当我们给View设置了setOnClickListener方法,默认会设置为CLICKABLE。

public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

接着我们继续分析Enable的情况:

        if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
            switch (action) {
                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, x, y);
                       }

                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            // 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();
                    }
                    mIgnoreNextUpEvent = false;
                    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();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true, x, y);
                        checkForLongClick(0, x, y);
                    }
                    break;

                case MotionEvent.ACTION_CANCEL:
                    setPressed(false);
                    removeTapCallback();
                    removeLongPressCallback();
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    break;

                case MotionEvent.ACTION_MOVE:
                    drawableHotspotChanged(x, y);

                    // 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;
        }

我们看下这段代码,我们可以看到View的状态只要CLICKABLE或者LONG_CLICKABLE,且这个View不是DISABLER的状态,那当

MotionEvent.ACTION_UP时他会执行performClick方法,在这个方法里就会调用onClick方法,并返回true。


如果有疑问或者错误,欢迎留言或指正。




【Android】View的事件分发机制 `dispatchTouchEvent(MotionEvent event)` 方法是事件分发的入口。 - 每当事件产生时(如点击、滑动),系统会将该事件封装成一个 `MotionEvent` 对象,并通过 `dispatchTouchEvent` 方法传递给根视图(通常是 `Activity` 中的 `DecorView`)。 - 在 `dispatchTouchEvent` 中,事件会根据层级逐层传递给子视图,直到找到可以处理事件的视图为止。 - 若 `dispatchTouchEv 阅读详情

相关推荐

探索Android事件分发机制,带你通过源码分析事件分发流程——ViewGroup篇

通过上一篇文章(探索Android事件分发机制,带你通过源码分析事件分发流程——View篇)我们已经了解了View的事件分发过程,还没有阅读的朋友可以点连接去阅读。本篇我们将分析事件分发机制主菜——ViewGroup的事件分发 一、事件的传递顺序 为什么说ViewGroup的事件分发是主菜呢?在解答这个问题之前,我们先看一看触摸事件是怎么到达View手中的: 触摸到手机屏幕后

纪田元的博客 806

android事件分发机制原理源码分析详解

  我们都知道,在android里当点击一个控件时,系统能准确地将事件传递给真正需要这个事件的控件,那么当android系统捕获到用户的各种输入时间之后,是如何传递分发的呢?其实android系统我们提供了一整套完善的事件传递、分发、处理机制,来帮助开发者完成准确的事件分发与处理。  要了解触摸事件的拦截机制,首先要了解什么是触摸事件?顾名思义,触摸事件就是捕获触摸屏幕后产生的事件。通常的当点击屏...

qtiao的博客 1283

View事件分发和坐标系统总结

View 座標分析相對與父控件 mTop mLeft mBottom mRight 絕對值 mHeight mWidth隱藏部分絕對值 mScrollX :上部隱藏部分 相對與mtop mScrollY  : 左邊隱藏部分 相對於mLeft 以(mTop,mLeft) 爲座標原點 x y 以屏幕左上角爲原點 rawX,rawY事件分发 采用组合模式和包装模式由activ

woai110120130的专栏 329

从源码角度分析事件分发流程

事件分发流程分为View的事件分发和ViewGroup的事件分发, 首先来看看View的事件分发流程,也就是View#dispatchTouchEvent到底做了什么。 View的事件分发 public boolean dispatchTouchEvent(MotionEvent event) { ... //默认不消费 boolean result = false; ...

热爱不止,前行不息 418

SMPTE ST 2110 概论(一)

SMPTE ST 2110 概论(一)前言ST 2110与ST 2022-6ST 2110-10:基本结构与时序ST 2110-20:未压缩的视频流后续 前言 这是一份我在实习期间制作的,关于SMPTE ST 2110的简单介绍。 这篇文章主要以梳理总结 SMPTE ST 2110 的概念为主,关于具体的内容,比如IP数据报的格式、RTP时间戳的具体代码内容等等,大家可以查阅 SMPTE ST 2...

Cidd0422的博客 2万+

【汇编】TSR内存驻留程序实现与删除及热键设置——以实现时钟为例

【汇编】TSR内存驻留程序实现与删除及热键设置——以实现时钟为例 最近完成了一个关于时钟中断驻留的汇编大作业,对于TSR很是感兴趣,查阅了不少资料,发现现在很少相关的内容资料。尤其是TSR删除这一块几乎找不到在低的水平完全正确的做法,下面我对于TSR的删除我会介绍一种几乎小程序可以完成的方法。当然,标题中的TSR实现,热键设置我也会一一介绍。

cly116的博客 3971

touch事件分发机制

  View事件的分发可以用如下伪代码来描述: public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume = false; if(onInterceptTouchEvent(ev)){ consume = onTouchEvent(ev); }else{ consu...

DK233333的博客 356

从零开始:用摩尔线程S4000运行开源AI项目的完整流程

本文详细介绍了如何使用摩尔线程S4000 GPU从零开始运行开源AI项目的完整流程,包括硬件选择、驱动安装、容器化环境配置以及典型AI项目的实战部署。通过性能优化技巧,显著提升推理速度,适合开发者快速上手国产GPU的AI应用开发。

weixin_29231725的博客 581

Android 事件分发机制,事件的传递流程

什么是事件分发: 通过手指对屏幕的触摸来完成整个交互的过程。 用户通过屏幕与手机交互的时候,每次点击、长按、移动等都是一个事件。 事件分发机制:某一个事件从屏幕传递各个View,由View来使用这一事件(消费事件)或者忽略这一事件,这个过程的控制。 事件分发的对象 系统把时间封装为MotionEvent对象,事件分发的过程就是MotionEvent分发的过程。 事件类型:按下(ACTION_DOW...

张雨的博客 454

Comsol&Matlab 亥姆霍兹共振消声器传递损失理论解与仿真解

当外界噪声以共振频率进入共振器时,共振器内的空气质量发生周期性的振动,从而减少或消除噪声。当特定频率的声波进入共振器时,共振器的空气质量会发生周期性的振动,从而实现对该频率的噪声的减弱或消除。5. 反射和吸收:共振器的几何形状和容积还可以影响共振器内空气振动的反射和吸收。然而,对于不同频率的噪声,需要相应调整共振器的参数以匹配新的共振频率。3. 腔体内的空气振动:当特定频率的声波进入共振器时,共振器内的空气质量会发生振动。2. 声波进入共振器:外界的声波通过共振器的颈部进入共振器的封闭空腔。

声学黑洞仿真工作室 4575

激光雷达与相机时间戳同步:原理、触发方案与工程实现

目录一、引言:时间不同步,多传感器融合必出问题二、核心原理:相机成像机制与触发模式(同步的基础)2.1 相机成像的两个核心阶段:曝光与读出(1)非交叠曝光(2)交叠曝光2.2 相机触发模式:内触发 vs 外触发(1)内触发(2)外触发2.3 关键信号:Strobe信号与预输出(同步的核心技巧)三、三种主流时间戳同步方案(工程落地首选)3.1 方案一:统一硬触发(精度最高,高端场景首选)核心原理核心配置要点优缺点适用场景3.2 方案二:软触发+硬触发(Strobe预输出,车载量产首选)核心原理核心配置要点优缺

getusushu的博客 200

View的事件分发机制解析

引言Android事件构成 在Android中,事件主要包括点按、长按、拖拽、滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作。所有这些都构成了Android中的事件响应。总的来说,所有的事件都由如下三个部分作为基础: 按下(ACTION_DOWN) 移动(ACTION_MOVE) 抬起(ACTION_UP) 所有的操作事件首先必须执行的是按下操作(ACTION_DOWN),之后所有的操

斩月的专栏 5414

黑猫带你学eMMC协议第29篇:eMMC设备锁详解(CMD42)

通过cmd42命令,可以给emmc设置密码,并且锁定emmc。这时候就不能对emmc的user分区进行读写数据访问了。设备锁在V4.3版本后的emmc里面,就只能保护user area分区,因此,被锁定的emmc,依旧可以正常访问BOOT\RPMB\GPP分区。emmc内部有128 bit PWD寄存器,用来存放密码,以及有8bit PWD_LEN寄存器,用来密码长度。这两个寄存器非易失性,掉电也不会丢失。

黑猫奥利奥的博客 3237

本以为精通Android事件分发机制,没想到被面试官问懵了

指从手指刚接触屏幕,到手指离开屏幕的那一刻结束,在这一过程产生的一系列事件,这个序列一般以down事件开始,中间含有多个move事件,最终以up事件结束2. 事件分发的本质事件分发的本质,其实就是将(MotionEvent)传递到某个具体的View处理的整个过程3. 事件分发的顺序事件传递的顺序:Activity->Window->DecorView->ViewGroup->View。

2401_84123094的博客 381

[deprecated]第四章:TTM分析: 4.2.1 存储分配ttm_bo_validate功能实现分析

ttm_bo_validate是TTM框架中负责验证和调整BufferObject物理内存分配的核心函数,主要用于显存管理。该函数通过placement参数判断BO是否需要迁移或重新分配资源,完成内存分配、迁移及缓存策略调整等操作。实现流程包括资源释放、兼容性检查、迁移保护、新资源分配、迁移实现等步骤,支持多跳迁移和临时缓冲区。典型应用于显存溢出迁移、缓存策略调整、驱动初始化等场景,确保BO始终处于预期状态。

图形/计算GPU的驱动与虚拟化技术分享园地 842

智能车图像处理21-进阶篇13--正入十字补线2

这篇文章主要的正入十字补线与1基本相同,主要防止图像中双十字的问题。

taiyuezyh的博客 2032

一文读懂Android View事件分发机制

Android View 虽然不是四大组件,但其并不比四大组件的地位低。而View的核心知识点事件分发机制则是不少刚入门同学的拦路虎。ScrollView嵌套RecyclerView(或者ListView)的滑动冲突这种老大难的问题的理论基础就是事件分发机制。 事件分发机制面试也会经常被提及,如果你能get到要领,并跟面试官深入的灵魂交流一下,那么一定会让面试官对你印象深刻,

学无止尽,生命不息.. 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Android View的事件分发机制

Android View的事件分发机制

m0_74448051的博客 1153

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

解锁Android View事件分发机制:从原理到实战

在 Android 中,用户与界面的交互操作,如点击、滑动、长按等,都会产生触摸事件,这些事件被封装成MotionEvent对象。MotionEvent包含了丰富的信息,如触摸的坐标、触摸的类型、触摸的时间等,开发者可以通过这些信息来处理用户的操作。:手指刚接触屏幕时触发,这是一个事件序列的开始。在点击操作中,当手指按下屏幕的瞬间,就会产生ACTION_DOWN事件。它是事件处理的起点,后续的其他事件往往基于此展开。

顾林海 4551

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Android View事件分发

什么是View事件分发?将点击事件(MotionEvent)传递到某个具体的View或者ViewGroup处理的过程。事件分发是向下传递的,也就是父到子的顺序,当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件)。Touch事件相关细节(发生触摸的位置、时间、历史记录、手势动作等)被封装成MotionEvent对象。

Android 领域开发程序员,希望通过写博客的方式不断的总结提升自己,大家共同进步哦! 1726

《Android View 的事件分发机制解析》

前言: 用户按下触摸屏幕的事件。ACTION_UP: 用户抬起手指的事件。: 用户在屏幕上移动手指的事件。: 事件被取消,例如由于系统的其他操作。: 当已经有一个手指按下的情况下,另一个手指按下会产生该事件;: 多个手指同时按下的情况下,抬起其中一个手指会产生该事件;

weijiangbc0的博客 1456

【Android】事件分发机制

从上表可以看到 Activity和 View都是没有事件拦截的,这是因为:Activity 作为原始的事件分发者,如果 Activity 拦截了事件会导致整个屏幕都无法响应事件,这肯定不是我们想要的效果。View作为事件传递的最末端,要么消费掉事件,要么不处理进行回传,根本没必要进行事件拦截。

2303_79296612的博客 1726

【Android】图解View事件分发机制

View的事件分发机制是Android中非常核心的一个概念,它负责处理触摸事件(如按下、移动、抬起等)的分发过程。当一个触摸事件发生时,这个事件首先会被传递到顶层的 ViewGroup(比如一个 Activity 的根布局),然后通过。View 的事件分发机制主要是通过。方法来决定如何分发这个事件。

xoliu的博客 1693

View的事件分发机制

也需要onTouchEvent方法来消费事件使事件不再向上回传处理。因为我当时并没有真正理解View的事件分发机制,平时使用时,同时对ViewGroup和其内部包含的子View设置点击事件,点击事件总会被子View响应,ViewGroup总是不响应,所以惯性思维的觉得事件是从子View发出,逐层向上传递的...。View也只有两个方法,没有事件拦截方法,这是因为View是最底层的事件接受者,它的下面没有子View,也就没有拦截的必要的,但View为什么会有事件分发的方法呢,它又没有子View,留着这个。

Chenyile161616的博客 1328

安卓view事件分发机制

安卓view事件分发机制

似霰的博客 981
上一篇: Android 获取栈最顶层Activity和Application Context解决方案
下一篇: Android面试(Activity生命周期)
VikcyWinner
博客等级 码龄11年 12粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值