自定义视图缩小:之前占用的空间没有被清除

Posted

技术标签:

【中文标题】自定义视图缩小:之前占用的空间没有被清除【英文标题】:Custom view shrinking: previously occupied space is not cleared 【发布时间】:2015-10-26 16:41:17 【问题描述】:

在自定义视图中,OnMeasure和OnSizeChanged分别用于设置intrisic尺寸和获取最终尺寸。

在 OnDraw 中,使用当前的宽度/高度绘制可绘制对象。

现在,如果视图被告知要更改其内部大小,它将请求布局。这会触发 OnMeasure/OnSizeChanged,最后触发 OnDraw。 它工作正常,drawable 总是使用正确的内部尺寸显示。

问题是,如果新的内部尺寸比旧的小,android会离开旧的绘图(它似乎在新的“下方”,但实际上应该已经被android清除了)。

我试图清除 OnDraw 中的视图内容,但绘图矩形已被裁剪为新的视图大小。

这听起来像是 LinearLayout 中的一个错误,当孩子的视图尺寸缩小时不会清除其内容。在 Android 4.4 / Samsung S3 4G / CyanogenMod cm-11-20151004-NIGHTLY 上进行测试。

布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content"
android:orientation="vertical"
android:layout_
android:layout_
android:background="#000000"
android:padding="8dp">
<LinearLayout
    android:orientation="horizontal"
    android:id="@+id/content"
    android:layout_
    android:layout_
    android:layout_weight="1"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="8dp"
    android:gravity="top">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_
        android:layout_
        android:background="#CCD39F">
        <MyCustomView
            android:id="@+id/myview"
            android:layout_
            android:layout_ />
    </LinearLayout>
</LinearLayout>

更新自定义视图大小后我看到的内容。应该只显示“黑色部分”,而不是白色部分。

应该是这样的:

【问题讨论】:

你能在不同的设备上试试吗?您也可以尝试将LinearLayout 替换为RelativeLayout 等其他布局。只是想隔离问题。还有Only the "black part" should be displayed, not the white one.是什么意思 【参考方案1】:

我发现了问题和解决方法。 真正的问题在于LinearLayout。从 Android 4.0.3 到 Android 6。当这个垂直线性布局的 weight=1 和 height=0dp 时,它只有一个高度小于可用高度的孩子。这个孩子第一次画,没问题。如果这个孩子的高度缩小,它下面的区域不会重新绘制。所以它会保留第一个孩子的旧内容,而不是用布局背景颜色重新填充。

在下面的布局代码中,我演示了问题和解决方案。解决方案是添加第二个孩子,它将占用第一个孩子下方的剩余可用空间。使用这种技术,当第一个孩子缩小,第二个孩子扩大并且新的“空”空间被正确重绘时,它可以按预期工作。

所以这确实是 LinearLayout 的一个 bug。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    android:background="#000000">
    <LinearLayout
        android:orientation="vertical"
        android:layout_
        android:layout_
        android:layout_weight="1"
        android:gravity="top">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_
            android:layout_
            android:background="#CCD39F">
            <MyCustomView
                android:id="@+id/icon"
                android:layout_
                android:layout_ />
        </LinearLayout>
        <!-- Solution. To see the problem, remove the following layout -->
        <LinearLayout
            android:orientation="vertical"
            android:layout_
            android:layout_
            android:layout_weight="1"
            android:background="#111111" />
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_
        android:layout_
        android:gravity="right">
        <Button
            android:text="Other demo"
            android:layout_
            android:layout_
            android:id="@+id/btnNextImage" />
        <Button
            android:text="Next SVG"
            android:layout_
            android:layout_
            android:id="@+id/btnGoEmpty" />
    </LinearLayout>
</LinearLayout>

【讨论】:

以上是关于自定义视图缩小:之前占用的空间没有被清除的主要内容,如果未能解决你的问题,请参考以下文章

自定义导航栏 titleView 在加载新标题之前不会清除以前的标题

带有集群和自定义视图标记的谷歌地图在放大和缩小时滞后太多

锚约束缩小超视图而不是放大子视图

Zend Framework - 从视图脚本中清除自定义占位符

自定义相机视图预览层加上大小的手机问题

DATAGridViewCell 自定义视图按钮操作方法没有被调用?