I have Chips inside ChipGroup and this ChipGroup inside HorizontalScrollView. But my problem is marginEnd on last Chip not working!
I'm tried change layout params programmatically, but not successfull
<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>
I need extra space after last Chip. ChipGroup's padding worked but it does not expected UI result.
I figured out this issue!
ChipGroup extends FlowLayout. FlowLayout, in onMeasure() method, does't take into account marginRight of last child to finalWidth.
My final solution:
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
}
}