Android iconGravity 不适用于具有 CircularProgressIndicator 的 MaterialButton

Wir*_*ing 5 android progress-indicator android-gravity material-components material-components-android

我创建了一个扩展 MaterialButton 的自定义视图,在加载时用 CircularProgressIndicator 替换可绘制对象。

但是,当我用 CircularProgressIndicator 替换可绘制对象时, iconGravity 不再起作用。我不明白我做错了什么。

我已经能够将课程归结为:

class LoadingButton constructor(context: Context) : MaterialButton(context) {

    private val progressIndicatorDrawable by lazy {
        val progressIndicatorSpec = CircularProgressIndicatorSpec(context, null, 0, R.style.Widget_MaterialComponents_CircularProgressIndicator_ExtraSmall)
        progressIndicatorSpec.indicatorColors = intArrayOf(getColor(context, R.color.white))
        IndeterminateDrawable.createCircularDrawable(context, progressIndicatorSpec).apply {
            setVisible(true, true)
        }
    }

    init {
        // the following drawable is aligned to the start of the view (incorrect).
        icon = progressIndicatorDrawable
        // the following drawable is aligned to the start of the text (correct).
        // icon = DrawableUtil.getDrawable(context, R.drawable.icon_delete)
        text = "Delete"
        iconGravity = ICON_GRAVITY_TEXT_START
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用这个依赖项

// I've also tried 1.5.0-alpha02
implementation "com.google.android.material:material:1.3.0"
Run Code Online (Sandbox Code Playgroud)

正确位置可绘制对象位于文本的开头。 可绘制的正确位置

位置不正确进度指示器不再位于文本的开头。 进度指示器位置不正确

Che*_*amp 2

奇怪的是,一个可绘制对象可以工作,但另一个却不能。可能值得将其报告为错误。与此同时,我可以提供一种不需要大量工作的解决方法(IMO)。

如果我们采用您的自定义视图并删除iconGravity并将文本的重力设置为开始和垂直中心:

gravity = Gravity.START or Gravity.CENTER_VERTICAL
Run Code Online (Sandbox Code Playgroud)

我们可以将不确定的内容和文本放在按钮的左侧:

在此输入图像描述

现在的问题是如何使该对在按钮中居中。我们可以从MaterialButton代码中得到提示,了解左侧需要多少空间才能将可绘制对象和文本居中。

int newIconLeft =
    (buttonWidth
        - getTextWidth()
        - ViewCompat.getPaddingEnd(this)
        - localIconSize
        - iconPadding
        - ViewCompat.getPaddingStart(this))
        / 2;
Run Code Online (Sandbox Code Playgroud)

把它们放在一起:

在此输入图像描述

这是演示代码。如果您的实际按钮比问题中所示的更复杂,则可能需要进行一些调整。

class LoadingButton @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : MaterialButton(context, attrs) {

    // true - use indeterminate; false = use delete icon
    private val useIndeterminate = true

    private val progressIndicatorDrawable by lazy {
        val progressIndicatorSpec = CircularProgressIndicatorSpec(
            context,
            null,
            0,
            R.style.Widget_MaterialComponents_CircularProgressIndicator_ExtraSmall
        )
        progressIndicatorSpec.indicatorColors = intArrayOf(getColor(context, R.color.white))
        IndeterminateDrawable.createCircularDrawable(context, progressIndicatorSpec).apply {
            setVisible(true, true)
        }
    }

    init {
        if (useIndeterminate) {
            icon = progressIndicatorDrawable
            gravity = Gravity.START or Gravity.CENTER_VERTICAL
        } else {
            icon = ContextCompat.getDrawable(context, R.drawable.icon_delete)
            iconGravity = ICON_GRAVITY_TEXT_START
            gravity = Gravity.CENTER
        }
        text = "Delete"
    }

    // This is homw much we need to shift the contents of the button to the right in order to
    // center it.
    private var xShift = 0f
    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        if (useIndeterminate) {
            xShift = (width
                    - icon.intrinsicWidth
                    - paint.measureText(text.toString())
                    - iconPadding
                    - ViewCompat.getPaddingStart(this)
                    - ViewCompat.getPaddingEnd(this)) / 2f
        }
    }

    override fun onDraw(canvas: Canvas?) {
        // Shift right before drawing.
        canvas?.withTranslation(xShift) {
            super.onDraw(canvas)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)