Android TextView图标对齐优化:使用LayerList精准控制drawable位置

背景

我们经常使用TextView的drawableStartdrawableEnd等属性来为文字添加图标。但有时会遇到这样的问题:

xml 复制代码
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:drawableStartCompat="@drawable/icon_left_arrow"
    android:includeFontPadding="false"
    android:drawablePadding="2dp"
    android:text="我是文字"
    android:textColor="@color/red"
    android:textSize="18sp" />

执行结果:

当图标尺寸大于或小于文字高度时,有时会出现图标位置偏移、视觉不居中的问题,而XML中又没有直接调整图标上下位置的属性,这时候该咋办呢?

:上述效果也可以通过代码来实现,XML中不再设置drawableXXX等属性:

ini 复制代码
<TextView
    android:id="@+id/tv_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="我是文字"
    android:includeFontPadding="false"
    android:textColor="@color/red"
    android:textSize="18sp" />

代码中动态设置:

kotlin 复制代码
//扩展函数
fun TextView.setLeftDrawable(leftDrawableRes: Int, widthInDp: Int = 10, heightInDp: Int = 10) {
    val drawable = ContextCompat.getDrawable(context, leftDrawableRes)

    val scale = context.resources.displayMetrics.density
    val widthPx = (widthInDp * scale + 0.5f).toInt() //dp to px
    val heightPx = (heightInDp * scale + 0.5f).toInt() //dp to px
    drawable?.setBounds(0, 0, widthPx, heightPx)
    compoundDrawablePadding = (2 * scale + 0.5f).toInt() //设置padding
    setCompoundDrawables(drawable, null, null, null)
}

//使用
mTvText.setCenteredDrawable(R.drawable.icon_left_arrow, 6, 10)

执行效果同上。

优化方式

方案1:分成两个控件

ini 复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginEnd="2dp"
        android:src="@drawable/icon_left_arrow" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:includeFontPadding="false"
        android:text="我是文字"
        android:textColor="@color/red"
        android:textSize="18sp" />
</LinearLayout>

执行结果:

把箭头单独拆成一个控件来处理,如果不居中还可以自由调整。

方案2:使用LayerList来控制(推荐)

LayerList(层叠列表)是一种Drawable资源,它允许我们将多个drawable组合在一起,并精确控制每个元素的位置、尺寸和对齐方式。实现步骤如下:

  • 创建LayerList Drawable

res/drawable/目录下创建layer_arrow_icon

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:width="6dp"
        android:height="10dp" 
        android:gravity="center"
        android:drawable="@drawable/icon_left_arrow"
        android:top="1dp">
    </item>
</layer-list>

android:drawable:引用的原始图标资源,android:width/height:精确控制图标尺寸,android:top/bottom等可以调整图标上下间距。

  • 在TextView中应用优化后的Drawable
xml 复制代码
<TextView
    app:drawableStartCompat="@drawable/layer_arrow_icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="我是文字"
    android:drawablePadding="2dp"
    android:textColor="@color/red"
    android:textSize="18sp" />

执行效果同上面居中样式的,不再贴了。

扩展:多图层控制

比如现在需要对图标加个背景,依然可以使用多层LayerList:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 背景层 -->
    <item
        android:width="16dp"
        android:height="16dp"
        android:gravity="center"
        android:top="1dp">
        <shape android:shape="oval">
            <solid android:color="#33000000" />
        </shape>
    </item>

    <item
        android:width="6dp"
        android:height="10dp"
        android:drawable="@drawable/icon_left_arrow"
        android:gravity="center"
        android:top="1dp" />
</layer-list>

执行结果:

通过LayerList优化TextView中drawable的位置和尺寸,可以动态调整图标尺寸,避免尺寸不匹配,优化居中效果,且无需修改现有布局结构。

相关推荐
执明wa9 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
404_coder10 小时前
源码视角下的 Android 开机流程:从 Zygote、SystemServer 到 Launcher
android
二流小码农10 小时前
鸿蒙开发:以登录案例了解代码架构MVVM
android·ios·harmonyos
用户693717500138411 小时前
从代码生产者到 AI 协作者:软件工程师的角色重构
android·前端·后端
GitLqr11 小时前
别在 Flutter 的 main() 里乱锁屏幕方向,小心 iPad 分屏功能被你搞没了
android·flutter·ios
sg_knight11 小时前
MySQL 存储过程详解:从入门到实战
android·数据库·mysql·database·dba·关系型数据库·db
爱笑鱼11 小时前
Binder(四):ioctl(BINDER_WRITE_READ) 之后,事务怎样到达目标进程?
android
AFinalStone11 小时前
Android 7系统休眠唤醒(二)开机全链路—BootROM到Launcher
android·电源管理·休眠唤醒
Mr YiRan12 小时前
Android NDK开发之统计到未被回收的图片
android