Android | 通过 layer-list 设置默认加载错误图片

背景

在需求开发中,经常会遇到需要展示图片列表的情况。然而,由于网络问题、图片链接失效等原因,某些图片可能无法正常加载。为了优化用户体验,通常会为加载失败的图片提供一个默认的占位图。

在常规的实现方式中,可能会直接使用一张默认图片来作为占位图(如果是个单色图,可以直接用一个drawable文件)。然而,如果图片列表里每个Item宽高比都是变化的时候,默认图片会因为宽高比不同而导致变形,虽然可以通过 ImageView 的 scaleType 设置 CENTER_CROP 以适应不同的图片比例不变形,但如果默认图片本身包含一个居中的小图标,在不同的宽高比下,小图标的显示效果可能会变形或错位。

问题分析

假设我们的默认错误图片是如下所示的样式(背景色 + 一个居中的错误图标):

如果我们将其合成一张完整的 PNG 图片并使用 CENTER_CROP 适配不同的 ImageView 尺寸,可能会遇到两个问题: 1. 小图标会跟随图片裁剪,可能会放大、变形,导致显示不一致。 2. 不同比例的 ImageView 会截取不同区域,导致小图标的位置和大小不可控。

为了解决这个问题,可以换一种思路,利用 layer-list 来动态组合背景和图标,从而确保小图标始终保持固定大小和居中位置。

解决方案:使用 layer-list

在 drawable 资源中,layer-list 允许我们叠加多个图层,可以将背景和图标分开定义,保证不同尺寸的 ImageView 显示时,背景始终铺满,而小图标始终居中,且不会因裁剪而变形。其中小图片的资源如下:

  • 创建 layer-list 资源文件

在 res/drawable/ 目录下创建 drawable_default_error.xml:

kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 背景矩形 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/gray_normal" /> <!-- 设置背景颜色 -->
        </shape>
    </item>

    <!-- 居中的错误图标 -->
    <item
        android:width="60dp"
        android:height="60dp"
        android:gravity="center">
        <bitmap
            android:gravity="center"
            android:src="@drawable/chat_ask_message_error" />
    </item>
</layer-list>
  • 代码中使用 layer-list

在使用 Glide 或其他图片加载框架时,我们可以直接将 drawable_default_error.xml 作为 placeholder 和 error 资源:

kotlin 复制代码
Glide.with(activity)
    .load(url)
    .placeholder(R.drawable.drawable_default_error) // 加载中显示的占位图
    .error(R.drawable.drawable_default_error) // 加载失败时显示的默认图
    .into(imageView)

效果展示

当图片加载失败时,ImageView 会显示 drawable_default_error.xml 组合的背景 + 图标,效果如下:

相比直接使用一张完整的 PNG 图片,layer-list 方案的优点:

  • 保证背景始终填充整个 ImageView,不会因为 scaleType 而变形。
  • 小图标始终保持固定大小,居中不变形,适应不同的 ImageView 尺寸。
  • 支持动态调整背景色或小图标,无需重新制作整张图片,维护更方便。

总结

在 Android 开发中,layer-list 是一个非常实用的 Drawable 资源,它可以将多个层叠的图形、颜色、图片等组合在一起,实现复杂的视觉效果。在需要为加载失败的图片提供占位图时,使用 layer-list 可以保证背景填充、图标居中且不会变形。

相关推荐
杉氧3 分钟前
打破边界(二):在 React Native 中嵌入原生 UI 组件 (Native UI Components)
android·前端·react native
古法安卓38 分钟前
Android-切换白天黑夜内存不足问题排查
android·java·android studio
聚美智数42 分钟前
快递拦截-物流在途拦截-在途拦截API接口介绍
android
flower_drop1 小时前
从 QtScrcpy 到 TabQA:如何在浏览器侧边栏搞定 Android 投屏与测试提单?
android
脚踏实地,坚持不懈!2 小时前
Android 系统工程师(性能/功耗/稳定性)岗位问题深度解析:从内核源码到实战排查(完善版)
android·linux·运维·服务器
Kapaseker2 小时前
适配小米“中”折屏,非得买一台吗
android·kotlin
恋猫de小郭3 小时前
Flutter 状态管理基准测评,一个很有趣的观点
android·前端·flutter
可乐鸡翅yeah_3 小时前
App WebView 加载 M3U8 流媒体踩坑,安卓 iOS 混合开发播放异常定位
android·ios·harmonyos·m3u8·m3u8在线播放
木卫四科技3 小时前
从函数劫持到智能体控制平面:Hook 如何从 Linux-Android 演化到 Agent Runtime
android·linux·人工智能·安全
菠萝加点糖3 小时前
Android applicationIdSuffix 详解
android·gitee·kotlin