Android自定义TextView多状态下如何实现文字统一左对齐?
自定义TextView多状态文本统一对齐实现方案
偏移原因定位
三个状态下文字位置不对齐,本质是组件左边缘到文本起始位置的总占位长度不一致:
- 带起始Drawable的STATE_TWO/STATE_THREE:文本左侧的总占位 = 左内边距 + 起始Drawable自身宽度 + Drawable与文本的间距
- 无Drawable的STATE_ONE:文本左侧的总占位 = 0(无内边距、无Drawable占位)
两个占位值差了「Drawable宽度 + 内边距差值 + Drawable间距」的长度,自然就会出现文本偏移。
具体实现修改
不需要改动外层布局约束,只要在自定义View的状态切换逻辑里统一占位规则即可,核心思路是让所有状态下,从组件左边缘到文本开头的总长度固定不变:
- 固定所有起始Drawable的尺寸,避免不同Drawable资源的实际宽度不一致导致的偏移
- 统一垂直方向的内边距规则,不要STATE_ONE用0内边距、其他状态用4dp内边距造成上下位置偏移
- 给无Drawable的STATE_ONE,补齐左侧内边距,让左侧总占位长度和带Drawable的状态完全相等
修改后的CustomTextView核心代码
enum class State { STATE_ONE, STATE_TWO, STATE_THREE } class CustomTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ): TextView(context, attrs, defStyleAttr) { // 统一尺寸常量,全部转成px private val basePadding = 4 * resources.displayMetrics.density.toInt() private val drawableSize = 24 * resources.displayMetrics.density.toInt() // 固定Drawable宽高24dp private val drawablePadding = 4 * resources.displayMetrics.density.toInt() // Drawable和文本的固定间距 // 计算带Drawable状态下,文本距离组件左边缘的总固定长度 // 总长度 = 基础左内边距 + Drawable宽度 + Drawable间距 private val totalStartOffset = basePadding + drawableSize + drawablePadding var state: State = State.STATE_ONE set(value) { field = value updateTextView() requestLayout() // 内边距变化时需要重新布局计算位置 invalidate() } private fun updateTextView() { when(state) { State.STATE_TWO -> { setBackgroundResource(R.color.light_red) // 给Drawable设置固定尺寸,避免原图大小不一致 val startDrawable = ContextCompat.getDrawable(context, R.drawable.ic_baseline_message_24) startDrawable?.setBounds(0, 0, drawableSize, drawableSize) setCompoundDrawables(startDrawable, null, null, null) compoundDrawablePadding = drawablePadding // 带Drawable的状态,左侧基础内边距设为basePadding,剩下的占位由Drawable+间距补上 setPadding(basePadding, basePadding, basePadding, basePadding) } State.STATE_THREE -> { setBackgroundResource(R.color.colorGreenBright) // 替换为状态3对应的不同起始Drawable,同样设置固定尺寸 val startDrawable = ContextCompat.getDrawable(context, R.drawable.状态3对应的Drawable资源ID) startDrawable?.setBounds(0, 0, drawableSize, drawableSize) setCompoundDrawables(startDrawable, null, null, null) compoundDrawablePadding = drawablePadding setPadding(basePadding, basePadding, basePadding, basePadding) } else -> { setBackgroundResource(R.color.transparent) setCompoundDrawables(null, null, null, null) // 无Drawable的状态,直接用计算好的totalStartOffset作为左内边距,补齐所有占位差 // 垂直、右侧内边距和其他状态保持一致 setPadding(totalStartOffset, basePadding, basePadding, basePadding) } } } }
注意事项
- 不要靠调整布局的
layout_margin凑对齐,列表场景下View复用很容易出现位置错乱 - 内边距/尺寸变化后要调用
requestLayout(),不然View不会重新测量计算位置 - 如果状态需要保留布局里设置的圆角背景,不要在状态切换时直接用
setBackgroundResource覆盖,按需修改背景色即可
内容的提问来源于stack exchange,提问作者ziselos
相关产品推荐
相关产品推荐

