CardView 在 Pre-Lollipop 上的每个边缘都有额外的边距

CardView has extra margin in each edge on Pre-Lollipop

这里有两张照片。

关于棒棒糖:

关于 Pre-Lollipop:

我们可以看到它刚好靠近棒棒糖的屏幕一侧。这就是我想要的。但在 Pre-Lollipop 设备上,它在屏幕边缘有额外的边距。你们有什么经验吗?谢谢。

布局如下xml:

<android.support.v7.widget.CardView
        android:id="@+id/card_title_schedule"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        app:cardCornerRadius="0dp"
        app:cardBackgroundColor="@color/colorAccent"
        >

Before L, CardView adds padding to its content and draws shadows to that area. This padding amount is equal to maxCardElevation + (1 - cos45) * cornerRadius on the sides and maxCardElevation * 1.5 + (1 - cos45) * cornerRadius on top and bottom.

来自 CardView 参考资料 here

尝试像这样

CardView 上设置负左边距
<android.support.v7.widget.CardView
        android:id="@+id/card_title_schedule"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        app:cardCornerRadius="0dp"
        app:cardBackgroundColor="@color/colorAccent" 
        app:cardUseCompatPadding="true"
        android:layout_marginLeft="-2dp" />

您可能需要调整边距以获得所需的结果。

PS,这是一种 hack-y 的方式。

试试 card_view:cardUseCompatPadding="true"

如果我们将此 属性 设置为 true,则边距在所有版本上都相同。

开发者说明

Add padding in API v21+ as well to have the same measurements with previous versions.

来源docs

要解决 PR​​E-L 版本的 "shadow space" 问题,您可以通过负值动态更新 CardView 边距以补偿 space。

获取实际阴影space:

shadowSpaceLeft = getPaddingLeft() - getContentPaddingLeft();

固定边距:

layoutParams.leftMargin -= shadowSpaceLeft;

这将适用于所有 Android 版本,因为我们正在动态获取填充值和 contentPadding 值。

例如,这里有一个 class,每当我们设置新的布局参数时它都会执行此操作:

public class NoPaddingCardView extends CardView {

    public NoPaddingCardView(Context context) {
        super(context);
        init();
    }

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

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

    private void init() {
        // Optional: Prevent pre-L from adding inner card padding 
        setPreventCornerOverlap(false);
        // Optional: make Lollipop and above add shadow padding to match pre-L padding
        setUseCompatPadding(true);
    }

    @Override
    public void setLayoutParams(ViewGroup.LayoutParams params) {
        // FIX shadow padding
        if (params instanceof MarginLayoutParams) {
            MarginLayoutParams layoutParams = (MarginLayoutParams) params;
            layoutParams.bottomMargin -= (getPaddingBottom() - getContentPaddingBottom());
            layoutParams.leftMargin -= (getPaddingLeft() - getContentPaddingLeft());
            layoutParams.rightMargin -= (getPaddingRight() - getContentPaddingRight());
            layoutParams.topMargin -= (getPaddingTop() - getContentPaddingTop());
        }

        super.setLayoutParams(params);
    }
}

因此它在 Kitkat 上运行得非常好,准确地说是三星设备。

我尝试了 card_view:cardUseCompatPadding="true" 但无济于事。没用!

然后我从Whosebug上发现了post这个 card_view:cardPreventCornerOverlap="false" 瞧!成功了!没有圆角(因为我想要 none 因为卡片有图像背景)。

道德是,额外的填充是因为那些需要禁用的小圆角。基本上这不是缺陷而是设计限制!

图片:请注意,顶角是边缘(具有颜色和背景图像的视图),而底部只有 TextView,没有背景,因此是圆角。这意味着如果一个视图在 CardView 中请求 match_parentcard_view:cardPreventCornerOverlap="false" 将允许在受影响的角落占用它。

我知道这个问题已经得到解答,但我想补充一点,除了 card_view:cardPreventCornerOverlap="false" 之外,我还必须设置 CardView.setMaxCardElevation(0) 以消除 Lollipop 之前的边距.仅将高程设置为 0 不起作用。我正在使用支持库 v23.4.0.

如果需要 Android 4(前棒棒糖)行为,将 app:cardUseCompatPadding="true" 添加到 CardView 应该可以解决它。

如果需要 Android 5+ 行为(根据 material 指南,这实际上是卡片视图的正确行为),则无法轻易实现完全相同的事情。我通常使用这个修复来避免定义多个布局文件并在所有设备上都有合理的输出:

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:contentPaddingRight="@dimen/fix_cardview"
    app:contentPaddingLeft="@dimen/fix_cardview"
    app:contentPaddingTop="@dimen/fix_cardview_vertical"
    app:contentPaddingBottom="@dimen/fix_cardview_vertical" />

在正常的 values/dimens.xml 文件中我们应该有:

<dimen name="fix_cardview">-8dp</dimen>
<dimen name="fix_cardview_vertical">-12dp</dimen>

并在 values-v21/dimens.xml 中:

<dimen name="fix_cardview">0dp</dimen>
<dimen name="fix_cardview_vertical">0dp</dimen>

请注意,数字 -8dp-12dp 可能需要根据您的布局进行调整,因为它们取决于海拔等因素。

这只是避免在 Android 4 个视图中使用丑陋的填充的变通方法,而不是在不同的布局文件中使用不同的视图(这通常会使代码更难维护)

只需将此添加到棒棒糖前版本的代码中:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
    {
        cardView.setMaxCardElevation(0f);
        cardView.setPreventCornerOverlap(false);
    }