Android原生Launcher3伪3D Touch分析

本文分析了Android 8.0 Launcher3中的伪3D Touch功能,它通过长按应用图标模拟3D Touch效果。详细讲解了从长按事件到弹出框显示的整个实现过程,包括关键代码分析和拖拽流程。

伪3D Touch在Android7.1系统上首次推出,只有Shortcut项,在Android8.0上又增加了Notification和System Shortcut两项。由于开发需要,基于Android8.0 Launcher3代码进行分析,并有了这篇文档。如有错误之处,欢迎指出!

3D Touch

  Android的伪3D Touch效果如下图所示。3D Touch是一种立体触控技术,被苹果称为新一代多点触控技术,屏幕可感应不同的感压力度触控。为什么说Android上的是伪3D Touch呢?因为在Launcher3上的实现是通过长按屏幕触发弹出菜单的,并不是以压力传感器为触发点的。

伪3D Touch动态图

  Android实现的伪3D Touch弹出框中实现中有三种类型:System Shorcut、Shortcut、notification,分别如下图所示。System Shortcut包含小部件和应用信息两项;Shortcut则是应用深度定制的快捷方式,可以拖动到桌面;Notification则是通知栏上的通知,可以在弹出框上左右滑动直接删除Notification。当有Notification时,Shortcut最多显示两项,没有Notification时,最多显示4项。

伪3D Touch弹出框

代码实现分析

  Android的伪3D Touch功能的实现是嵌入到原来的桌面拖拽框架中的,由长按应用图标触发启动,桌面(Workspace)长按事件的处理入口放在了Launcher类中,抽屉长按事件的处理入口则在AllAppsContainerView类中,文件夹则在Folder类中。长按应用图标的处理都会调用到Workspace.beginDragShared()函数来启动拖拽流程,故这里只分析从Workspace长按应用图标的实现,另外的两种启动类似,其启动流程时序图如下所示。
伪3D Touch启动流程

  下面从长按事件回调开始详细描述代码实现。当长按的View是应用图标时会执行下面所写Launcher类的代码块,调用Workspace类的startDrag()方法,其中CellInfo记录了应用图标对应的App包括图标位置、包名、等信息,DragOptions是新增加的控制类,主要是用于拖拽过程中与伪3D Touch功能进行交互。接着调用beginDragShared()函数,参数child即点击的应用图标view。关键代码如下:

/**com.android.launcher3.Launcher*/
public boolean onLongClick(View v) {
       ......
       } else {
           final boolean isAllAppsButton =
                 !FeatureFlags.NO_ALL_APPS_ICON && isHotseatLayout(v) &&
                                mDeviceProfile.inv.isAllAppsButtonRank(mHotseat.getOrderInHotseat(
                                        longClickCellInfo.cellX, longClickCellInfo.cellY));
                if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {
                    // User long pressed on an item
                    mWorkspace.startDrag(longClickCellInfo, new DragOptions());
                }
            }
        }
        return 
<think>我们正在处理一个复杂的Android系统开发问题:将Android 11 Launcher3中的手势和多任务功能移植到Android 9的定制Launcher3中。这涉及到两个不同Android版本之间的代码差异和兼容性处理。 根据引用[2]的信息,我们知道Launcher2(旧版Launcher)中关于滑动多屏的代码主要在Workspace类中,但包含了大量其他功能。在Launcher3中,手势和多任务功能可能分布在多个类中。 在Android 11中,手势导航和多任务处理(如最近任务列表)是深度集成的系统功能。要移植这些功能到Android 9,我们需要考虑以下几点: 1. **识别关键类**: - 手势操作可能涉及`TouchController`、`GestureState`等类。 - 多任务处理可能涉及`RecentsView`、`TaskView`等类。 2. **版本差异处理**: - Android 9(API 28)和Android 11(API 30)在系统API和框架上存在差异。我们需要确保在移植过程中处理这些差异,可能通过条件编译或反射。 3. **依赖注入**: - Launcher3Android 11中可能使用了新的依赖注入框架(如Hilt),而Android 9的Launcher3可能没有。需要调整依赖管理方式。 4. **资源文件**: - 布局、动画等资源文件需要一并移植,并确保兼容性。 5. **权限和系统服务**: - 手势和多任务功能可能依赖特定的系统服务,需要检查权限和系统API的可用性。 **移植步骤建议**: 1. **获取源代码**: - 分别获取Android 11和Android 9的Launcher3源代码。 2. **功能模块分析**: -Android 11的Launcher3中,定位手势和多任务功能的相关代码。重点关注以下包: - `com.android.launcher3.uioverrides`(可能包含手势相关重写) - `com.android.launcher3.touch`(触摸事件处理) - `com.android.quickstep`(多任务处理,快速切换) 3. **逐步移植**: -Android 11中与手势和多任务相关的类、资源文件复制到Android 9项目中。 - 注意调整包名和导入语句。 4. **解决兼容性问题**: - 使用`Build.VERSION.SDK_INT`进行条件判断,对于Android 11新增的API,在Android 9上提供替代实现或降级处理。 - 例如,如果使用了`WindowInsetsController`(Android 11新增),则在低版本上使用`View.setSystemUiVisibility()`。 5. **测试与调试**: - 由于涉及触摸事件处理(引用[2]提到触摸事件处理不同),需要仔细测试手势的响应。 - 使用日志和调试工具定位问题。 **示例代码片段(条件编译)**: ```java // 在移植的代码中处理版本差异 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // 使用Android 11的API WindowInsetsController controller = view.getWindowInsetsController(); if (controller != null) { controller.hide(WindowInsets.Type.systemBars()); } } else { // 低版本兼容 view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); } ``` **注意事项**: - 引用[1]提到触摸事件处理在不同版本可能有差异,需要特别注意。 - 引用[3]提到图形渲染(OpenGL ES)的差异,但手势和多任务功能主要涉及触摸事件和动画,可能不直接涉及3D渲染,除非有复杂的动画效果。 - 引用[4]提到Flutter的热重载特性,但我们的项目是原生开发,不适用。 **潜在挑战**: - Android 11的手势导航是系统级集成,可能需要修改框架层(framework)代码,而Launcher3通常运行在应用层。因此,完全移植系统级手势可能不可行,但可以尝试在Launcher内部实现类似的手势效果。 - 多任务处理(最近任务列表)在Android 11中可能依赖系统服务(如ActivityTaskManager),在Android 9上可能无法直接使用,需要寻找替代方案。 **替代方案考虑**: - 如果直接移植困难,可以考虑在Android 9上实现类似的手势交互,但功能上可能无法完全一致。 **结论**: 移植工作复杂,需要对Launcher3的架构和两个Android版本都有深入了解。建议分模块逐步移植,并做好兼容性处理。 §§相关问题§§ 1. Android 11 Launcher3中手势导航的具体实现类有哪些? 2. 如何在不同Android版本上实现条件编译? 3. 在移植过程中如何处理资源文件的兼容性问题? 4. Android 9上是否有替代Android 11多任务处理API的方案?</think>要将Android 11的Launcher3中的手势操作和多任务功能移植到Android 9的定制Launcher3项目,需遵循以下步骤: ### 1. **识别关键代码模块** - **手势操作**:主要位于`TouchController`相关类(如`LauncherTaskController`)和手势识别逻辑中 - **多任务处理**:集中在`RecentsView`、`TaskView`及相关动画控制器(如`RecentsAnimationController`) - **系统集成**:需检查`QuickstepProcessManager`等系统交互类[^2] ### 2. **版本兼容性处理** ```java // 使用条件编译处理API差异 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+ 的手势API getSystemService(WindowManager.class).getMaximumWindowMetrics(); } else { // Android 9 替代方案 display.getRealMetrics(metrics); } ``` ### 3. **核心移植步骤** - **手势模块移植**: 1. 复制`src/com/android/launcher3/touch`包下的触摸事件处理类 2. 修改`Workspace.java`中的`onInterceptTouchEvent()`方法接入新手势逻辑 3. 调整触摸阈值参数适配不同设备(引用[2]提到触摸事件差异) - **多任务模块移植**: 1. 复制`quickstep`包下的Recents相关类 2. 重写`RecentsView`的滑动逻辑: ```java // 示例:任务卡片滑动处理 protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); // 添加Android 9兼容的滚动逻辑 } ``` 3. 移植任务缩略图生成机制(需处理Android 9的`ActivityManager` API差异) ### 4. **依赖项处理** - 在`build.gradle`中添加必要依赖: ```gradle dependencies { implementation &#39;androidx.dynamicanimation:dynamicanimation:1.0.0&#39; // 手势动画 implementation &#39;com.android.support:recyclerview-v7:28.0.0&#39; // 多任务列表 } ``` - 同步资源文件:复制`res/animator`下的手势动画资源 ### 5. **兼容性测试重点** - 手势冲突检测:测试与现有功能(如文件夹展开)的触摸事件冲突 - 多任务内存管理:验证`onTrimMemory()`的低内存处理 - 动画性能优化:使用OpenGL ES加速(引用[3]的硬件加速方案) ### 6. **调试技巧** - 启用手势日志: ```java if (DEBUG_TOUCH) Log.d(TAG, "Touch event: " + MotionEvent.actionToString(event)); ``` - 使用`adb shell dumpsys activity recents`检查多任务状态 > **难点注意**:Android 11的`WindowInsets`API在Android 9不可用,需用`View.getLocationOnScreen()`替代。系统级手势(如底部横滑)需修改`frameworks/base`层,这在定制ROM中才可实现[^1][^2]。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值