You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MaterialCardView旋转180度后阴影/elevation消失问题

MaterialCardView旋转180度后阴影消失的问题排查与解决方案

问题描述

开发绘图应用时,承载画布的MaterialCardView在旋转180度时阴影完全消失,但旋转90度无异常。该问题仅在手机设备出现,平板设备正常。已尝试为CardView预留更多空间、旋转后手动添加阴影等方案,均未解决。

旋转CardView核心代码

fun CanvasActivity.rotate(rotationValue: RotationValue, animate: Boolean = false) {
    rotate(rotationValue.degrees, rotationValue.clockwise, animate)
}

fun CanvasActivity.rotate(degrees: Int, clockwise: Boolean = true, animate: Boolean = false) {
    val rotationAmount = if (clockwise) {
        (binding.activityCanvasCardView.rotation + degrees)
    } else {
        (binding.activityCanvasCardView.rotation - degrees)
    }

    if (animate) {
        binding.activityCanvasCardView
            .animate()
            .rotation(rotationAmount)
    } else {
        binding.activityCanvasCardView.rotation = rotationAmount
    }
}

布局文件(activity_canvas.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/fragment_background_color_daynight"
    tools:context=".activities.canvas.CanvasActivity">
    <!-- 防止缩放时内容重叠 -->
    <View
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_topView"
        android:layout_width="0dp"
        android:layout_height="90dp"
        android:background="@color/fragment_background_color_daynight"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- 自定义颜色切换控件 -->
    <com.therealbluepandabear.pixapencil.customviews.colorswitcherview.ColorSwitcherView
        android:id="@+id/activityCanvas_colorSwitcherView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:elevation="20dp"
        android:outlineProvider="none"
        app:isPrimarySelected="true"
        app:layout_constraintEnd_toEndOf="@+id/activityCanvas_topView"
        app:layout_constraintTop_toTopOf="@+id/activityCanvas_colorPickerRecyclerView" />

    <!-- 颜色选择器列表 -->
    <androidx.recyclerview.widget.RecyclerView
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_colorPickerRecyclerView"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:orientation="horizontal"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="@+id/activityCanvas_topView"
        app:layout_constraintEnd_toStartOf="@+id/activityCanvas_colorSwitcherView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/activityCanvas_primaryFragmentHost"
        tools:listitem="@layout/color_picker_layout" />

    <!-- 用于计算画布尺寸的容器 -->
    <FrameLayout
        android:id="@+id/activityCanvas_distanceContainer"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/activityCanvas_tabLayout"
        app:layout_constraintEnd_toEndOf="@+id/activityCanvas_primaryFragmentHost"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/activityCanvas_topView" />

    <!-- 承载画布的CardView -->
    <com.google.android.material.card.MaterialCardView
        android:id="@+id/activityCanvas_cardView"
        style="@style/activityCanvas_canvasFragmentHostCardViewParent_style"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/activityCanvas_tabLayout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/activityCanvas_topView">
        <!-- 透明背景画布 -->
       <com.therealbluepandabear.pixapencil.customviews.transparentbackgroundview.TransparentBackgroundView
            android:id="@+id/activityCanvas_transparentBackgroundView"
            android:layout_width="0dp"
            android:layout_height="0dp" />

        <!-- 像素网格画布 -->
        <com.therealbluepandabear.pixapencil.customviews.pixelgridview.PixelGridView
            android:id="@+id/activityCanvas_pixelGridView"
            android:layout_width="0dp"
            android:layout_height="0dp" />
    </com.google.android.material.card.MaterialCardView>

    <!-- 底部功能标签栏 -->
    <com.google.android.material.tabs.TabLayout
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_tabLayout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:tabStripEnabled="false"
        app:layout_constraintBottom_toTopOf="@+id/activityCanvas_viewPager2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">
        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/activityCanvas_tab_tools_str" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/activityCanvas_tab_filters_str" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/activityCanvas_tab_color_palettes_str" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/activityCanvas_tab_brushes_str" />
    </com.google.android.material.tabs.TabLayout>

    <!-- 画布移动交互层 -->
    <View
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_moveView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="@+id/activityCanvas_distanceContainer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/activityCanvas_topView" />

    <!-- 功能面板容器 -->
    <androidx.viewpager2.widget.ViewPager2
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_viewPager2"
        android:layout_width="0dp"
        android:layout_height="110dp"
        app:layout_constraintBottom_toBottomOf="@+id/activityCanvas_primaryFragmentHost"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <!-- Snackbar交互容器 -->
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_coordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <!-- 全屏Fragment容器 -->
    <FrameLayout
        android:elevation="20dp"
        android:outlineProvider="none"
        android:id="@+id/activityCanvas_primaryFragmentHost"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

现象对比

  • 0度:阴影正常显示
  • 90度:阴影正常显示
  • 180度:阴影完全消失

实用解决方案

1. 强制重绘CardView阴影

旋转完成后手动触发阴影重绘,避免系统优化导致阴影丢失:

// 非动画旋转场景
binding.activityCanvasCardView.rotation = rotationAmount
binding.activityCanvasCardView.invalidateOutline()

// 动画旋转场景
binding.activityCanvasCardView
    .animate()
    .rotation(rotationAmount)
    .withEndAction {
        binding.activityCanvasCardView.invalidateOutline()
    }

2. 旋转内部内容而非CardView本身

避免直接旋转MaterialCardView,转而旋转其内部容器,保持CardView本身状态不变:

<com.google.android.material.card.MaterialCardView
    android:id="@+id/activityCanvas_cardView"
    ...>
    <FrameLayout
        android:id="@+id/activityCanvas_innerContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.therealbluepandabear.pixapencil.customviews.transparentbackgroundview.TransparentBackgroundView
            ... />
        <com.therealbluepandabear.pixapencil.customviews.pixelgridview.PixelGridView
            ... />
    </FrameLayout>
</com.google.android.material.card.MaterialCardView>

修改旋转代码,操作内部容器的rotation属性:

val innerContainer = binding.activityCanvasInnerContainer
val rotationAmount = // 计算旋转角度
innerContainer.rotation = rotationAmount

3. 优化CardView样式配置

检查CardView的style,确保开启兼容 padding 并设置合理的阴影高度:

<style name="activityCanvas_canvasFragmentHostCardViewParent_style">
    <item name="cardElevation">4dp</item>
    <item name="useCompatPadding">true</item>
    <!-- 其他样式属性 -->
</style>

useCompatPadding可避免不同系统版本下阴影被容器裁剪。

4. 升级Material Components库

该问题可能是库的已知bug,尝试升级到最新稳定版:

implementation 'com.google.android.material:material:1.11.0' // 替换为最新版本

内容的提问来源于stack exchange,提问作者thebluepandabear

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:39:20