Launcher3 OverviewMode和mInsets

来源:互联网 发布:淘宝2017双11广告视频 编辑:程序博客网 时间:2024/06/06 01:20

OverviewMode

OverviewMode

Launcher3里,在Workspace界面长按空白处,桌面进去OverviewMode,查看源码:Launcher类实现了View.OnLongClickListener接口,可以看到在onLongClick方法中有这么一句:

mWorkspace.enterOverviewMode();

这句代码在onLongClick方法中出现了两次:

  • 在长按的view为Workspace且当前不在OverviewMode模式
  • 长按的地方为Hotseat图标外的空白地方时,且当前不在拖动状态和OverviewMode下

退出OverviewMode的方法是exitOverviewMode,通过查看这两个方法,它们都调用了enableOverviewMode方法。
看一下enableOverviewMode方法,这一句比较重要:

Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);

如同对象名workspaceAnim,这句代码是取得Launcher3在各种状态之间变化时的动画,Workspace中有一个enum State,代表桌面的各种状态,OverviewMode时State为State.OVERVIEW,显示Workspace时状态为State.NORMAL,getChangeStateAnimation方法第一个参数就是桌面即将进入的状态。

getChangeStateAnimation方法比较重要,在桌面在各种状态之间变化时都会调用,这里看一下进入OverviewMode的动画:一开始经过新老状态boolean的判断,决定背景透明度(finalBackgroundAlpha)、Hotseat和PageIndicator透明度(finalHotseatAndPageIndicatorAlpha)等相关属性的设定和当前进行的状态改变。然后取得桌面上各种“拼图”:SearchBar,HotSeat,PageIndicator等对象并进行各种动画效果,比如scale就是Workspace对象的缩放动画。

LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);scale.scaleX(mNewScale)     .scaleY(mNewScale)     .translationY(finalWorkspaceTranslationY)     .setDuration(duration)     .setInterpolator(mZoomInInterpolator);anim.play(scale);...

mInsets

在计算动画时各对象的属性变化中,关于透明度,缩放的值的计算比较简单,但是位置的计算通常要从DeviceProfile中取得信息计算而来,比如Workspace缩放后的TranslationY在OverviewMode下由Workspace的getOverviewModeTranslationY方法得来。

看这个方法使用到了mInsets对象,看源代码时一直想不明白这个值的意义,上网搜索后才恍然大悟,可以参考这里:LauncherRootView和DragLayer的布局过程。
这个网址打开较慢,摘录一下相关的:

在主布局launcher.xml中, 最外层是LauncherRootView。
我们发现它只是重写了一个方法, View.fitSystemWindow(rect), 那这个方法是干什么的呢?查了官方文档,还是看不懂他到底是做什么的,但是倒是会用了。如果你的View在status bar或者navigation bar之下,那么这个方法会传递进去一个参数,说明这个View的四周有多少是被status bar或者navigation bar挡住了的。这个方法的会调用父类的setInsets()方法,我们来看看父类InsettableFrameLayout。

InsettableFrameLayout继承了FrameLayout, 并且实现了父类的一些方法,总的来说,他的目的就是给子View都设定一个Margin值,防止被status bar或者navigation bar挡住。如果一个View已经是Insettable的了,那么就忽略他。在Launcher3中,Workspace, DragLayer和AppsCustomizeTabHost都实现了这个接口,那么他们自身就不会被加Margin, 而搜索栏和Hotseat都没有实现这个接口,那么说明他们在被加到父亲上得时候会被设一个Margin,最后的到得效果就是搜索栏刚好在status bar之下(gravity为top,topmargin是statusbar的高度),Hotseat刚好在navigationbar的上方(gravity为bottom,bottomMargin为navigation bar的高度)。

可以看一下InsettableFrameLayout的setFrameLayoutChildInsets方法

public void setFrameLayoutChildInsets(View child, Rect newInsets, Rect oldInsets) {        final LayoutParams lp = (LayoutParams) child.getLayoutParams();        if (child instanceof Insettable) {            ((Insettable) child).setInsets(newInsets);        } else if (!lp.ignoreInsets) {            lp.topMargin += (newInsets.top - oldInsets.top);            lp.leftMargin += (newInsets.left - oldInsets.left);            lp.rightMargin += (newInsets.right - oldInsets.right);            lp.bottomMargin += (newInsets.bottom - oldInsets.bottom);        }        child.setLayoutParams(lp);    }

child是当前类的子类,如果其不是Insettable的子类,fitSystemWindow方法中传进来的Rect就会当成Margin值加到LayoutParams中, 由于InsettableFrameLayout继承了FrameLayout,加了这些Margin的View可以保证自己至少不会被状态栏和导航栏遮挡。

如果child没有继承Insettable,如Workspace。Workspace重写了setInsets方法,将fitSystemWindow方法传递进来的mInsets给自己的mInsets,这样在计算布局的时候(例如上面提到的Workspace的getOverviewModeTranslationY方法),就可以考虑到状态栏和导航栏的影响了。

1 0
原创粉丝点击