ViewOverlay 是存在于API 18+(Android 4.3)内的类,它是位于View视图层顶部的一个附加层,在View所有内容绘制完成后被绘制。 ViewGroupOverlay 是ViewOverlay的子类,对应于ViewGroup,同样地,这个层在ViewGroup中所有内容(包括childView)绘制完毕后才会被绘制。这个层和我们的View拥有同样的尺寸,可看做浮在View上方的一个二维空间。
Overlay对象可通过 View.getOverlay()
或 ViewGroup.getOverlay()
方法获得,获得Overlay对象后,就可以通过add、clear和remove方法操作其中的元素,这也是Overlay仅有的几个方法。
从表面上看,任何ViewOverlay能做到的事情,都可以使用FrameLayout之类来实现,但ViewOverlay是一种更友好的实现方式。其中很重要的一点是ViewOverlay仅仅是可见的。ViewOverlay中容纳的View或Drawable不会响应任何的触摸事件,因此ViewOverlay非常适合用于动画或制作一些不需要直接接受交互的浮层。
利用ViewGroupOverlay可以让某个View在任意Layout区域内播放动画,而不管Layout是否是这个View的Parent。当一个View被add到ViewOverlay内时,如果它的Parent不为null,则它会先被从它的Parent中移除。
这里通过一个给View的content、padding和margin区域添加颜色的例子来说明ViewOverlay的用法,各区域的颜色遵循Chrome DevTools内各元素高亮的配色。
由于View的margin区域并不包含在其自身的绘制范围内,要绘制margin区域,必须把View的画布先做扩展。此处我们已经事先获取到了四个方向上的margin值。所有的蒙层区域均通过 ColorDrawable
对象实现。
@Override public void draw(Canvas canvas) { Rect newRect = canvas.getClipBounds(); newRect.inset(-(mMargins.right + mMargins.left), -(mMargins.top + mMargins.bottom)); canvas.clipRect(newRect, Region.Op.REPLACE); super.draw(canvas); }
获取View各个方向上的margin和padding值,依次创建四个方向上的ColorDrawable对象。
for (HighlightDrawable drawable : drawables) { drawable.highlightView(view); view.getOverlay.add(drawable); }
上文说过,使用ViewGroupOverlay可以让不属于一个ViewGroup的View在其区域内显示,此处演示在parent之外的区域播放动画来说明ViewGroupOverlay的作用。
ObjectAnimator anim = ObjectAnimator.ofFloat(x, "translationX", 0, right.getWidth() * 2); anim.setDuration(2000); right.getOverlay().add(x); anim.start(); anim.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { right.getOverlay().remove(x); } @Override public void onAnimationCancel(Animator animation) { right.getOverlay().remove(x); } });
在调用 ViewGroupOverlay.add()
方法的时候,View x会从原有的parent中被移除,并添加到目标ViewGroup的Overlay中。