简体   繁体   English

Android MaterialCardView 的投影/高度在旋转 180 度时消失

[英]Android MaterialCardView's drop shadow/elevation disappears when rotating it 180 degrees

Summarize the problem:总结问题:

I am working on a paint app, and in this app, the user has the option to rotate the canvas, this feature can be useful in some scenarios.我正在开发一个绘画应用程序,在这个应用程序中,用户可以选择旋转 canvas,这个功能在某些情况下很有用。

The problem I am having, is that when I rotate the CardView , which hosts the canvas/bitmap, 180 degrees -- the drop shadow gets lost.我遇到的问题是,当我将承载画布/位图的CardView旋转 180 度时,阴影会丢失。 I do not get this problem when I rotate the CardView 90 degrees, only 180 degrees.当我将CardView旋转 90 度时,我没有遇到这个问题,只有 180 度。

Describe what you've tried描述你尝试过的东西

I've tried many things, such as giving the CardView more space so that the drop shadow will show, or manually applying drop shadow from the code after rotating it 180 degrees, but it hasn't worked.我尝试了很多东西,例如给 CardView 更多空间以便显示投影,或者在将代码旋转 180 度后手动应用代码中的投影,但它没有奏效。

Show some code显示一些代码

Here is the code responsible for rotating the CardView (it's really simple):这是负责旋转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 : activity_canvas

<?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">
    <!-- This view is here to ensure that when the user zooms in, there is no overlap -->
    <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" />

    <!-- The ColorSwitcherView is a view I created which helps
         simplify the code for controlling the user's primary/secondary color -->
    <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" />

    <!-- The user's color palette data will be displayed in this RecyclerView -->
    <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" />

    <!-- This FrameLayout is crucial when it comes to the calculation of the TransparentBackgroundView and PixelGridView -->
    <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" />

    <!-- This gives both views (the PixelGridView and TransparentBackgroundView) a nice drop shadow -->
    <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">
        <!-- At runtime, the width and height of the TransparentBackgroundView and PixelGridView will be calculated -->
       <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>

    <!-- The primary tab layout -->
    <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>

    <!-- This view allows move functionality -->
    <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" />

    <!-- The tools, palettes, brushes, and filters fragment will be displayed inside this ViewPager -->
    <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" />

    <!-- This CoordinatorLayout is responsible for ensuring that the app's snackbars can be swiped -->
    <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" />

    <!-- All of the full page fragments will be displayed in this fragment host -->
    <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 degrees: 0度:

在此处输入图像描述

90 degrees: 90度:

在此处输入图像描述

180 degrees: 180度:

在此处输入图像描述

As you can see, no drop shadow when it's rotated 180 degrees (when the origin is 0 degrees).如您所见,旋转 180 度时(原点为 0 度时)没有阴影。

Any help would be appreciated as to why I am getting this problem, it's not major but it makes the UI of my app inconsistent.任何帮助将不胜感激为什么我会遇到这个问题,这不是主要问题,但它使我的应用程序的 UI 不一致。

Note: for some reason, I only get the issue on phones but not tablet devices.注意:由于某种原因,我只在手机上遇到问题,而不是平板设备。

You're setting android:outlineProvider="none" on most items ... while the drop-shadow being used might have the wrong offset coordinates - you'd need to substract instead of adding the offset.您在大多数项目上设置android:outlineProvider="none" ...而正在使用的投影可能具有错误的偏移坐标 - 您需要减去而不是添加偏移量。 There's too little code provided to answer this more accurately - but with high probability, the shadow is just hidden underneath the canvas, due to the stated cause.提供的代码太少,无法更准确地回答这个问题 - 但由于所述原因,阴影很可能只是隐藏在画布下方。 I'd suggest to provide your own implementation of ViewOutlineProvider and then pass this instead of none .我建议提供您自己的ViewOutlineProvider实现,然后通过 this 而不是none

您需要在android:layout_margin="16dp"的每一侧设置总计(左、右、下和上)16dp 并设置app:cardElevation="4dp" ,它会起作用。

It's a curious thing, actually.实际上,这是一件很奇怪的事情。 I've tried to rotate a simple shadowed View and it seems that it cuts off the shadow when it has 180/-180 rotation angle without any logical reason.我试图旋转一个简单的阴影视图,它似乎在没有任何逻辑原因的情况下在旋转角度为 180/-180 时切断了阴影。 I also tried to play with outline providers, buut no.我也尝试与大纲提供者一起玩,但没有。 So it's not about CardView, it rather comes from the implementation of drawing a shadow in the View class.所以这与 CardView 无关,而是来自在 View class 中绘制阴影的实现。

I've searched a bit, and it was already reported directly to Google and fixed, but probably some compat libraries still have this issue that's why you're facing it.我搜索了一下,它已经直接报告给谷歌并修复了,但可能一些兼容库仍然存在这个问题,这就是你面临它的原因。

https://issuetracker.google.com/issues/173730323 https://issuetracker.google.com/issues/173730323

https://issuetracker.google.com/issues/137454913 https://issuetracker.google.com/issues/137454913

I can suggest you creating a crutch (yeap, I know, that it's not a solution) with leaving a comment.我可以建议您创建一个拐杖(是的,我知道,这不是解决方案)并留下评论。 If your rotation is about -180/180, you can "normalize" it with "-179.9/179.9".如果你的旋转大约是 -180/180,你可以用“-179.9/179.9”“标准化”它。 In terms of the user experience it won't be visible, in terms of beautiful code - meh, but I don't see any other ways here.就用户体验而言,就漂亮的代码而言,它是不可见的——嗯,但我在这里看不到任何其他方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM