文本对齐居中时无法在 Chip 上绘制

Cannot draw on Chip when text alignment is center

我正在扩展 Chip class 来为我的 lib 执行一些绘制,我的用例更复杂,但为了简单起见,假设我只是绘制一条对角线

我的代码

class MyChip (context: Context,attributeSet: AttributeSet) : Chip(context,attributeSet){

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    //just want to draw a diagonal line
    canvas.drawLine(0f,0f,width/1f,height/1f,paint)
  }
 }

xml

<com.abhinav.chouhan.loaderchipdemo.MyChip
    android:layout_width="200dp"
    android:layout_height="50dp"
    android:textAlignment="center"
    android:text="SOME TEXT"/>

当我没有 android:textAlignment="center" 属性时,一切正常,但有了该属性,我们无法在芯片上绘制任何东西。 我尝试了一切,但无法弄清楚为什么会这样。

请帮忙

Chip 小部件严格遵守 Material 设计指南,并且 (IMO) 不能更改。我建议您查看其他小部件 - 也许是 MaterialButton 看看是否有其他东西可以满足您的需要。

您引用的属性 textAlignmentTextView 中可用,它是 的 class Chip是基于。 Chips 期望 wrap_content 并且还期望文本与开头对齐。在混合的某个地方,你的过度绘制丢失了。我怀疑这样的东西是否已经过测试,因为它不符合 Material 准则。

但是,如果您必须使用 Chip,这里有一种使用自定义视图的方法:

class MyChip @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : Chip(context, attrs, defStyleAttr) {

    private val mLinePaint = Paint().apply {
        color = Color.BLUE
        strokeWidth = 10f
    }

    init {
        doOnNextLayout {
            // Turn off center alignment if specified. We will handle centering ourselves.
            if (isTextAlignmentCenter()) {
                textAlignment = View.TEXT_ALIGNMENT_GRAVITY
                // Get the length of all the stuff before the text.
                val lengthBeforeText =
                    if (isChipIconVisible) iconStartPadding + chipIconSize + iconEndPadding else 0f
                val chipCenter = width / 2
                // Chips have only one line, so we can get away with this.
                val textWidth = layout.getLineWidth(0)
                val newTextStartPadding = chipCenter - (textWidth / 2) - lengthBeforeText
                textStartPadding = max(0f, newTextStartPadding)
                textEndPadding = 0f
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //just want to draw a diagonal line
        canvas.drawLine(0f, 0f, width.toFloat(), height.toFloat(), mLinePaint)
    }

    private fun isTextAlignmentCenter() = textAlignment == View.TEXT_ALIGNMENT_CENTER
}

示例布局:

activity_main.xml

    <com.example.myapplication.MyChip
        android:id="@+id/chip"
        android:layout_width="300dp"
        android:layout_height="50dp"
        android:layout_gravity="center"
        android:text="Some Chip"
        android:textAlignment="center"
        app:chipIcon="@drawable/ic_baseline_cloud_download_24"
        app:chipIconVisible="true"
        app:closeIcon="@drawable/ic_baseline_clear_24"
        app:closeIconVisible="true" />
</LinearLayout>

结果:

我更深入地研究了这个问题。由于某些原因,canvas 操作(例如 drawLine()drawRect() 等)不起作用。但是,我可以在 canvas 上绘制文本并用颜料或颜色填充它。


更新: 因此,我将问题追溯到 TextViewbringTextIntoView() 方法。出于我不清楚的原因,视图在正方向上滚动了很多地方(大,像千分之十)。正是在这个滚动位置写入文本。要在 Chip 上绘图,我们还必须滚动到此位置。此卷轴解释了为什么我可以用颜色填充 canvas 但无法在其上绘制以使其可见。

以下内容将捕获“错误的”滚动位置并滚动到该位置,然后再在 Chip 上绘图。屏幕截图看起来与上图相同。

MyChip.kt

class MyChip @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : Chip(context, attrs, defStyleAttr)/*, View.OnScrollChangeListener*/ {

    private val mLinePaint = Paint().apply {
        color = Color.BLUE
        strokeWidth = 10f
    }

    private var mBadScroll = 0f

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //just want to draw a diagonal line
        canvas.withTranslation(x = mBadScroll) {
            canvas.drawLine(0f, 0f, this@MyChip.width.toFloat(), height.toFloat(), mLinePaint)
        }
    }

    private fun isTextAlignmentCenter() = textAlignment == View.TEXT_ALIGNMENT_CENTER

    override fun scrollTo(x: Int, y: Int) {
        super.scrollTo(x, y)
        if (isTextAlignmentCenter()) {
            mBadScroll = scrollX.toFloat()
        }
    }
}

更新:水平滚动仍然是问题。在 TextViewonMeasure() 方法中,如果为视图启用了水平滚动,则所需宽度设置为 VERY_WIDE。 (它用于 Chip。)VERY_WIDE 是 1024*1024 或 1 兆字节。这就是我们后面看到的大卷轴的来源。 Chip 的这个问题可以直接用 TextView 复制,如果我们在 TextView.

Chips 只有一行,可能不应该滚动。无论如何,调用 setHorizontallyScrolling(true) 不会使 ChipTextView 可滚动。上面的代码现在变成了:

MyChip.kt

class MyChip @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : Chip(context, attrs, defStyleAttr) {

    private val mLinePaint = Paint().apply {
        color = Color.BLUE
        strokeWidth = 10f
    }

    init {
        setHorizontallyScrolling(false)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //just want to draw a diagonal line
        canvas.drawLine(0f, 0f, this@MyChip.width.toFloat(), height.toFloat(), mLinePaint)
    }
}

水平滚动在 Chip 的构造函数中设置为“true”。