为什么带有 Chip 的 marginEnd 的 HorizontalScrollView 中的 ChipGroup 不起作用?
Why ChipGroup inside HorizontalScrollView with Chip's marginEnd not working?
我在 ChipGroup 中有 Chips,在 HorizontalScrollView 中有这个 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
}
}
嘿,我知道这有点晚了,我很高兴你找到了适合你的答案。但是我认为我有更好的解决方案:
- 为您的 HorizontalScrollView 添加 8dp 的开始和结束填充
- 使 clipToPadding 为假
这就是您的 HorizontalScrollView 的外观:
<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"
>
并且您可以去除第一个和最后一个筹码上的边距!
我在 ChipGroup 中有 Chips,在 HorizontalScrollView 中有这个 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
}
}
嘿,我知道这有点晚了,我很高兴你找到了适合你的答案。但是我认为我有更好的解决方案:
- 为您的 HorizontalScrollView 添加 8dp 的开始和结束填充
- 使 clipToPadding 为假
这就是您的 HorizontalScrollView 的外观:
<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"
>
并且您可以去除第一个和最后一个筹码上的边距!