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的位置和尺寸,可以动态调整图标尺寸,避免尺寸不匹配,优化居中效果,且无需修改现有布局结构。

相关推荐
_小马快跑_2 小时前
Kotlin协程并发控制:多线程环境下的顺序执行
android
_小马快跑_2 小时前
Kotlin协程异常捕获陷阱:try-catch捕获异常失败了?
android
_小马快跑_2 小时前
Android | 权限申请与前置说明弹窗同时展示的优雅方案
android
_小马快跑_2 小时前
Android | Channel 与 Flow的异同点
android
_小马快跑_2 小时前
Android | 文本测量:从 Paint.measureText 到 StaticLayout 的替换
android
树獭非懒3 小时前
告别繁琐多端开发:DivKit 带你玩转 Server-Driven UI!
android·前端·人工智能
三少爷的鞋4 小时前
为什么应该先在 IntelliJ 中学习 Kotlin 与协程,而不是直接上 Android Studio
android
不爱说话郭德纲19 小时前
告别漫长的HbuilderX云打包排队!uni-app x 安卓本地打包保姆级教程(附白屏、包体积过大排坑指南)
android·前端·uni-app
Sinclair1 天前
简单几步,安卓手机秒变服务器,安装 CMS 程序
android·服务器