学习android framework有一段时间了,感觉有必要实战一个复杂点的功能来巩固一下学到的东西。于是就仿照自己手上华为nova 8 pro的自由窗口最小化效果,做了一下,过程还是挺漫长的,终于做出来了,下面是完整的效果:
自由窗口最小化完整效果
效果概述:
1.点击最小化按钮后,侧边栏会出现一个悬浮球。悬浮球可以随意拖动,但松手后会靠边。
2.每当一个自由窗口最小化后,都会更新悬浮球上的logo
3.只允许出现一个自由窗口,新的自由窗口或进入最近任务页面都会触发已有的自由窗口最小化
4.点击悬浮球出现的自由窗口会有一个放大的动画;点击最小化按钮会有一个逐渐缩小的动画。
5.当最小化的自由窗口大于等于2个时,点击悬浮球会展示已最小化的窗口列表,且背景是模糊的。
6.太多细节就不赘述了。。。
遇到的问题分享
实现的过程中遇到了太多的问题,但都解决了。这里就挑两个问题分享一下:
1.最小化按钮
我在加这个最小化按钮的时候,需要修改DecorCaptionView的布局文件,这就涉及到了修改frameworks/base/core/res/res目录下的文件。而修改这个文件下的内容时(添加id,layout,drawable,style等),注意,需要在frameworks/base/core/res/res/values/symbols.xml中添加对应的<java-symbol>标签。否则,编译会报错:cannot find symbol
另外,感觉修改frameworks/base/core目录下的东西,哪怕修改一点点,都会编译很长时间。所以,以后应该注意尽量不要改这个目录下的内容吧。
2.SurfaceControl.Transaction的setCrop()方法
在做窗口的缩小动画时,分两步:1 把画面渐渐裁成一个正方形 2 把正方形缩小平移到悬浮球位置。第一步时裁剪出了问题,请看慢动作回放:
发现一开始顶部就突然少了一部分,这就导致变成正方形时,看上去logo并没有居中。
其实是因为setCrop(SurfaceControl sc,Rect rect)这个方法中第二个参数rect应该是相对task的坐标而不是绝对坐标。看图,假如task在屏幕的区域为(0,100)-(1440,2500)
那如果想完整地把task内容裁出来,就需要这样:
t.setCrop(task.getSurfaceControl,new Rect(0,0,1440,2400));
而不是这样:
t.setCrop(task.getSurfaceControl,new Rect(0,100,1440,2500));
再比如,如果想要裁剪task的左上角一块边长100的正方形,不论task位置在何处,只需要这样:
t.setCrop(task.getSurfaceControl,new Rect(0,0,100,100));
了解了这个,修改后的完整动画如图:
总结
其他细节实现:
1.动画过程中,画面上的logo实现方案参考的时app启动时的addStartingWindow
2.悬浮球,侧边栏都是直接add的TYPE_APPLICATION_OVERLAY窗口
未实现的或待改进的:
1.放大缩小动画根据task画面和悬浮球的相对位置不同而不同
2.悬浮球拖动到底部某一区域,移除全部的最小化task。感觉可以参考pip的类似功能
3.还是有非必现的闪退bug
4.现在实现代码都写在systemServer里,感觉应该写到systemUI里是不是更好
最后,要感谢一下马哥在我framework学习过程中给予的帮助,在开发过程中大部分问题的解决思路也都是从马哥那里学到的,最终实现的这个自由窗口最小化功能虽然还有问题,但还是很开心的。