为什么带有 Chip 的 marginEnd 的 Horizo​​ntalScrollView 中的 ChipGroup 不起作用?

Why ChipGroup inside HorizontalScrollView with Chip's marginEnd not working?

我在 ChipGroup 中有 Chips,在 Horizo​​ntalScrollView 中有这个 ChipGroup。但我的问题是最后一个 Chip 上的 marginEnd 不工作!

我尝试以编程方式更改布局参数,但没有成功

<HorizontalScrollView
    android:id="@+id/chips_container"
    android:layout_width="0dp"
    android:layout_height="56dp"
    android:layout_gravity="center_vertical"
    android:visibility="gone"
    app:layout_constraintBottom_toTopOf="@+id/dividerSmartReplies"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    tools:visibility="visible">

    <com.google.android.material.chip.ChipGroup
        android:id="@+id/chip_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        app:chipSpacing="8dp"
        app:singleLine="true"
        app:singleSelection="true">

        <com.google.android.material.chip.Chip
            style="@style/Widget.MaterialComponents.Chip.Choice"
            android:layout_width="wrap_content"
            android:layout_height="42dp"
            android:layout_marginStart="8dp"
            android:textColor="@color/selector_smart_reply_chip_text"
            app:checkedIconVisible="false"
            app:chipBackgroundColor="@color/selector_smart_reply_chip"
            app:chipCornerRadius="21dp"
            app:chipStrokeColor="@color/app_base_blue"
            app:chipStrokeWidth="1dp" />

        <com.google.android.material.chip.Chip
            style="@style/Widget.MaterialComponents.Chip.Choice"
            android:layout_width="wrap_content"
            android:layout_height="42dp"
            android:textColor="@color/selector_smart_reply_chip_text"
            app:checkedIconVisible="false"
            app:chipBackgroundColor="@color/selector_smart_reply_chip"
            app:chipCornerRadius="21dp"
            app:chipStrokeColor="@color/app_base_blue"
            app:chipStrokeWidth="1dp" />

        <com.google.android.material.chip.Chip
            style="@style/Widget.MaterialComponents.Chip.Choice"
            android:layout_width="wrap_content"
            android:layout_height="42dp"
            android:textColor="@color/selector_smart_reply_chip_text"
            app:checkedIconVisible="false"
            app:chipBackgroundColor="@color/selector_smart_reply_chip"
            app:chipCornerRadius="21dp"
            app:chipStrokeColor="@color/app_base_blue"
            app:chipStrokeWidth="1dp" />

        <com.google.android.material.chip.Chip
            style="@style/Widget.MaterialComponents.Chip.Choice"
            android:layout_width="wrap_content"
            android:layout_height="42dp"
            android:layout_marginEnd="8dp"
            android:textColor="@color/selector_smart_reply_chip_text"
            app:checkedIconVisible="false"
            app:chipBackgroundColor="@color/selector_smart_reply_chip"
            app:chipCornerRadius="21dp"
            app:chipStrokeColor="@color/app_base_blue"
            app:chipStrokeWidth="1dp" />
    </com.google.android.material.chip.ChipGroup>

</HorizontalScrollView>

在最后一个筹码之后我需要额外的 space。 ChipGroup 的填充有效,但它并不期望 UI 结果。

我想通了这个问题! ChipGroup 扩展了 FlowLayout。 FlowLayout,在 onMeasure() 方法中,没有考虑 marginRight of last child to finalWidth.
我的最终解决方案:

class SmartRepliesGroup @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyle: Int = 0
) : ChipGroup(context, attributeSet, defStyle) {

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val maxWidth =
            if (widthMode != -2147483648 && widthMode != 1073741824) 2147483647 else width
        var childLeft = this.paddingLeft
        var childTop = this.paddingTop
        var childBottom = childTop
        var maxChildRight = 0
        val maxRight = maxWidth - this.paddingRight

        var finalWidth = 0
        var lastChildMarginRight = 0
        while (finalWidth < this.childCount) {
            val child = this.getChildAt(finalWidth)
            if (child.visibility != 8) {
                this.measureChild(child, widthMeasureSpec, heightMeasureSpec)
                val lp = child.layoutParams
                var leftMargin = 0
                var rightMargin = 0
                if (lp is MarginLayoutParams) {
                    leftMargin += lp.leftMargin
                    rightMargin += lp.rightMargin
                    lastChildMarginRight = rightMargin
                }

                var childRight = childLeft + leftMargin + child.measuredWidth
                if (childRight > maxRight && !this.isSingleLine) {
                    childLeft = this.paddingLeft
                    childTop = childBottom + this.lineSpacing
                }

                childRight = childLeft + leftMargin + child.measuredWidth
                childBottom = childTop + child.measuredHeight
                if (childRight > maxChildRight) {
                    maxChildRight = childRight
                }

                childLeft += leftMargin + rightMargin + child.measuredWidth + this.itemSpacing
            }
            ++finalWidth
        }

        finalWidth =
            getMeasuredDimension(width, widthMode, maxChildRight + lastChildMarginRight)
        val finalHeight = getMeasuredDimension(height, heightMode, childBottom)
        this.setMeasuredDimension(finalWidth, finalHeight)
    }

    private fun getMeasuredDimension(size: Int, mode: Int, childrenEdge: Int): Int =
        when (mode) {
            -2147483648 -> Math.min(childrenEdge, size)
            1073741824 -> size
            else -> childrenEdge
        }
}

嘿,我知道这有点晚了,我很高兴你找到了适合你的答案。但是我认为我有更好的解决方案:

  • 为您的 Horizo​​ntalScrollView 添加 8dp 的开始和结束填充
  • 使 clipToPadding 为假

这就是您的 Horizo​​ntalScrollView 的外观:

    <HorizontalScrollView
        android:id="@+id/chips_container"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:layout_gravity="center_vertical"
        android:visibility="gone"
        app:layout_constraintBottom_toTopOf="@+id/dividerSmartReplies"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:visibility="visible"

        android:paddingStart="8dp"
        android:paddingEnd="8dp"
        android:clipToPadding="false"
>

并且您可以去除第一个和最后一个筹码上的边距!