多屏联动 - 动画

基于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 开始,该接口名称修改为了moveRootTaskToDisplayAndroid 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:屏幕的物理大小改变(可选)
相关推荐
短剑重铸之日2 分钟前
《ShardingSphere解读》12 解析引擎:SQL 解析流程应该包括哪些核心阶段?(下)
数据库·后端·sql·架构·shardingsphere·分库分表
qq_283720052 分钟前
MySQL技巧(三):慢查询开启与分析优化案例
android·adb
假如梵高是飞行员3 分钟前
角色设定对大模型表现的影响:对不同架构的对比分析
架构
常利兵4 分钟前
从Groovy到KTS:Android Gradle脚本的华丽转身
android
穷人小水滴4 分钟前
使用 WebRTC 实现局域网投屏: PC (GNOME ArchLinux) -> 平板 (Android)
android·linux·webrtc·浏览器·js·gnome·投屏
zh_xuan5 分钟前
Android compose 无限滚动列表
android
诸神黄昏EX7 分钟前
Android Binder 系列专题【篇六:自定义AIDL HAL进程】
android
Fate_I_C9 分钟前
Android现代开发:Kotlin&Jetpack
android·开发语言·kotlin·android jetpack
Densen201410 分钟前
[.NET 9] BlazorWebView 无法在较旧的 Android 设备上加载, 附临时解决方法
android
泯泷10 分钟前
阶段二:为什么先设计指令集,编译器和运行时才能稳定对齐?
前端·javascript·架构