返回

Android透明背景ConstraintLayout阴影实现方案

Android

透明背景下 ConstraintLayout 的阴影效果

在 Android 应用开发中,常常需要在保持布局背景透明的同时,给布局添加阴影(elevation)效果。 这其中 ConstraintLayout 的运用十分常见。但直接设置透明背景的 ConstraintLayout 会遇到问题:阴影效果无法显示。本篇文章将深入探讨这个问题,并提供有效的解决方案。

问题分析

ConstraintLayout 设置 android:elevation 属性后,默认会在背景层上绘制阴影。当布局背景色设置为透明 (#00000000) 或未设置时,系统会认为该布局的背景完全透明,因此不会绘制阴影。实际上,阴影是附着在背景之上的。 要想显示阴影效果,必须要有一个“底”,即便是完全透明的“底”。直接把透明值设为 #00000000 并不可行,因为这时系统根本不会创建阴影所需的图层,不会产生绘制效果。

解决方案一:使用自定义 Background Drawable

最直接的方法是自定义一个 Background drawable,它包含一个透明但可被系统识别的"底", 确保 ConstraintLayout 的阴影能正确显示。这个"底"需要是有颜色,但我们可以利用透明值(alpha)来达到近似完全透明的效果。

  1. 创建一个自定义的 drawable 资源文件:res/drawable 目录下新建一个 XML 文件, 比如命名为 transparent_background_with_elevation.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#01000000" />
</shape>

注意:这里的solid颜色值不是纯透明 00000000 ,而是 01000000。 这表示有 1/255 的不透明度。这个极小的不透明度让系统可以绘制阴影效果,并且视觉上接近透明,几乎看不见。

  1. ConstraintLayout 中引用这个 drawable
<android.support.constraint.ConstraintLayout
    android:id="@+id/topBorder"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginRight="8dp"
    android:layout_marginLeft="8dp"
    android:background="@drawable/transparent_background_with_elevation"
    android:elevation="4dp"
    app:layout_constraintTop_toBottomOf="@id/tvTitle">
   <!-- Your Textview List here-->
</android.support.constraint.ConstraintLayout>

代码解释:
 -  `android:background="@drawable/transparent_background_with_elevation"` 使用刚刚创建的自定义 `drawable` 作为背景,即设置了一个带极低透明度颜色的背景。
 - `android:elevation="4dp"` 设置了布局的阴影高度,可以调整 `dp` 值来改变阴影的深浅程度。

步骤:
1. 在项目的 res/drawable 文件夹下新建 transparent_background_with_elevation.xml 文件,并复制上述 XML 代码。
2. 在相应的 ConstraintLayout 代码中,添加android:backgroundandroid:elevation属性,确保指定正确的drawable 资源和 elevation 数值。
3. 编译运行项目,即可看到 ConstraintLayout 背景透明并且具有阴影的效果。

解决方案二: 使用 View 作为 Elevation 基准面

有时候,通过修改背景 drawable 添加阴影不是最灵活的方案。我们还可以使用一个不可见的 View 作为基准面来绘制阴影。

  1. ConstraintLayout 中插入一个空的 View: 把下面的代码添加到 ConstraintLayout 内 TextView 上层.
    <View
        android:id="@+id/elevationBase"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:background="#01000000"
        android:elevation="4dp"
        />
  1. 此时,elevationBase这个 View 本身没有可视大小。但通过在ConstraintLayout中上下左右的 constraint 把高度铺满,此时系统识别到 elevationBase 并且应用设置的android:elevation="4dp" 的属性后会为其创建绘制阴影效果所需的层。这样就能使得后续布局有了绘制阴影效果的基础。

    接下来只需要确保将其他的视图添加在这个基准面之上:

    <android.support.constraint.ConstraintLayout
     android:id="@+id/topBorder"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_marginRight="8dp"
     android:layout_marginLeft="8dp"
     app:layout_constraintTop_toBottomOf="@id/tvTitle">
    
          <View
         android:id="@+id/elevationBase"
         android:layout_width="0dp"
         android:layout_height="0dp"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         android:background="#01000000"
         android:elevation="4dp"
         />
    
       <!-- TextView List ... 使用constraint 放置于这个之上-->
    
      <TextView
     android:id="@+id/tvIon"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_marginStart="8dp"
     android:layout_marginTop="5dp"
     android:text="@string/Ion"
     android:textColor="@android:color/black"
     android:textSize="18sp"
     android:textStyle="bold"
     app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintTop_toTopOf="parent"/>
    
    

</android.support.constraint.ConstraintLayout>

  步骤:

     1.  在需要添加阴影效果的`ConstraintLayout` 中插入上述 `View`。确保 View 的 ID 设置正确。
     2. 设置 `View`的约束条件(`constraintTop_toTopOf`、 `constraintBottom_toBottomOf` 、`constraintStart_toStartOf` 和`constraintEnd_toEndOf`)确保此 View 与容器一样大小。
    3. 为这个`View`添加背景颜色(`#01000000`)以及合适的 `elevation` 值,这里同样是使用了微透明度值,确保系统生成阴影所需的图层。
    4.  保证其它视图使用了正确的 `constraint` 放置于这个基准面之上。
     5.  运行应用程序。透明背景,且带有阴影效果的 `ConstraintLayout`  便呈现在眼前。

## 安全提示
在使用透明度颜色来添加阴影时,选择 `#01000000` 可以确保最小的视觉影响同时满足系统的绘制要求。同时,elevation 的数值请保持适中,以免阴影过于突兀。 使用独立的 View 作为阴影基准面提供了更好的控制和扩展性。它更适合布局元素需要调整的情况,以及在多个位置复用阴影效果。


本文提供了两种在透明背景的 ConstraintLayout 上实现阴影效果的方法,具体选择哪种方式取决于实际的开发需求。理解 Android 系统绘制阴影的机制,能让我们更好地处理此类布局问题。