一、ViewOverlay能实现什么?
在Android中,ViewOverlay是一个特殊的视图层,可以在一个视图的上方添加和管理附加的视图层,而不会干扰原始视图的布局和交互。它提供了一种方便的方式来在运行时添加、移除或修改视图层,而无需修改原始布局。
二、基础用法
2.1 一个简单案例
比如我们想给一张图片加一张蒙层效果,蒙层颜色是#cc000000,那可以这样很简单的实现:
val imageView = findViewById<AppCompatImageView>(R.id.image_view)
val colorDrawable = ColorDrawable(Color.parseColor("#cc000000"))
button.setOnClickListener {
// 完全盖住ImageView
colorDrawable.setBounds(0, 0, imageView.measuredWidth, imageView.measuredHeight)
imageView.overlay.add(colorDrawable)
}
原始图片效果:
添加蒙层效果:
移除蒙层效果:
imageView.overlay.remove(colorDrawable)
2.2 overlay.add(drawable)/groupOverlay.add(view)之后,不显示问题解决
2.2.1 add(Drawable)方法
如果直接将Drawable对象添加到imageView.overlay.add()没有setBounds则会因为Drawable没有宽高而无法展示,宽高可能为0,需要主动调用setBounds指定drawable的宽高。
2.2.1 add(View)方法
而对于add(View)来说(需要通过ViewGroup类型的容器对象getOverlay()),就需要给需要添加的view通过setLayoutParams的方式指定宽高才能展示。
注意View和ViewGroup的getOverlay方法实现的差异,是和ViewGroup有addView()而View没有是一样的道理。
- ViewGroup->getOverlay()返回ViewGroupOverlay类型对象,能添加view的浮层,也能添加drawable
@Override
public ViewGroupOverlay getOverlay() {
if (mOverlay == null) {
mOverlay = new ViewGroupOverlay(mContext, this);
}
return (ViewGroupOverlay) mOverlay;
}
- View->getOverlay()返回ViewOverlay类型对象,无法addView(),只能添加drawable对象
public ViewOverlay getOverlay() {
if (mOverlay == null) {
mOverlay = new ViewOverlay(mContext, this);
}
return mOverlay;
}
特别的如果添加TextView,因为不同字体、大小都会导致宽高不同,所以预先无法知道,这时候就需要StaticLayout.getDesiredWidth()方法获取文本需要的宽高,然后设置给TextView。
测试代码:
val tv = TextView(this)
tv.text = "是神仙姐姐呀~"
val desiredWidth = StaticLayout.getDesiredWidth(
tv.text,
tv.paint // 注意这里的画笔对象,要tv.getPaint(),否则可能测量值偏差较大
)
Log.d(TAG, "onCreate: desiredWidth = $desiredWidth")
tv.isSingleLine = true
tv.maxLines = 1
tv.layoutParams =
ViewGroup.LayoutParams(desiredWidth.toInt(), ViewGroup.LayoutParams.WRAP_CONTENT)
// View的overlay对象是不能addView()的,这里从ImageView的父布局添加,仅为测试效果
(imageView.parent as? ViewGroup)?.addView(tv)
效果:
三、最后
通过overlay方式添加view层级通过抓布局可以看到,原理其实也是增加了布局层次,但是操作比较简单高效。