文本对齐居中时无法在 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 看看是否有其他东西可以满足您的需要。
您引用的属性 textAlignment 在 TextView 中可用,它是 的 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 上绘制文本并用颜料或颜色填充它。
更新: 因此,我将问题追溯到 TextView 的 bringTextIntoView()
方法。出于我不清楚的原因,视图在正方向上滚动了很多地方(大,像千分之十)。正是在这个滚动位置写入文本。要在 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()
}
}
}
更新:水平滚动仍然是问题。在 TextView 的 onMeasure()
方法中,如果为视图启用了水平滚动,则所需宽度设置为 VERY_WIDE
。 (它用于 Chip。)VERY_WIDE
是 1024*1024 或 1 兆字节。这就是我们后面看到的大卷轴的来源。 Chip 的这个问题可以直接用 TextView 复制,如果我们在 TextView.
Chips 只有一行,可能不应该滚动。无论如何,调用 setHorizontallyScrolling(true)
不会使 Chip 或 TextView 可滚动。上面的代码现在变成了:
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”。
我正在扩展 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 看看是否有其他东西可以满足您的需要。
您引用的属性 textAlignment 在 TextView 中可用,它是 的 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 上绘制文本并用颜料或颜色填充它。
更新: 因此,我将问题追溯到 TextView 的 bringTextIntoView()
方法。出于我不清楚的原因,视图在正方向上滚动了很多地方(大,像千分之十)。正是在这个滚动位置写入文本。要在 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()
}
}
}
更新:水平滚动仍然是问题。在 TextView 的 onMeasure()
方法中,如果为视图启用了水平滚动,则所需宽度设置为 VERY_WIDE
。 (它用于 Chip。)VERY_WIDE
是 1024*1024 或 1 兆字节。这就是我们后面看到的大卷轴的来源。 Chip 的这个问题可以直接用 TextView 复制,如果我们在 TextView.
Chips 只有一行,可能不应该滚动。无论如何,调用 setHorizontallyScrolling(true)
不会使 Chip 或 TextView 可滚动。上面的代码现在变成了:
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”。