Appcompat CardView和Picasso无法实现圆角效果。

19

我不知道应该在哪里提出这个问题,如果是我的错,那么可能是 Picasso Lib 或者 Cardview Library 中有问题。

基本上,我有一个包含图片(完全卡片覆盖)和 TextView 叠加的 CardView。

当在 Android 5.0 设备上运行代码时,一切正常,图像获得其圆角。

然而,如果在早期版本的设备上运行它,图像会重叠在 Cardlayout 上,并且没有圆角。

您可以在此图像上看到比较: comparison

这里有一些代码片段:

layout_row.xml

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/pandaImage"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/pandaName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/pandaImage"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:background="@color/photo_tint"
        android:clickable="true"
        android:focusable="true"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:textSize="24sp" />

</RelativeLayout>

回收适配器正在加载图片:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
    Photo p = photos.get(i);
    Picasso.with(mContext).load(p.getUrl()).fit().into(viewHolder.mImage);
    viewHolder.mPandaName.setText(p.getTitle());
}

如果将图像设置为卡片的背景,会发生什么? - JacksOnF1re
5个回答

20

正如 @kcoppock 所提到的,这是按设计来的。

以下是我在这种情况下会做的事情:

1) 您可以使用 Picasso Transformation 接口为图像指定自定义转换(在我们的情况下 - 圆角图像)

2) 将此转换应用于 pre-L 设备上的 Picasso 请求

3) 由于 CardView 为图像添加了一些边距 - 通过调用 setPreventOverlap(false) 在 pre-L 设备上摆脱它

回到代码:

自定义转换:

public class RoundedTransformation implements com.squareup.picasso.Transformation {
    private final int radius;
    private final int margin;

    public RoundedTransformation(final int radius, final int margin) {
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);

        if (source != output) {
            source.recycle();
        }

        return output;
    }

    @Override
    public String key() {
        return "rounded(radius=" + radius + ", margin=" + margin + ")";
    }
}

毕加索:

//feel free to play with radius to match your CardView
Picasso.with(mContext).load(p.getUrl()).transform(new RoundedTransformation(12, 0)).fit().into(viewHolder.mImage);

在处理卡片背景时,setPreventOverlap(false) 是非常重要的调用。在这里提到它非常好。 - Richard Le Mesurier
非常好的解决方案!如何只将顶部角落变成圆形而保持底部为正方形? - jiawen
@jiawen 很不幸,实现一个圆角效果需要比调用一个API更多的工作。通常需要分两次绘制。你可以参考SO上类似的问题。 - Pavel Dudka
1
@PavelDudka。我在这里找到了一个好的解决方案:https://github.com/wasabeef/picasso-transformations/blob/master/transformations/src/main/java/jp/wasabeef/picasso/transformations/RoundedCornersTransformation.java它允许您自定义要圆角化的哪个角落。 - jiawen

20
根据文档,这是设计上的考虑:
由于在 L 版本之前的平台上,圆角裁剪的成本较高,因此 CardView 不会裁剪与圆角相交的子元素。相反,它会添加填充以避免这种相交(请参见 setPreventCornerOverlap(boolean) 以更改此行为)。
有关更多信息,请参见 CardView 文档

3
当在早期的 Android 设备上设置 setPreventCornerOverlap(false) 时,ImageView 会超出 CardView 并与阴影对齐。对此有什么想法吗? - mike.b93
2
@mike.b93 我相信你在提到这个bug https://code.google.com/p/android/issues/detail?id=77821 我的评论似乎修复了Pre-L版本的问题。至少在我测试过的一个设备上是这样的。 - Nathan Schwermann

3
这是我的解决办法:
  1. ImageView 替换为 RoundedImageView (https://github.com/vinc3m1/RoundedImageView)。
  2. RoundedImageView 上设置 riv_corner_radius 属性,使其与 CardView 的角度大小相同。
  3. CardViewcardPreventCornerOverlap 设置为 false (app:cardPreventCornerOverlap="false")。
  4. 现在,在 L 和 pre-L 上看起来都一样了。

1
如果您希望针对该问题有一个全球解决方案,您可以使用Carbon's CardView。它可以在所有设备上正确地将其内容剪裁成圆角,包括Froyo版本及以后的所有设备。请参见以下图片:

enter image description here


0
请使用以下代码。 重要提示:不要在XML中为ImageView设置背景。
<android.support.v7.widget.CardView 
                                    android:layout_width="match_parent"
                                    android:layout_height="130dp"
                                    app:cardCornerRadius="5dp"
                                    app:cardElevation="0dp"
                                    app:cardUseCompatPadding="true">

    <RelativeLayout
        android:id="@+id/rl_target_marry"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/textView2"
        >

        <ImageView
            android:id="@+id/img_target_marry"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            />
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:foreground="?attr/selectableItemBackground">

            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_gravity="right|center_vertical"
                android:layout_marginRight="16dp"
                android:text="Marry"
                android:textColor="@color/colorWhite"
                android:textSize="28sp"/>

        </FrameLayout>

    </RelativeLayout>
</android.support.v7.widget.CardView>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接