材料景观和顶部的角落应夹住儿童

发布于 2025-01-20 14:05:58 字数 1074 浏览 0 评论 0原文

材料cardview使用圆角时将其孩子剪辑。如果我使用cardCornerradius = true(将所有4个角圆形圆角),则剪辑的行为符合预期 - >没有在圆形区域外吸引儿童。如果我尝试更小的角(即只有shapeappearancemodel>的顶部角落),那么剪辑部分就会丢失 - >将在圆角区域上绘制一个顶级孩子)。

我意识到剪辑MaterialCardView调用 setCliptoOutline(shapeappearancemodel.isroundrect(getBoundSasRectf())); set setShapeAppeApeModel的内部,其中isROUNDRECT仅在所有四个角落都被四舍五入时返回true,因此我尝试在code>上应用cliptooutline = true在设置shapeappearancemodel带有圆角的shapeappearancemodel ,但没有类似的结果 - 仍然可以在父卡的圆形部分上绘制孩子。

什么实际触发了剪裁部分,我该如何将其强加于顶部的圆形材料贴图?

LE:反复试验:

// card is MaterialCardView
card.shapeAppearanceModel =   
    ShapeAppearanceModel()
        .toBuilder()
        .setTopRightCorner(CornerFamily.ROUNDED, cornerPx) // cornerPx = 24dp in pixels
        .setTopLeftCorner(CornerFamily.ROUNDED, cornerPx)
        .build()

card.apply {
    preventCornerOverlap = true
    clipChildren = true
    clipToOutline = true
}
card.invalidateOutline()
    

MaterialCardView clips its children when using rounded corners. If I use cardCornerRadius = true (which rounds all 4 corners of the card), the clipping behaves as expected -> children are not being drawn outside of the rounded area. If I try to round less corners (ie. only top corners, using ShapeAppearanceModel), then the clipping part is lost -> a top positioned child will be drawn over the rounded cornered area).

I realised that clip MaterialCardView calls
setClipToOutline(shapeAppearanceModel.isRoundRect(getBoundsAsRectF()));
inside of setShapeAppearanceModel, where isRoundRect returns true only if all four corners are rounded, so I tried applying clipToOutline = true on the MaterialCardView after setting the shapeAppearanceModel with top corners rounded, but with no similar result - children were still able to be drawn over the rounded part of the parent card.

What is actually triggering the clipping part and how can I force it on a top rounded shaped MaterialCardView?

LE: trial and error code:

// card is MaterialCardView
card.shapeAppearanceModel =   
    ShapeAppearanceModel()
        .toBuilder()
        .setTopRightCorner(CornerFamily.ROUNDED, cornerPx) // cornerPx = 24dp in pixels
        .setTopLeftCorner(CornerFamily.ROUNDED, cornerPx)
        .build()

card.apply {
    preventCornerOverlap = true
    clipChildren = true
    clipToOutline = true
}
card.invalidateOutline()
    

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ㄖ落Θ余辉 2025-01-27 14:05:58

在调试材料浏览量源代码后,我提出了以下子类,这些子类将阻止额外的偏移到填充到填充物,并脱离轮廓。

/**
 * This view is for solving the MaterialCardView bug that in case that not all corner radius are of the same size
 * an additional offset is added to the card padding which causes undesired behavior(e.g certain child view of the card
 * that is aligned to the card top wont get it's corners rounded according to the card corner radius which will make it look like
 * it overlaps the card border at the corners).
 * Note that this bug does not occur when the corner radius is the same size for all corners!!!
 * [For more info](https://stackoverflow.com/questions/71824566/materialcardview-with-top-rounded-corners-should-clip-children)
 *
 * @constructor
 *
 * @param context
 * @param attributeSet
 * @param defStyleRes
 */
class AsymmetricRadiusCardView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleRes: Int = R.attr.materialCardViewStyle
) : MaterialCardView(context, attributeSet, defStyleRes) {

    /*
    Method instance of MaterialCardView.setAncestorContentPadding via reflection.
    Invoking this method will allow us to set desired card content padding without
    the additional offset that is added when calling MaterialCardView.setContentPadding if
    the radius of all corners is not equal.
     */
    private val reflectedAncestorPaddingMethod: Method by lazy {
        MaterialCardView::class.java.getDeclaredMethod(
            "setAncestorContentPadding",
            Int::class.java,
            Int::class.java,
            Int::class.java,
            Int::class.java
        ).apply {
            isAccessible = true
        }
    }

    init {
        setContentPadding(contentPaddingLeft, contentPaddingTop, contentPaddingRight, contentPaddingBottom)
    }

    override fun setContentPadding(left: Int, top: Int, right: Int, bottom: Int) {
        //override this method so that after calling super method for content padding which
        //will add the undesired padding offset in case the radius is not the same size for all corners
        //we will invoke the reflected to enforce given padding without additional offset
        super.setContentPadding(left, top, right, bottom)
        try {
            reflectedAncestorPaddingMethod.invoke(this, left, top, right, bottom)
        } catch (e: Exception) {
            Timber.w(e)
        }
    }

    override fun setShapeAppearanceModel(shapeAppearanceModel: ShapeAppearanceModel) {
        //due to the fact that in super method if the radius is not the same size for all corners
        //the card wont be clipped to outline(which can cause overlap drawing of it's child views on card corners)
        //we enforce clipping to outline after calling super method
        super.setShapeAppearanceModel(shapeAppearanceModel)
        clipToOutline = true
    }
}

After debugging the MaterialCardView source code I came up with the following sub-class that will prevent from additional offset to padding and unclipping to outlines.

/**
 * This view is for solving the MaterialCardView bug that in case that not all corner radius are of the same size
 * an additional offset is added to the card padding which causes undesired behavior(e.g certain child view of the card
 * that is aligned to the card top wont get it's corners rounded according to the card corner radius which will make it look like
 * it overlaps the card border at the corners).
 * Note that this bug does not occur when the corner radius is the same size for all corners!!!
 * [For more info](https://stackoverflow.com/questions/71824566/materialcardview-with-top-rounded-corners-should-clip-children)
 *
 * @constructor
 *
 * @param context
 * @param attributeSet
 * @param defStyleRes
 */
class AsymmetricRadiusCardView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleRes: Int = R.attr.materialCardViewStyle
) : MaterialCardView(context, attributeSet, defStyleRes) {

    /*
    Method instance of MaterialCardView.setAncestorContentPadding via reflection.
    Invoking this method will allow us to set desired card content padding without
    the additional offset that is added when calling MaterialCardView.setContentPadding if
    the radius of all corners is not equal.
     */
    private val reflectedAncestorPaddingMethod: Method by lazy {
        MaterialCardView::class.java.getDeclaredMethod(
            "setAncestorContentPadding",
            Int::class.java,
            Int::class.java,
            Int::class.java,
            Int::class.java
        ).apply {
            isAccessible = true
        }
    }

    init {
        setContentPadding(contentPaddingLeft, contentPaddingTop, contentPaddingRight, contentPaddingBottom)
    }

    override fun setContentPadding(left: Int, top: Int, right: Int, bottom: Int) {
        //override this method so that after calling super method for content padding which
        //will add the undesired padding offset in case the radius is not the same size for all corners
        //we will invoke the reflected to enforce given padding without additional offset
        super.setContentPadding(left, top, right, bottom)
        try {
            reflectedAncestorPaddingMethod.invoke(this, left, top, right, bottom)
        } catch (e: Exception) {
            Timber.w(e)
        }
    }

    override fun setShapeAppearanceModel(shapeAppearanceModel: ShapeAppearanceModel) {
        //due to the fact that in super method if the radius is not the same size for all corners
        //the card wont be clipped to outline(which can cause overlap drawing of it's child views on card corners)
        //we enforce clipping to outline after calling super method
        super.setShapeAppearanceModel(shapeAppearanceModel)
        clipToOutline = true
    }
}
如果没有你 2025-01-27 14:05:58

应用以下配置,如果您使用形状外观覆盖层以防止孩子从角落重叠:

  • set cardpreventcorneroverlap true
  • ,然后将与角落设置与默认设置相关的其他所有内容(只需删除在设计模式下的文本框中的值)。

然后,您应该看到这样的东西:

Apply the following configurationsif you use shape appearance overlay in order to prevent the childs to overlapping from the corners:

  • Set cardPreventCornerOverlap to true
  • Then leave everything else that has to do with the corner settings as default (just delete the values from the textboxes in the design mode).

Then you should see something like this:
enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文