CardView 高程阴影不居中?

CardView elevation shadow not centered?

我有一个 CardView 定义为

<androidx.cardview.widget.CardView
    android:layout_width="70dp"
    android:layout_height="70dp"
    app:cardCornerRadius="35dp"
    app:cardElevation="10dp">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        android:src="@drawable/ic_user_default"/>
</androidx.cardview.widget.CardView>

但不知何故我得到了这个奇怪的阴影,我无法弄清楚为什么?

我想要一个圆形的 CardView,周围有一个圆形的阴影,但我在右下角得到了一个阴影。

我错过了什么?

我尝试了一些东西,这就是我的结论。

CardView 位于 RelativeLayout 中,其中 wrap_contentlayout_height。我猜这只是包装 CardView,没有它的影子。看看下面的例子。

<?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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <androidx.cardview.widget.CardView
            android:layout_width="70dp"
            android:layout_height="70dp"
            app:cardCornerRadius="35dp"
            app:cardElevation="10dp">
        </androidx.cardview.widget.CardView>
    </RelativeLayout>

    <androidx.cardview.widget.CardView
        android:layout_width="70dp"
        android:layout_height="70dp"
        app:cardCornerRadius="35dp"
        app:cardElevation="10dp">
    </androidx.cardview.widget.CardView>

</LinearLayout>

哪个会像

这就引出了一个问题,为什么它环绕 CardView 而不是 CardView 的阴影? 还有一个问题。如何使 CardView 的阴影居中?如果仔细观察第二个 CardView,阴影底部有重力。

CardView的阴影偏差取决于它在屏幕中的位置。如下图所示,当CardView放在屏幕的左侧或右侧时,它的阴影也偏向左侧或右侧。

但是,据我所知,我们无法控制 CardView 的阴影透视,因为它没有属性可以更改。如果你想要自定义方向阴影,你应该自己做。

我建议你看看android documentation for shadows

你说:

CardView 位于 RelativeLayout 中,其中 wrap_contentlayout_height。我猜这只是包装 CardView,没有它的影子。所以这就引出了一个问题,为什么它环绕 CardView 而不是 CardView 的阴影?

以下回答原因:

Shadows are drawn by the parent of the elevated view, and thus subject to standard view clipping, clipped by the parent by default.

还有:

The bounds of a view's background drawable determine the default shape of its shadow. Consider this view, defined with a background drawable:

<TextView
    android:id="@+id/myview"
    ...
    android:elevation="2dp"
    android:background="@drawable/myrect" />

The background drawable is defined as a rectangle with rounded corners:

<!-- res/drawable/myrect.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="#42000000" />
    <corners android:radius="5dp" />
</shape>

The view casts a shadow with rounded corners, since the background drawable defines the view's outline. Providing a custom outline overrides the default shape of a view's shadow.

您已经使用 app:cardCornerRadius="35dp" 而不是自定义背景可绘制对象实现了这一点(这同样可以接受,但我认为添加这些信息可能会有所帮助,如果您需要在未来)。

回答问题CardView的阴影如何居中?可以看看material design guidelines。根据Material设计,阴影应该来自环境光(前光源)和关键光(顶部光源):

这些光源的仰角在android框架中默认分别为90度和45度,不能更改,因为那样会与material设计不一致。但是,如果您想创建具有自定义角度的自定义阴影,您可以使用渐变可绘制对象并将其设置为阴影,如标题 here Using Shape Drawable 中所述(实现阴影的新方法).

基本上,您需要使用 android.graphics.Paint class 中的 setShadowLayer 方法。

希望这对您有所帮助!