1

我的用例是编辑 shapeAppearanceModelcom.google.android.material.card.MaterialCardView

card.shapeAppearanceModel = card.shapeAppearanceModel
            .toBuilder()
            .setTopEdge(TriangleEdgeTreatment(triangleSize))
            .build()

上面的代码按预期工作但由于上述 shapeAppearanceModel 的编程设置

xml

 <com.google.android.material.card.MaterialCardView
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:cardBackgroundColor="?myCustomColor"
        app:cardCornerRadius="8dp"
        app:cardElevation=4dp"
        app:cardPreventCornerOverlap="true"
        app:cardUseCompatPadding="false">

    <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/myImageDrawable"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
</com.google.android.material.card.MaterialCardView>

在 Android 工作室中,由于 TopEdge 是以编程方式定义的,编辑器不会复制错误,但在模拟器/真实设备中,孩子没有被剪裁,并且圆角被 ImageView 重叠。

当我删除 shapeAppearanceModel 时,剪裁工作按预期进行。

截屏

漏洞

4

1 回答 1

0

原因是因为只有在 Shape 被标记为 Rounded 时才会发生MaterialCardView锁定行为,不幸的是,该实现也被默认情况下它自己的组件锁定:clipToOutline

在这里,如果你打开 MaterialCardView.java,你可以找到这段代码:

@Override
  public void setShapeAppearanceModel(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
    if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
      setClipToOutline(shapeAppearanceModel.isRoundRect(getBoundsAsRectF()));
    }
    cardViewHelper.setShapeAppearanceModel(shapeAppearanceModel);
  }

如果你更深入, , 的实现isRoundRect将是这样的:

@RestrictTo(LIBRARY_GROUP)
  public boolean isRoundRect(@NonNull RectF bounds) {
    boolean hasDefaultEdges =
        leftEdge.getClass().equals(EdgeTreatment.class)
            && rightEdge.getClass().equals(EdgeTreatment.class)
            && topEdge.getClass().equals(EdgeTreatment.class)
            && bottomEdge.getClass().equals(EdgeTreatment.class);

    float cornerSize = topLeftCornerSize.getCornerSize(bounds);

    boolean cornersHaveSameSize =
        topRightCornerSize.getCornerSize(bounds) == cornerSize
            && bottomLeftCornerSize.getCornerSize(bounds) == cornerSize
            && bottomRightCornerSize.getCornerSize(bounds) == cornerSize;

    boolean hasRoundedCorners =
        topRightCorner instanceof RoundedCornerTreatment
            && topLeftCorner instanceof RoundedCornerTreatment
            && bottomRightCorner instanceof RoundedCornerTreatment
            && bottomLeftCorner instanceof RoundedCornerTreatment;

    return hasDefaultEdges && cornersHaveSameSize && hasRoundedCorners;
  }

如果形状具有相同或所有圆角,则使其返回 true 的条件是。

你不能通过编程设置来欺骗它,card.setClipToOutline(true)因为它发生在渲染散文之后。

他们这样做的原因是由于设计上的一些限制:

(进一步阅读:https ://github.com/material-components/material-components-android/issues/1950 )

好消息,您可以通过创建自己的MaterialCardView并覆盖一些这样的实现来解决这个问题:

package com.example.myapp;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;

import com.google.android.material.card.MaterialCardView;
import com.google.android.material.shape.ShapeAppearancePathProvider;

public class MaskedCardView extends MaterialCardView {
    private ShapeAppearancePathProvider pathProvider = new ShapeAppearancePathProvider();
    private Path path = new Path();
    private RectF rectF = new RectF(0f, 0f, 0f, 0f);

    public MaskedCardView(Context context) {
        super(context);
    }

    public MaskedCardView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MaskedCardView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.clipPath(path);
        super.onDraw(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        rectF.right = (float) w;
        rectF.bottom = (float) h;
        pathProvider.calculatePath(getShapeAppearanceModel(), 1f, rectF, path);
        super.onSizeChanged(w, h, oldw, oldh);
    }
}

我希望它能回答你的问题。

于 2022-02-24T11:43:08.423 回答