多屏联动 - 动画

基于Android R版本分析

参考:车载多屏互动联动动画版本同屏幕大小情况方案设计

实现双屏联动的效果,需要关注两个部分:

  • 手势识别;
  • move stack进行移栈操作;

手势识别

基于原生手指识别的基础上,我们新定义自信的手指识别,例如:在3指滑动的情况下,实现Task move的操作;

实现方案

  • 单独创建一个PointerEventListener的实现类,该实现类用于处理3指滑动的逻辑;
  • 将该监听注册到DisplayContent中,这样每一个DisplayId都会对应一个PointerEventListener,每一个屏幕都可以响应3指滑动;

核心点

  • 当前场景是否处于3指滑动, 针对非3指滑动场景下也需要进行处理;

  • MotionEvent.ACTION_DOWN、MotionEvent.ACTION_POINTER_DOWN、MotionEvent.ACTION_MOVE、MotionEvent.ACTION_POINTER_UP、MotionEvent.ACTION_UP 5个Event的响应;

  • 开启move stack的临界值判断,例如:滑动间距 >= 10px时,触发move stack;

  • 结束3指滑动之后,Task自动move的临界值判断,例如:

    • 当move 间隔 >= 100px时,Task向右侧/左侧滑动,代表move stack成功;
    • 当move 间隔 < 100px时,Task向右侧/左侧滑动,代表move stack未成功,Task自动回位;
  • 主副屏的判断(默认主屏在左 ,副屏在右),例如:

    • 主屏Task向副屏滑动时,主屏Task不能向左滑动,滑动过程中也不允许主屏Task向左滑动;
    • 副屏Task向主屏滑动时,主屏Task不能向右滑动,滑动过程中也不允许副屏Task向右滑动;

move stack

移栈的操作,最核心的逻辑就是move stack,该接口的版本迭代:

  • Android O 提供了moveStackToDisplay能力,在DisplayContent中实现;
  • Android O ~ Android Q,该接口一致又DisplayContent提供;
  • Android R开始,新增了RootWindowContainer类,moveStackToDisplay接口移植到RootWindowContainer中实现;
  • Android S 开始,该接口名称修改为了moveRootTaskToDisplay ,Android T沿用moveRootTaskToDisplay;
核心点

在Android R版本中使用时,需要对比Android S ~ Android T的moveRootTaskToDisplay接口逻辑,各版本之间的实现逻辑上有一点的差异性;

双屏双图层

我们知道,在启动应用的时候,不会启动多个相同的应用进程,即无论存在多少个屏幕,同一个应用进程只会启动一个;那么对应的Task要不在Display 0显示,要不在Display 1中显示,无法做到两个屏幕同时显示同一个应用进程;

需要解决Display 0和Display 1同时显示Task画面;

实现方案

在Android R 及之后,在SurfaceControl提供了mirrorSurface接口:

java 复制代码
/**
  * Creates a mirrored hierarchy for the mirrorOf {@link SurfaceControl}
  *
  * Real Hierarchy    Mirror
  *                     SC (value that's returned)
  *                      |
  *      A               A'
  *      |               |
  *      B               B'
  *
  * @param mirrorOf The root of the hierarchy that should be mirrored.
  * @return A SurfaceControl that's the parent of the root of the mirrored hierarchy.
  *
  * @hide
  */
public static SurfaceControl mirrorSurface(SurfaceControl mirrorOf) {
    long nativeObj = nativeMirrorSurface(mirrorOf.mNativeObject);
    SurfaceControl sc = new SurfaceControl();
    sc.assignNativeObject(nativeObj, "mirrorSurface");
    return sc;
}

Animator move

动画滑动的效果,本质上就是Task的偏移;

实现方案

滑动动画的实现方案:Matrix + SurfaceControl.Transaction

Matrix是Android中一个重要的类,提供了一些矩阵变换的方法,可以实现图形的缩放、旋转、平移和倾斜等操作;

start move

Display 0画面移动情况:

  • Display 0是接受了3指触摸的右边移动了offsetX的距离,这时候屏幕Display 0的Task画面也要跟着向右平移offsetX;

Display 1画面移动情况:

  • Display 1的Task画面应该最右边往左边有offsetX的画面,所以左边原点相对屏幕偏移距离就应该是 -(width - offsetX),这里应该是负数,因为屏幕最左边才是0;
Auto move

PointerEvent结束之后,Task画面并不是已经完全移动到另一个人屏幕中,Task画面大概念横跨两个屏幕,这样就需要判断Task auto move的临界值;

总结

在实现过程中,需要关注的几个点:

  • 在move主屏的Task至副屏之后,主屏/副屏的界面实现不能为黑屏状态;
  • 针对不同屏幕分辨率的时候,需要新增Scale操作;
  • 针对不同屏幕density的时候,需要考虑解决方案;
  • 在移栈的时候,有可能会出现黑屏闪烁的情况,这个问题需要调研(Activity重建导致的);

针对size和density不一致问题,需要在应用模块AndroidManifest.xml中新增属性:

ini 复制代码
android:configChanges="density|screenSize|smallestScreenSize"
  • density:像素密度
  • screenSize:屏幕大小
  • smallestScreenSize:屏幕的物理大小改变(可选)
相关推荐
cynicism??8 小时前
Linux 与 ZXISOS 驱动开发架构对比
linux·驱动开发·架构
聪明蛋子哟9 小时前
高扩展性AI应用架构指南:融合RAG检索、Agent编排与OpenAPI/RPC工具网关的设计模式
人工智能·rpc·架构
恋猫de小郭9 小时前
感人,Flutter 居然有了一个超实用提案,期待落地
android·前端·flutter
CS_Zero9 小时前
安卓开发:Linux的android工具命令
android·linux·运维
Kari119 小时前
Dify多租户架构:从单团队到SaaS化服务
大数据·人工智能·架构
fellow9910 小时前
DSH Desktop - Android Edition
android·agent·deepseek·harness·dsh
Carson带你学Android10 小时前
Android Studio Rabbit 2 发布:除了Gemini,40+ AI Agent 正式入驻!
android·ai编程
vortex510 小时前
Windows Server IIS 运维配置指南:架构、身份、安全与排障
运维·windows·架构
mldong10 小时前
工作流引擎的退回修改:金额从 6666 改成 666,重提还是回到退回它的那个人
后端·架构
海宇服务20 小时前
零信任架构实战:基于海宇全能小微企业报告构建自动化园区商户免押租赁资信核验网关
大数据·人工智能·架构·自动化