仅圆角 CardView 的顶部

91

我想只将CardView的顶部圆角化。

我使用了以下属性,但它会将所有角都圆化。

我想要显示所有卡片的重叠部分。

card_view:cardCornerRadius="4dp"

这是我的布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    card_view:cardCornerRadius="4dp"
    card_view:cardPreventCornerOverlap="false"
    >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:id="@+id/re1">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:background="@color/colorAccent"
            android:text="contact det"
            android:gravity="center_vertical"
            android:textColor="@android:color/white"
            android:textSize="14dp"/>

        <TextView
            android:id="@+id/txtName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Name"
            android:gravity="center_vertical"
            android:textSize="10dp"
            android:layout_below="@id/title"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="5dp"/>

        <TextView
            android:id="@+id/txtSurname"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Surname"
            android:gravity="center_vertical"
            android:textSize="10dp"
            android:layout_below="@id/txtName"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="5dp"
            />

        <TextView
            android:id="@+id/txtEmail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Email"
            android:textSize="10dp"
            android:layout_marginTop="10dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="150dp"
            android:layout_alignBaseline="@id/txtName"/>

        <TextView
            android:id="@+id/txtAdd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Address"
            android:textSize="10dp"
            android:layout_alignLeft="@id/txtEmail"
            android:layout_alignBaseline="@id/txtSurname"/>

    </RelativeLayout>


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

1
请查看此答案 - Gabriele Mariotti
14个回答

118

我们可以将卡片视图的marginBottom设置为负值,其大小应与卡片的圆角相同。例如:

    <FrameLayout
        android:id="@+id/rootview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

   <android.support.v7.widget.CardView
         android:id="@+id/card_view"
         android:layout_marginBottom="-3dp"
         project:cardCornerRadius="3dp"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

         <!--The child view inside the cardview should have extra padding,so that negative margin will not affect the bottom padding of its child.Here normally we have 16dp bottom padding for child + margin bottom of the parent is 3dp=19dp comes.-->

       <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="19dp"/>

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

这对我来说是有效的。但我怀疑这是否是正确的做法。欢迎任何建议。


7
仅当卡片视图在屏幕底部时才起作用。 - tymbark
3
但是android:layout_marginBottom="-3dp"会减少CardView的高度,有没有其他替代方案可以达到同样的效果。 - Arbaz.in
谢谢你的回答,但是在我使用的旧版Lollipop设备上并没有起作用。 - Surendar Dharavath
太棒了!真棒! - Felipe
只需尝试半圆形视图,您就会知道错误所在。 - Vikas Acharya

37

或者,您可以使用MaterialCardView

<com.google.android.material.card.MaterialCardView
            style="@style/CustomCardViewStyle"
            ...>         
</com.google.android.material.card.MaterialCardView>

    <style name="CustomCardViewStyle" parent="@style/Widget.MaterialComponents.CardView">
         <item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay_card_custom_corners</item>
      </style>
    
    
          <style name="ShapeAppearanceOverlay_card_custom_corners" parent="">
            <item name="cornerFamily">rounded</item>
            <item name="cornerSizeTopRight">4dp</item>
            <item name="cornerSizeTopLeft">8dp</item>
            <item name="cornerSizeBottomRight">16dp</item>
            <item name="cornerSizeBottomLeft">0dp</item>
          </style>

你可以在这里找到一个好答案。


2
最佳解决方案 - Михаил

31

我一直在尝试相同的方法,但提供的解决方案都没有对我起作用。

唯一有效的方法是:

1)制作自定义背景资源(例如圆角矩形形状)。

2)使用以下命令设置此自定义背景:

cardView = view.findViewById(R.id.card_view2);
cardView.setBackgroundResource(R.drawable.card_view_bg);

对我来说完美地运作了!希望这能帮到你。

我用上左和下右半径做的 XML 布局。

<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:topLeftRadius="18dp" android:bottomRightRadius="18dp" />
</shape>

在你的情况下,你只需要更改topLeftRadius和topRightRadius。


7
这种方法的问题在于,当我们设置背景时,卡片视图的大多数属性会消失,例如: 水波纹效果和高度。 - Pulkit
这个解决方案不起作用。它只在您不需要剪切CardView内容的任何部分时才起作用 - 这违背了使用CardView的目的。 - Firzen

23
这是一个棘手的问题,因为你不能让CardView做到这一点。它在内部使用一个RoundRectDrawable(包私有),它使用roundRect来实现这个功能。
 // rectf, rx, ry, paint
 canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint);

因此,你需要一个不同的解决方案,例如我找到了Ahmed-Abdelmeged的这个代码片段,他们使用画布剪辑来描述每个角落的轮廓。
所以虽然我不是编写这段代码的人,但我会在这里发布它,供将来的使用者参考。
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundedView">
        <attr name="topLeftCornerRadius" format="dimension" />
        <attr name="topRightCornerRadius" format="dimension" />
        <attr name="bottomLeftCornerRadius" format="dimension" />
        <attr name="bottomRightCornerRadius" format="dimension" />
    </declare-styleable>
</resources>

并且

package com.abdelmeged.ahmed.roundedlayout;

/**
 * Created by ahmed on 9/17/2017.
 */

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Custom wrapper view to get round corner round view
 */
public class RoundedView extends FrameLayout {

    /**
     * The corners than can be changed
     */
    private float topLeftCornerRadius;
    private float topRightCornerRadius;
    private float bottomLeftCornerRadius;
    private float bottomRightCornerRadius;

    public RoundedView(@NonNull Context context) {
        super(context);
        init(context, null, 0);
    }

    public RoundedView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public RoundedView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.RoundedView, 0, 0);

        //get the default value form the attrs
        topLeftCornerRadius = typedArray.getDimension(R.styleable.
                RoundedView_topLeftCornerRadius, 0);
        topRightCornerRadius = typedArray.getDimension(R.styleable.
                RoundedView_topRightCornerRadius, 0);
        bottomLeftCornerRadius = typedArray.getDimension(R.styleable.
                RoundedView_bottomLeftCornerRadius, 0);
        bottomRightCornerRadius = typedArray.getDimension(R.styleable.
                RoundedView_bottomRightCornerRadius, 0);

        typedArray.recycle();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }


    final Path path = new Path();

    @Override
    protected void dispatchDraw(Canvas canvas) {
        int count = canvas.save();

        path.reset();

        float[] cornerDimensions = {
                topLeftCornerRadius, topLeftCornerRadius,
                topRightCornerRadius, topRightCornerRadius,
                bottomRightCornerRadius, bottomRightCornerRadius,
                bottomLeftCornerRadius, bottomLeftCornerRadius};

        path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight())
                , cornerDimensions, Path.Direction.CW);

        canvas.clipPath(path);

        super.dispatchDraw(canvas);
        canvas.restoreToCount(count);
    }

    public void setTopLeftCornerRadius(float topLeftCornerRadius) {
        this.topLeftCornerRadius = topLeftCornerRadius;
        invalidate();
    }

    public void setTopRightCornerRadius(float topRightCornerRadius) {
        this.topRightCornerRadius = topRightCornerRadius;
        invalidate();
    }

    public void setBottomLeftCornerRadius(float bottomLeftCornerRadius) {
        this.bottomLeftCornerRadius = bottomLeftCornerRadius;
        invalidate();
    }

    public void setBottomRightCornerRadius(float bottomRightCornerRadius) {
        this.bottomRightCornerRadius = bottomRightCornerRadius;
        invalidate();
    }
}

这将允许您在图像和视图被渲染之前剪裁边缘,因此它完全符合您的要求。

2
上面链接中提供的代码与Glide图像加载器配合良好,应该接受这个答案。 - Markonioninioni
1
@EpicPandaForce 非常感谢,但您能否提供一种添加高程的方法?就像在CardView中一样? - Alan Deep
阴影是填充和高程的问题。如果有效,则生效。 - EpicPandaForce

12

如果您只想对图像进行形状变换,请使用材料ShapeableImageView,该视图使用提供的形状绘制位图。

 <!-- Media -->
<com.google.android.material.imageview.ShapeableImageView
  ...
     app:shapeAppearance="?attr/shapeAppearanceMediumComponent"
     app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Card.Media" />

res/values/styles.xml 中:

<style name="ShapeAppearanceOverlay.App.Card.Media" parent="">
    <item name="cornerSizeBottomLeft">0dp</item>
    <item name="cornerSizeBottomRight">0dp</item>
    <item name="cornerSizeTopLeft">8dp</item>
    <item name="cornerSizeTopRight">8dp</item>
</style>

3

我非常渴望找到一种方法来实现这个目标,但有一种方法是不可能的,而创造自己的阴影则不太让我满意。幸运的是,在我的情况下,我需要它在屏幕右上角。

让我们简单点,将超大的卡片视图转换为另一个视图,在我的情况下,我使用框架布局然后改变它的x和y平移值以达到需要的效果。我所做的就是把平移x和y设置成相同的卡片圆角值,然后你就可以得到一个单边圆角的卡片视图,虽然制作方法有些狂野。

代码?样例? 这里你可以看到:

<FrameLayout
    android:id="@+id/miniTimer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="@+id/frameLayout"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <androidx.cardview.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:translationX="10dp"
        android:translationY="-10dp"
        app:cardBackgroundColor="@android:color/transparent"
        app:cardCornerRadius="10dp"
        app:cardUseCompatPadding="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/drwable_red__rounded_botleft_10"
            android:gravity="center"
            android:orientation="horizontal"
            android:paddingStart="5dp"
            android:paddingLeft="5dp"
            android:paddingTop="10dp"
            android:paddingEnd="10dp"
            android:paddingRight="10dp"
            android:paddingBottom="5dp">

            <TextView
                android:id="@+id/miniTimerText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/colorAccent"
                android:textSize="12dp" />

        </LinearLayout>
    </androidx.cardview.widget.CardView>
</FrameLayout>

注意:哦,我动态生成 TextView 文本,因此请自行添加它 :)


来自评论:首先,欢迎来到 Stack Overflow。由于缺乏标点符号和语法问题,我几乎无法理解你的答案,尽管它看起来是一个可能的解决方案。你能否编辑这篇文章并改进解释文本?谢谢。 - sɐunıɔןɐqɐp

1

最好更新你的CardView表单:

androidx.cardview.widget.CardView

转换为新的内容:

com.google.android.material.card.MaterialCardView

像这样:

<com.google.android.material.card.MaterialCardView
            android:id="@+id/bottomCard"
            android:layout_width="70dp"
            android:layout_height="70dp">

然后在 Kotlin 中使用如下:

 var shapeAppearanceModel: ShapeAppearanceModel.Builder =ShapeAppearanceModel().toBuilder()
        shapeAppearanceModel.setBottomRightCorner(
            CornerFamily.ROUNDED,
            CornerSize { return@CornerSize 45F })
        binding.bottomCard.shapeAppearanceModel =shapeAppearanceModel.build()

你可以用替代来代替绑定

bottomCard=view.findViewById<MaterialCardView>(R.id.bottomCard) 

太棒了,它运行得像魔法一样顺畅。 - Anil Ugale

1
我只创建了卡片视图以包装图像的圆角,然后使用约束布局添加了指南线并将下面的文本布局添加到指南线中。 然后指南线与带有边距的卡片重叠。
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/card_icon"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="@dimen/_10sdp"
    android:layout_marginRight="@dimen/_10sdp"
    android:layout_marginTop="@dimen/_9sdp"
    android:elevation="@dimen/_2sdp"
    android:background="@drawable/card_top_corners"
    android:clipChildren="true"
     xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="@dimen/_152sdp"
        app:cardCornerRadius="@dimen/_10sdp"
        app:cardPreventCornerOverlap="false"
        app:cardElevation="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="@dimen/_142sdp"
            android:scaleType="centerCrop"
            android:src="@drawable/shahruk"
            android:visibility="visible" />


    </androidx.cardview.widget.CardView>

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline14"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="@dimen/_142sdp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline14">

        <TextView
            android:id="@+id/txt_title"
            style="@style/medium_14sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="start"
            android:paddingLeft="@dimen/_8sdp"
            android:paddingTop="@dimen/_8sdp"
            android:paddingRight="@dimen/_8sdp"
            android:text="Rupa Singh: First indian woman to become a Jockey."
            android:textColor="@color/city_news_text" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/_8sdp"
            android:layout_marginRight="@dimen/_8sdp"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/txt_date"
                style="@style/medium_9sp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:maxWidth="@dimen/_120sdp"
                android:maxLines="1"
                android:paddingTop="2dp"
                android:text="Today"
                android:textColor="@color/header_new"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <View
                android:id="@+id/view2"
                android:layout_width="1dp"
                android:layout_height="@dimen/_8sdp"
                android:layout_gravity="center"
                android:layout_marginLeft="@dimen/_7sdp"
                android:layout_marginRight="@dimen/_7sdp"
                android:background="@color/header_new"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toEndOf="@+id/txt_date"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/txt_special_tag"
                style="@style/medium_9sp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="start|center_vertical"
                android:maxLines="1"
                android:paddingTop="2dp"
                android:text="Top News"
                android:textColor="@color/header_new"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/view2"
                app:layout_constraintTop_toTopOf="parent" />
        </LinearLayout>

        <TextView
            style="@style/regular_11sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/_5sdp"
            android:paddingLeft="@dimen/_8sdp"
            android:paddingTop="@dimen/_2sdp"

            android:paddingRight="@dimen/_8sdp"
            android:paddingBottom="@dimen/_8sdp"
            android:text="Napur records highest temperature in summers this year with  measure of 225 degree celsius....[Read more]"
            android:textColor="@color/scheme_subtext" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

请检查图像中的结果。

0
您可以在卡片视图底部添加一个空视图,将其背景颜色设置为与卡片视图相同,并在空视图顶部给予一个小的负边距。以下是一个示例:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linBottomSheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    >


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="200dp"
        >

        <androidx.cardview.widget.CardView

            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginBottom="-8dp"
            android:elevation="2dp"
            app:cardBackgroundColor="@color/colorAccent"
            app:cardCornerRadius="10dp">




        </androidx.cardview.widget.CardView>

    </LinearLayout>

    <View
        
        android:layout_width="match_parent"
        android:layout_height="10dp"
        android:layout_marginTop="-10dp"
        android:background="@color/colorAccent" />
</LinearLayout>

0

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