TextView居中Drawable(kotlin)

本文介绍了一个自定义的CenterTextView,通过计算文本和图片的尺寸,自动调整内边距实现图文居中。代码详细解释了如何处理不同方向上的Drawable,并在onDraw方法中动态设置Padding,确保内容在任何情况下都能保持居中。测试代码展示了不同位置Drawable的使用情况。
摘要由CSDN通过智能技术生成

1.先看效果。

2.代码(代码直接拷贝,正常TextView使用就行)

/**
 * @author: Maple
 * @date: 2022/3/17
 * @description:
 */
class CenterTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {

    override fun onDraw(canvas: Canvas?) {

        // 当左边Drawable的不为空时
        compoundDrawables[0]?.run {
            horizontalDrawable(this)
        }
        // 如果上边的Drawable不为空时
        compoundDrawables[1]?.run {
            verticalDrawable(this)
        }
        // 当右边Drawable的不为空时
        compoundDrawables[2]?.run {
            horizontalDrawable(this)
        }
        // 如果下边的Drawable不为空时
        compoundDrawables[3]?.run {
            verticalDrawable(this)
        }
        super.onDraw(canvas)
    }


    /**
     * 水平方向的重绘
     */
    private fun horizontalDrawable(drawable: Drawable) {
        val textWidth: Float = paint.measureText(text.toString())
        // 计算总宽度(文本宽度 + drawablePadding + drawableWidth) minimumWidth或者intrinsicWidth
        val bodyWidth = textWidth + compoundDrawablePadding + drawable.minimumWidth
        if (layoutParams.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            //不用处理
        } else {
            //这里判断主要是因为每次setPadding的时候会重新执行OnDraw(),所以进行判断,避免死循环
            if (paddingRight != (width - bodyWidth).toInt() / 2) {
                //设置边距
                setPadding(
                    (width - bodyWidth).toInt() / 2,
                    paddingTop,
                    (width - bodyWidth).toInt() / 2,
                    paddingBottom
                )
            }
        }
    }

    /**
     * 垂直方向的重绘
     */
    private fun verticalDrawable(drawable: Drawable) {
        var textHeight: Float = (paint.fontMetrics.bottom - paint.fontMetrics.top)
//        var textHeight: Float = (paint.fontMetrics.descent - paint.fontMetrics.ascent)
        textHeight *= lineCount
        // 计算总高度(文本高度 + drawablePadding + drawableHeight)
        val bodyHeight = textHeight + compoundDrawablePadding + drawable.minimumHeight

        if (layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
            //不用处理
        } else {
            //这里判断主要是因为每次setPadding的时候会重新执行OnDraw(),所以进行判断,避免死循环
            if (paddingBottom != (height - bodyHeight).toInt() / 2) {
                //设置边距
                setPadding(
                    paddingLeft,
                    (height - bodyHeight).toInt() / 2,
                    paddingRight,
                    (height - bodyHeight).toInt() / 2,
                )
            }
        }
    }
}

3.测试代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <priv.maple.library_basic.view.text.CenterTextView
        android:id="@+id/view1"
        android:layout_width="@dimen/dp_100"
        android:layout_height="wrap_content"
        android:background="@drawable/btn_20c5a3_4"
        android:drawableStart="@mipmap/ic_ac_play_gold_beans"
        android:drawablePadding="@dimen/dp_10"
        android:gravity="center"
        android:paddingVertical="@dimen/dp_10"
        android:text="100"
        android:textColor="@color/color_f1f1f1"
        android:textSize="@dimen/sp_14"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <priv.maple.library_basic.view.text.CenterTextView
        android:id="@+id/view2"
        android:layout_width="@dimen/dp_100"
        android:layout_height="wrap_content"
        android:background="@drawable/btn_20c5a3_4"
        android:drawableEnd="@mipmap/ic_ac_play_gold_beans"
        android:drawablePadding="@dimen/dp_10"
        android:gravity="center"
        android:paddingVertical="@dimen/dp_10"
        android:text="100"
        android:textColor="@color/color_f1f1f1"
        android:textSize="@dimen/sp_14"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/view1" />

    <priv.maple.library_basic.view.text.CenterTextView
        android:id="@+id/view3"
        android:layout_width="@dimen/dp_100"
        android:layout_height="wrap_content"
        android:background="@drawable/btn_20c5a3_4"
        android:drawableTop="@mipmap/ic_ac_play_gold_beans"
        android:drawablePadding="@dimen/dp_10"
        android:gravity="center"
        android:paddingVertical="@dimen/dp_10"
        android:text="100"
        android:textColor="@color/color_f1f1f1"
        android:textSize="@dimen/sp_14"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/view2" />

    <priv.maple.library_basic.view.text.CenterTextView
        android:id="@+id/view4"
        android:layout_width="@dimen/dp_100"
        android:layout_height="wrap_content"
        android:background="@drawable/btn_20c5a3_4"
        android:drawableBottom="@mipmap/ic_ac_play_gold_beans"
        android:drawablePadding="@dimen/dp_10"
        android:gravity="center"
        android:paddingVertical="@dimen/dp_10"
        android:text="100"
        android:textColor="@color/color_f1f1f1"
        android:textSize="@dimen/sp_14"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/view3" />

</androidx.constraintlayout.widget.ConstraintLayout>

4.代码解析

​​​​​​​逻辑是这样考虑的,首先这个是一个居中的文本加图片,那么我们只要计算出来控件的大小减去文字的大小,图片的大小,以及drawablePadding的大小,然后再除以2,这个时候的数值就是我们所要设置的Padding。然后在onDraw里面设置setPadding就可以了。

  • compoundDrawables
    可以获取一个数组,这个数组共有4个值,索引分别对应了左,上,右,下的drawable。
  • measureText
    测量文字的宽度。
  • textHeight
    文字的高度获取-paint.fontMetrics.bottom - paint.fontMetrics.top
    文字的高度获取-paint.fontMetrics.descent - paint.fontMetrics.ascent
    
  • compoundDrawablePadding
    返回可绘制对象和文本之间的填充。也就是Xml里面的drawablePadding。
    
  • drawable.minimumHeight------drawable.minimumWidth
    代表了drawable图片的宽度和高度。本来使用的是intrinsicWidth看过源码以后发现intrinsicWidth如果没有高度返回的是-1,minimumHeight返回的是0,这个看源码很简单。 
  • layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT
    这里判断是因为,咱们用的是宽度过大,还要保持图片居中的TextView控件,如果说是WRAP_CONTENT那么直接使用TextView就好了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值