ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Android 事件分发机制基础详解:从 MotionEvent 到 dispatchTouchEvent 的完整脉络

Android 事件分发机制基础详解:从 MotionEvent 到 dispatchTouchEvent 的完整脉络 教程技术博客文档【免费下载链接】YCBlogs技术博客笔记大汇总包括Java基础线程并发数据结构Android技术博客等等常用设计模式常见的算法网络协议知识点部分flutter笔记还包括平时开发中遇到的bug汇总当然也在工作之余收集了大量的面试题长期更新维护并且修正持续完善……开源的文件是markdown格式的转载请注明出处谢谢项目地址https://gitcode.com/gh_mirrors/yc/YCBlogs点击查看免费下载本文是 YCBlogs 仓库「事件分发」系列的开篇之作以 android/05.事件分发/01.View事件基础介绍.md 为骨架结合同目录下源码分析、滑动冲突、返回键分发与面试题等姊妹篇完整梳理 Android 触摸事件分发的概念、核心方法、调用顺序与经典场景。读完本文你将掌握事件序列DOWN/MOVE/UP/CANCEL的本质、dispatchTouchEvent()/onInterceptTouchEvent()/onTouchEvent()三者分工与返回语义、默认 / 处理 / 拦截 / 半路拦截四种典型场景下事件的流向以及由这些规则衍生出的滑动冲突与拖动业务解决方案可直接用于自定义 View 开发和滑动冲突排查。01. 事件分发概念1.1 事件分发的对象是谁事件分发的对象是事件注意事件分发是向下传递的也就是父到子的顺序。当用户触摸屏幕时View 或 ViewGroup 派生的控件将产生点击事件Touch 事件。Touch 事件相关细节发生触摸的位置、时间、历史记录、手势动作等被封装成MotionEvent对象。主要发生的 Touch 事件有如下四种事件类型说明MotionEvent.ACTION_DOWN按下 View所有事件的开始MotionEvent.ACTION_MOVE滑动 ViewMotionEvent.ACTION_CANCEL非人为原因结束本次事件MotionEvent.ACTION_UP抬起 View与 DOWN 对应a.1 ACTION_DOWN用户手指的按下操作一次按下操作标志着一次触摸事件的开始。a.2 ACTION_UP用户手指离开屏幕的操作一次抬起操作标志着一次触摸事件的结束。a.3 ACTION_MOVE用户手指按压屏幕后在松开之前如果距离超过一定阈值那么会被判定为 ACTION_MOVE。一般情况下手指的轻微移动都会触发一系列移动事件。a.4 注意在一次屏幕触摸事件中ACTION_DOWN和ACTION_UP这两个事件是必须的而ACTION_MOVE视情况而定——如果用户仅是点击了一下屏幕那么可能只会监测到按下和抬起的动作。通过MotionEvent可以获得事件发生的 x 和 y 坐标getX()/getY()返回的是相对于当前 View 左上角的 X 和 Y 坐标getRawX()/getRawY()返回的是相对于手机屏幕左上角的 X 和 Y 坐标。a.5 其他Touch触摸事件 ♦ 在Android中Touch触摸事件主要包括 点击(onClick) 长按(onLongClick) 拖拽(onDrag) 滑动(onScroll) ♦ 在Android中Touch操作状态主要包括 按下(ACTION_DOWN) 移动(ACTION_MOVE) 抬起(ACTION_UP) 取消手势(ACTION_CANCEL) 划出屏幕(ACTION_OUTSIDE)事件列事件序列从手指接触屏幕至手指离开屏幕这个过程产生的一系列事件。即当一个 MotionEvent 产生后系统需要把这个事件传递给一个具体的 View 去处理。任何事件列都是以 DOWN 事件开始、UP 事件结束中间有无数个 MOVE 事件。补充ACTION_OUTSIDE 表示触摸区域划出了控件边界而 ACTION_CANCEL 通常是系统层面如父容器中途拦截主动结束事件序列时派发的是触摸事件处理中非常关键的“补偿机制”后文 3.2.4 会详细展开。1.2 事件分发的本质将点击事件MotionEvent向某个 View 进行传递并最终得到处理——即当一个点击事件发生后系统需要将这个事件传递给一个具体的 View 去处理。这个事件传递的过程就是分发过程。Android 事件分发机制的本质是要解决点击事件由哪个对象发出经过哪些对象最终达到哪个对象并最终得到处理。1.3 事件在哪些对象间进行传递Activity、ViewGroup、View是参与事件分发的三大角色。一个点击事件产生后传递顺序是ActivityWindow - ViewGroup - View。Android 的 UI 界面正是由 Activity、ViewGroup、View 及其派生类组合而成的。View 是所有 UI 组件的基类一般 Button、ImageView、TextView 等控件都是继承父类 View。ViewGroup 是容纳 UI 组件的容器即一组 View 的集合包含很多子 View 和子 ViewGroup其本身也是从 View 派生的即 ViewGroup 是 View 的子类是 Android 所有布局的父类或间接父类项目用到的布局LinearLayout、RelativeLayout 等都继承自 ViewGroup即属于 ViewGroup 子类与普通 View 的区别ViewGroup 实际上也是一个 View只不过比起 View它多了可以包含子 View 和定义布局参数的功能。从更完整的链路看触摸事件从系统 Native 层进入应用后会依次经过Native 层 - ViewRootImpl 层 - DecorView 层 - Activity 层 - ViewGroup 层 - View 层详见 返回键事件分发流程 中的输入链路分析。应用内日常讨论的分发聚焦于 Activity/ViewGroup/View 三层。1.4 事件分发过程涉及方法事件分发过程由这几个方法协作完成dispatchTouchEvent()分发事件onInterceptTouchEvent()判断是否拦截事件仅 ViewGroup 有onTouchEvent()处理事件1.5 Android 触摸事件流程总结一个事件序列从手指触摸屏幕开始到触摸结束。同一事件序列是以ACTION_DOWN开始中间有数量不定的ACTION_MOVE事件最终以ACTION_UP结束。事件传递顺序是Activity —— Window —— View最后顶级 View 接收到事件后就会按照事件分发机制去分发事件。事件传递过程是由外向内的即事件总是由父元素分发给子元素。02. 事件分发机制方法事件分发过程由dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()三个方法协助完成。2.1 dispatchTouchEvent()属性介绍使用对象Activity、ViewGroup、View作用分发点击事件调用时刻当点击事件能够传递给当前 View 时该方法就会被调用返回结果是否消费当前事件1. 默认情况根据当前对象的不同而返回方法不同对象返回方法备注Activitysuper.dispatchTouchEvent()即调用父类ViewGroup的dispatchTouchEvent()ViewGrouponInterceptTouchEvent()即调用自身的onInterceptTouchEvent()ViewonTouchEvent()即调用自身的onTouchEvent()流程解析返回 true消费事件事件不会往下传递后续事件Move、Up会继续分发到该 View。返回 false不消费事件事件往下传递将事件回传给父控件的onTouchEvent()处理Activity 例外返回 false 消费事件后续事件Move、Up会继续分发到该 View与onTouchEvent()的区别。源码佐证Activity 的dispatchTouchEvent()中事件先经过onUserInteraction()空实现多用于屏保逻辑随后调用getWindow().superDispatchTouchEvent(ev)把事件交给 Window只有 Window 层返回 false即所有 View 都没有处理时才回落到onTouchEvent(ev)自己处理见 View事件机制源码分析。2.2 onTouchEvent()属性介绍使用对象Activity、ViewGroup、View作用处理点击事件调用时刻在dispatchTouchEvent()内部调用返回结果是否消费处理当前事件流程解析返回 true自己处理消费该事件事件停止传递该事件序列的后续事件Move、Up交由它处理。返回 false同默认实现调用父类 onTouchEvent()不处理消费该事件事件往上传递给父控件的onTouchEvent()处理当前 View 不再接受此事件列的其他事件Move、Up。注意一点这里要强调 View 的OnTouchListener如果 View 设置了该监听那么onTouch()将会回调。如果返回为 true那么该 View 的onTouchEvent()将不会执行——这是因为设置的OnTouchListener执行时的优先级要比onTouchEvent高。优先级OnTouchListener onTouchEvent onClickListener源码佐证View 的dispatchTouchEvent()源码中只有当mOnTouchListener ! null (mViewFlags ENABLED_MASK) ENABLED mOnTouchListener.onTouch(this, event)三个条件全部成立才直接返回 true否则继续走onTouchEvent(event)而onClick()是在onTouchEvent()的 ACTION_UP 分支中经由performClick()回调的因此优先级最低详见 View事件机制源码分析 与 View事件总结案例。2.3 onInterceptTouchEvent()属性介绍使用对象ViewGroup注Activity、View 都没有该方法作用拦截事件即自己处理该事件调用时刻在 ViewGroup 的dispatchTouchEvent()内部调用返回结果是否拦截当前事件流程解析true当前 ViewGroup因为 View 中没有该方法而没有 child 的 View 也不需要有拦截机制希望该事件不再传递给其 child而是希望自己处理。false当前 ViewGroup 不准备拦截该事件事件正常向下分发给其 child。2.4 三个方法执行顺序以下代码在自定义 View 中同时重写三个方法并打印日志Override public boolean onInterceptTouchEvent(MotionEvent e) { LogUtils.e(yc----------事件拦截----------); return super.onInterceptTouchEvent(e); } Override public boolean dispatchTouchEvent(MotionEvent ev) { LogUtils.e(yc----------事件分发----------); return super.dispatchTouchEvent(ev); } SuppressLint(ClickableViewAccessibility) Override public boolean onTouchEvent(MotionEvent e) { LogUtils.e(yc----------事件触摸----------); return super.onTouchEvent(e); }执行结果如下yc----------事件分发---------- yc----------事件拦截---------- yc----------事件触摸----------可以看到事件先进入dispatchTouchEvent()分发入口—— 再进入onInterceptTouchEvent()判断是否拦截—— 最后进入onTouchEvent()处理事件这与源码中的调用关系完全一致。2.5 三者之间关系下面将用一段伪代码来阐述上述三个方法的关系和点击事件传递规则// 点击事件产生后会直接调用dispatchTouchEvent分发方法 public boolean dispatchTouchEvent(MotionEvent ev) { // 代表是否消耗事件 boolean consume false; if (onInterceptTouchEvent(ev)) { // 如果onInterceptTouchEvent()返回true则代表当前View拦截了点击事件 // 则该点击事件则会交给当前View进行处理 // 即调用onTouchEvent()方法去处理点击事件 consume onTouchEvent(ev); } else { // 如果onInterceptTouchEvent()返回false则代表当前View不拦截点击事件 // 则该点击事件则会继续传递给它的子元素 // 子元素的dispatchTouchEvent()就会被调用重复上述过程 // 直到点击事件被最终处理为止 consume child.dispatchTouchEvent(ev); } return consume; }对照真实源码ViewGroup 的dispatchTouchEvent()中判断是否调用拦截器的核心逻辑如下节选自 View事件机制源码分析// 发生 ACTION_DOWN 事件或者已经发生过 ACTION_DOWN 且 mFirstTouchTarget 已被赋值才进入此区域 final boolean intercepted; if (actionMasked MotionEvent.ACTION_DOWN || mFirstTouchTarget ! null) { // disallowIntercept是否禁用事件拦截的功能(默认是 false) final boolean disallowIntercept (mGroupFlags FLAG_DISALLOW_INTERCEPT) ! 0; if (!disallowIntercept) { intercepted onInterceptTouchEvent(ev); // 默认情况下会调用拦截方法 ev.setAction(action); } else { intercepted false; } } else { // 当没有触摸 targets且不是 down 事件时开始持续拦截触摸 intercepted true; }这也解释了如果子 View 的onTouchEvent()返回 false那么接下来的一系列事件都不会再交给它处理如果 ViewGroup 的onInterceptTouchEvent()第一次执行为 true则mFirstTouchTarget null后续事件将不再调用onInterceptTouchEvent()直接视为拦截。03. 事件分发背景描述3.1 先看一个案例讨论的布局层次如下最外层Activity A包含两个子 ViewViewGroup B、View C中间层ViewGroup B包含一个子 ViewView C最内层View C。触摸情况假设用户首先触摸到屏幕上 View C 上的某个点那么ACTION_DOWN事件就在该点产生然后用户移动手指并最后离开屏幕。3.2 该案例事件传递情况一般的事件传递场景有四种默认情况、处理事件、拦截 DOWN 事件、拦截后续事件MOVE、UP。3.2.1 默认情况即不对控件里的方法dispatchTouchEvent()、onTouchEvent()、onInterceptTouchEvent()进行重写或更改返回值那么调用的是这 3 个方法的默认实现——调用父类的方法。事件传递情况从Activity A -- ViewGroup B -- View C从上往下调用dispatchTouchEvent()再由View C -- ViewGroup B -- Activity A从下往上调用onTouchEvent()。注虽然 ViewGroup B 的onInterceptTouchEvent()方法对 DOWN 事件返回了 false后续的事件MOVE、UP依然会传递给它的onInterceptTouchEvent()。这一点与onTouchEvent()的行为是不一样的因为此时mFirstTouchTarget ! null仍会进入拦截判断分支见 2.5 节源码。3.2.2 处理事件假设 View C 希望处理这个点击事件即 C 被设置成可点击的Clickable或者覆写了 C 的onTouchEvent()方法返回 true最常见的设置 Button 按钮来响应点击事件。事件传递情况DOWN 事件被传递给 C 的onTouchEvent()方法该方法返回 true表示处理这个事件因为 C 正在处理这个事件那么 DOWN 事件将不再往上传递给 B 和 A 的onTouchEvent()该事件列的其他事件Move、Up也将传递给 C 的onTouchEvent()。3.2.3 拦截 DOWN 事件假设 ViewGroup B 希望处理这个点击事件即 B 覆写了onInterceptTouchEvent()返回 true、onTouchEvent()返回 true。事件传递情况DOWN 事件被传递给 B 的onInterceptTouchEvent()方法该方法返回 true表示拦截这个事件即自己处理这个事件不再往下传递调用onTouchEvent()处理事件DOWN 事件将不再往上传递给 A 的onTouchEvent()该事件列的其他事件Move、Up将直接传递给 B 的onTouchEvent()。注意该事件列的其他事件Move、Up将不会再传递给 B 的onInterceptTouchEvent()方法该方法一旦返回一次 true就再也不会被调用了。3.2.4 拦截 DOWN 的后续事件假设 ViewGroup B 没有拦截 DOWN 事件还是 View C 来处理 DOWN 事件但它拦截了接下来的 MOVE 事件。事件传递情况DOWN 事件传递到 C 的onTouchEvent()方法返回了 true在后续到来的 MOVE 事件中B 的onInterceptTouchEvent()方法返回 true 拦截该 MOVE 事件但该事件并没有传递给 B这个 MOVE 事件将会被系统变成一个 CANCEL 事件传递给 C 的onTouchEvent()方法后续又来了一个 MOVE 事件该 MOVE 事件才会直接传递给 B 的onTouchEvent()后续事件将直接传递给 B 的onTouchEvent()处理后续事件将不会再传递给 B 的onInterceptTouchEvent()方法该方法一旦返回一次 true就再也不会被调用了C 再也不会收到该事件列产生的后续事件。特别注意如果 ViewGroup A 拦截了一个半路的事件如 MOVE这个事件将会被系统变成一个 CANCEL 事件并传递给之前处理该事件的子 View该事件不会再传递给 ViewGroup A 的onTouchEvent()只有再到来的事件才会传递到 ViewGroup A 的onTouchEvent()。这段 CANCEL 机制正是后续实现滑动冲突“外部拦截法”时的理论基础当父容器在 MOVE 阶段决定接管事件时子 View 会先收到一个 CANCEL 来终止自己的滑动/点击状态避免出现“子 View 还在处理、父 View 也在处理”的撕裂状态。04. 拖动过程业务举例事件分发机制落实到业务上最常见的就是拖拽 / 滑动场景手指按下DOWN选中目标移动MOVE过程中根据坐标差实时改变控件位置或滚动内容抬起UP结束。这一场景直接复用第 03 节的四种传递模型并结合滑动方法实现。4.1 拖动案例的流程设计以一个可拖动的自定义 View 为例在onTouchEvent()中根据事件类型分别处理Override public boolean onTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: // 1. 记录按下位置标记开始拖动对应事件序列的开始 lastX (int) event.getRawX(); lastY (int) event.getRawY(); return true; // 消费 DOWN保证后续 MOVE/UP 都交给本 View case MotionEvent.ACTION_MOVE: // 2. 计算偏移量更新控件位置layout / offsetLeftAndRight 等滑动方式 int offsetX (int) event.getRawX() - lastX; int offsetY (int) event.getRawY() - lastY; layout(getLeft() offsetX, getTop() offsetY, getRight() offsetX, getBottom() offsetY); lastX (int) event.getRawX(); lastY (int) event.getRawY(); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // 3. 抬起或取消结束拖动 return true; } return super.onTouchEvent(event); }关键点解读DOWN 必须返回 true只有 DOWN 被消费事件序列才被当前 View“锁定”后续 MOVE/UP 才会持续派发给它对应 1.5 与 2.1 的规则MOVE 中计算增量使用getRawX()/getRawY()屏幕坐标计算绝对偏移避免嵌套容器时坐标偏移叠加问题CANCEL 需要妥善处理当父容器中途拦截如滑动冲突场景系统会先派发 CANCEL此时应复位拖动状态否则控件会停留在半路。4.2 拖动场景下的滑动冲突当父容器与子 View 都可以滑动时就会产生滑动冲突例如外层 ScrollView 纵向滑动、内层 ViewPager 横向滑动。解决 View 之间滑动冲突的方法分为两种外部拦截法和内部拦截法详见 View滑动冲突处理。外部拦截法父容器在onInterceptTouchEvent()中根据需求选择性拦截核心思路伪代码如下public boolean onInterceptTouchEvent(MotionEvent event) { boolean intercepted false; int x (int) event.getX(); int y (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { intercepted false; // DOWN 不能拦截否则后续事件都归父容器 break; } case MotionEvent.ACTION_MOVE: { if (满足父容器的拦截要求) { intercepted true; } else { intercepted false; } break; } case MotionEvent.ACTION_UP: { intercepted false; // UP 原则上不拦截保证子 View 的 onClick 能触发 break; } default: break; } mLastXIntercept x; mLastYIntercept y; return intercepted; }要点ACTION_DOWN 返回 false否则后续 MOVE/UP 默认全归父容器ACTION_MOVE 按业务判断ACTION_UP 返回 false父容器拦截 UP 会导致子 View 收不到 UPonClick 无法触发。内部拦截法父容器不拦截任何事件所有事件先传递给子 View子 View 根据需求决定自己消费还是交回父容器核心是配合requestDisallowInterceptTouchEvent()// 子 View 重写 dispatchTouchEvent public boolean dispatchTouchEvent(MotionEvent event) { int x (int) event.getX(); int y (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { parent.requestDisallowInterceptTouchEvent(true); // 先请求父容器不要拦截 break; } case MotionEvent.ACTION_MOVE: { int deltaX x - mLastX; int deltaY y - mLastY; if (父容器需要此类点击事件) { parent.requestDisallowInterceptTouchEvent(false); // 交还父容器 } break; } case MotionEvent.ACTION_UP: { break; } default: break; } mLastX x; mLastY y; return super.dispatchTouchEvent(event); } // 父容器 onInterceptTouchEventDOWN 必须返回 false public boolean onInterceptTouchEvent(MotionEvent event) { int action event.getAction(); if (action MotionEvent.ACTION_DOWN) { return false; } else { return true; } }注意requestDisallowInterceptTouchEvent()对ACTION_DOWN 无效源码中FLAG_DISALLOW_INTERCEPT的判定只在非 DOWN 阶段生效所以父容器对 DOWN 的拦截必须显式返回 false。典型的实战案例是 ScrollView 嵌套 ViewPager当手指左右滑动deltaX deltaY时父容器不拦截交给 ViewPager 横向翻页当上下滑动时父容器拦截由 ScrollView 纵向滚动完整布局示例与完整代码见 View滑动冲突处理。05. 事件传递规则要点速查把前文规则浓缩成可直接用于排查问题的清单汇总自 View事件总结案例 与 AndroidView事件问题事件传递顺序Activity - Window - View - 分发如果 View 的onTouchEvent()返回 false则父容器的onTouchEvent()会被调用最终可以传递到 Activity 的onTouchEvent()。View 一旦拦截事件则整个事件序列都由它处理ACTION_DOWN、UP 等onInterceptTouchEvent()不会再被调用因为默认都拦截了。如果 View 开始处理事件已经拦截但不消耗 ACTION_DOWNonTouchEvent()返回 false则同一事件序列的剩余内容都直接交给父onTouchEvent()处理。View 消耗了 ACTION_DOWN 但不处理其他事件整个事件序列会“消失”父onTouchEvent()不会被调用这些消失的点击事件最终会传给 Activity 处理。ViewGroup 默认不拦截任何事件onInterceptTouchEvent()默认返回 false。View 没有onInterceptTouchEvent()方法一旦有事件传递给 ViewonTouchEvent()就会被调用。View 的onTouchEvent()默认都会消耗事件返回 true除非该 View 不可点击clickable和longClickable同时为 false。View 的enable属性不影响onTouchEvent()的默认返回值即使是 disable 状态可点击的 View 仍会消费触摸事件只是不响应。onClick()的发生前提是当前 View 可点击并且收到了 DOWN 和 UP 事件。事件传递过程是由父到子层层分发可以通过requestDisallowInterceptTouchEvent()让子元素干预父元素的事件分发ACTION_DOWN 除外。06. 常见问题延伸onTouch / onTouchEvent / onClick 优先级验证三个方法的回调优先级为onTouch onTouchEvent onClick可通过日志验证场景一onTouch 返回 trueTextView textView findViewById(R.id.tv_13); textView.setOnTouchListener(new View.OnTouchListener() { Override public boolean onTouch(View v, MotionEvent event) { Log.d(yc, 执行了onTouch(), 动作是: event.getAction()); return true; // 消费事件 } }); textView.setOnClickListener(new View.OnClickListener() { Override public void onClick(View v) { Log.d(yc, 执行了onClick()); } });打印结果action 为 0 是 ACTION_DOWN2 是 ACTION_MOVE1 是 ACTION_UP执行了onTouch(), 动作是:0 执行了onTouch(), 动作是:2 执行了onTouch(), 动作是:2 执行了onTouch(), 动作是:1场景二onTouch 返回 false执行了onTouch(), 动作是:0 执行了onTouch(), 动作是:2 执行了onTouch(), 动作是:2 执行了onTouch(), 动作是:1 执行了onClick()结论onTouch()返回 true 就认为该事件被onTouch()消费掉因而不会再继续向下传递即不会执行onClick()。如果设置了 onClickListener 但 onClick() 没有调用可能产生的原因排查清单父 View 拦截了事件没有传递到当前 ViewView 的Enabled falsesetEnabled(false)view 处于不可用状态会直接返回View 的Clickable falsesetClickable(false)/setLongClickable(false)view 不可以点击不会执行 onClickView 设置了onTouchListener且消耗了事件会提前返回View 设置了TouchDelegate且消耗了事件会提前返回。特别提醒onTouch能得到执行需要两个前提条件——mOnTouchListener的值不能为空且当前点击的控件必须是 enable 的源码中为短路与前面条件为 false 将不再往下执行。如果你有一个控件是非 enable 的给它注册 onTouch 事件将永远得不到执行此时必须通过重写该控件的onTouchEvent()方法来监听触摸。07. 扩展阅读本系列姊妹篇本文是 YCBlogs 事件分发系列的第一篇其余主题与本篇互相印证、层层递进View事件机制源码分析从 Activity、ViewGroup、View 三个层次逐段阅读 AOSP 源码剖析FLAG_DISALLOW_INTERCEPT、mFirstTouchTarget、dispatchTransformedTouchEvent()、addTouchTarget()等核心实现细节View滑动冲突处理外部拦截法与内部拦截法的完整伪代码、ScrollView 嵌套 ViewPager 实战案例返回键事件分发流程从 Native 层到 ViewRootImpl、DecorView、Activity 的完整按键分发链路可对照理解触摸事件的系统级输入路径View事件总结案例事件分发高频面试问答与 View 滑动方法layout、scrollTo/scrollBy、Scroller、属性动画、ViewDragHelper汇总AndroidView事件问题14 个 View 事件面试题的问答式整理涵盖分发机制、滑动冲突、GestureDetector、Scroller、SurfaceView 等。赞分享教程技术博客文档【免费下载链接】YCBlogs技术博客笔记大汇总包括Java基础线程并发数据结构Android技术博客等等常用设计模式常见的算法网络协议知识点部分flutter笔记还包括平时开发中遇到的bug汇总当然也在工作之余收集了大量的面试题长期更新维护并且修正持续完善……开源的文件是markdown格式的转载请注明出处谢谢项目地址https://gitcode.com/gh_mirrors/yc/YCBlogs点击查看免费下载相关推荐Flet 事件系统深度解析从 Event 基类到事件分发机制的完整指南Flet 事件系统深度解析从 Event 基类到事件分发机制的完整指南 导读 在 Flet 中几乎所有交互能力都建立在事件Event机制之上点击按钮、前端跨平台桌面应用移动开发Golden Layout事件系统深度剖析从基础事件到冒泡机制的完整解析Golden Layout事件系统深度剖析从基础事件到冒泡机制的完整解析 Golden Layout作为一款功能强大的多窗口布局管理器其事件系统是开发者必须前端UI组件如何快速实现多业务线程池管理DynamicTp完整配置指南如何快速实现多业务线程池管理DynamicTp完整配置指南 DynamicTp是一款轻量级动态线程池框架专为多业务线系统设计通过内置监控告警功能和主流配置后端任务调度可观测性上一篇Legacy-iOS-Kit终极指南3步轻松让旧iPhone/iPad重获新生下一篇Legacy-iOS-Kit终极指南让你的旧iPhone/iPad重获新生的免费开源工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表