前语

Android 的界面制作中,控件的暗影是我们经常会处理的一种界面元素,尤其会呈现在按钮 Button 这种需求吸引用户关注点的控件上。Android 原生供给了控件的 Z 轴特点即 elevetion 供暗影作用,可是这个作用嘛,但凡是有一点想法的 UI 都不会满足的,比方我司的,就坚决不接受。

常见的问题比方不支撑特定的暗影形状或巨细,或不允许完全自定义暗影的色彩或透明度,切图是一种办法,可是自定义 View 制作的作用会更好,究竟切图会实实在在的形成 apk 包体积的增大,而且屏幕适配也会是一个潜藏的问题危险。

结合我的经历,简单封装了一下,共享我目前运用的 ShadowView

运用

圆角矩形暗影

  1. 一般暗影

    <?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"
        tools:context=".MainActivity">
        <com.randalldev.shadowview.ShadowView
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="@id/btn_target"
            app:layout_constraintEnd_toEndOf="@id/btn_target"
            app:layout_constraintStart_toStartOf="@id/btn_target"
            app:layout_constraintTop_toTopOf="@id/btn_target"
            app:shadowBottomHeight="16dp"
            app:shadowCardColor="#FF7043"
            app:shadowColor="#FFEE58"
            app:shadowLeftHeight="16dp"
            app:shadowRadius="16dp"
            app:shadowRightHeight="16dp"
            app:shadowRound="8dp"
            app:shadowTopHeight="16dp" />
        <Button
            android:id="@+id/btn_target"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent"
            android:paddingStart="40dp"
            android:paddingEnd="40dp"
            android:paddingTop="20dp"
            android:paddingBottom="20dp"
            android:text="target button"
            android:textColor="@color/purple_700"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    【自定义 View】一个易用且好看的阴影控件

    抛开配色不谈,这个作用还能够吧

  2. 一般暗影 + 偏移

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        
            app:shadowLeftHeight="16dp"
            app:shadowOffsetX="8dp"
            app:shadowOffsetY="4dp"
            app:shadowRadius="16dp"
        
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    【自定义 View】一个易用且好看的阴影控件

圆形暗影

圆形暗影也能够认为是一种特殊的圆角矩形暗影,能够持续沿用圆角矩形的办法,或许增加 shadowShape 特点。

假如要运用圆角矩形的办法,需求事前确认方针控件的尺度,这可能会遇到屏幕适配问题,所以我这儿就直接演示运用 shadowShape 特点的办法

  1. 一般暗影

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        
            app:shadowCardColor="#FF7043"
            app:shadowColor="#FFEE58"
            app:shadowRadius="16dp"
            app:shadowShape="1" />
        <Button
            android:id="@+id/btn_target"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:background="@android:color/transparent"
            android:padding="20dp"
            android:text="target button"
            android:textColor="@color/purple_700"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintDimensionRatio="1:1"
        
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    【自定义 View】一个易用且好看的阴影控件

    很简单吧,相比圆角矩形的配置,多了一个 shadowShape 可是少了很多尺度的设置,只需求设置一个 shadowRaduis 即可。

    需求留意的是,我这儿运用了 ConstrainLayoutratio 特点设置为 1:1 来完成一个正方形的方针控件,由于在制作圆形时,是以控件的中心作为圆心来制作的,假如不是正方形就可能呈现问题了。

  2. 一般暗影 + 偏移

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        
            app:shadowCardColor="#FF7043"
            app:shadowColor="#FFEE58"
            app:shadowRadius="16dp"
            app:shadowOffsetX="4dp"
            app:shadowOffsetY="4dp"
            app:shadowShape="1" />
        
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    【自定义 View】一个易用且好看的阴影控件

这个运用起来仍是比较便利的吧,只需求方针控件设置 padding 留出足够的空间制作暗影作用即可。

而且不需求再写 drawable 文件设置控件的背景了。

当然也不是没有缺陷,目前仍是只能兼容圆角矩形和圆形。异形的暂时没用到,可能也不会去做支撑。

完成

什么是暗影

首先,暗影是什么?

在真实世界中,暗影是物体遮挡住光源的光路呈现的现象;在 Android View 系统中则是 Z 轴高度,Z 轴高度越高,暗影范围越大,色彩越深。

可是只是通过 elevetion 特点设置 Z 轴高度完成的暗影视效上往往只能说满足有无的问题,究竟国内谁按照 MD 风格去规划界面啊。

【自定义 View】一个易用且好看的阴影控件

那么,暗影是什么?

当我们自定义 View 去制作暗影的时候,其实也能够是一圈从边际向四周放射式扩散的渐变色层,从而形成一种视觉的暗影作用。

那偏移又是什么?

偏移其实便是表达光源的位置,偏移为 0,即光源在正中心光线直射,暗影作用是从边际均匀的向四周逐渐变淡。

X 偏移为正,则光源在中心偏右,Y 偏移为正,则光源在中心偏下。 若为负数则相反。视觉上则会呈现某一或两轴方向上的暗影区域偏少。

上代码

初始化

这段很简单,便是读取 attrs 特点,设置硬件加速

init {
    initView(context, attrs)
    //设置软件烘托类型,跟制作暗影相关,后边会说
    setLayerType(View.LAYER_TYPE_SOFTWARE, null)
}

制作暗影

这儿创立了一个画笔 Paint 的实例,画笔的色彩是方针控件的背景色;制作形式设置的是 FILL 表明填充形式,还有 STROKE 描边形式,FILL_AND_STROKE 描边加填充形式;AntiAlias 设置为 true 标识敞开抗锯齿。

这儿便是运用 PaintsetShadowLayer() 办法创立暗影作用,其中:

  • radius:暗影半径,值越大暗影越含糊,值为0时暗影消失。
  • dx:暗影在水平方向的偏移量,正值表明向右偏移,负值表明向左偏移。
  • dy:暗影在笔直方向的偏移量,正值表明向下偏移,负值表明向上偏移。
  • shadowColor:暗影色彩。

Canvas 能够理解为画布,根据 shadowShape 特点在画布上对应的制作圆角矩形和圆形两种不同形状。

  • drawRoundRect() 用于在 Canvas 上制作一个圆角矩形。该办法需求传递四个参数,分别是矩形左上角的 X 坐标,矩形左上角的 Y 坐标,矩形右下角的 X 坐标和矩形右下角的 Y 坐标。此外还需求供给两个额定参数,分别是圆角的 X 半径和 Y 半径。
  • canvas.drawCircle() 用于在 Canvas 上制作一个圆形。该办法需求传递三个参数,分别是圆心的 X 坐标,圆心的 Y 坐标以及圆的半径。

创立一个 RectF,也便是一个矩形目标,表明一个浮点数精度的矩形。在制作操作,比方指定制作区域、裁剪画布等经常会用到。其结构函数包括4个浮点型成员变量:left、top、right、bottom,分别表明矩形左鸿沟、上鸿沟、右鸿沟和下鸿沟的坐标值。

override fun dispatchDraw(canvas: Canvas) {
    // 配置画笔
    val shadowPaint = Paint()
    shadowPaint.color = shadowCardColor
    shadowPaint.style = Paint.Style.FILL
    shadowPaint.isAntiAlias = true
    val left = shadowLeftHeight.toFloat()
    val top = shadowTopHeight.toFloat()
    val right = (width - shadowRightHeight).toFloat()
    val bottom = (height - shadowBottomHeight).toFloat()
    // 配置暗影的范围,偏移,色彩
    shadowPaint.setShadowLayer(shadowRadius.toFloat(), shadowOffsetX.toFloat(), shadowOffsetY.toFloat(), shadowColor)
    if (shadowShape == 0) {
        // 假如制作圆角矩形的暗影,用 drawRoundRect
        val rectF = RectF(left, top, right, bottom)
        canvas.drawRoundRect(rectF, shadowRound.toFloat(), shadowRound.toFloat(), shadowPaint)
    } else {
        // 假如制作圆形的暗影,用 drawCircle
        val radius = measuredHeight.toFloat() / 2 - shadowRadius
        canvas.drawCircle(measuredHeight.toFloat() / 2, measuredHeight.toFloat() / 2, radius, shadowPaint)
    }
    shadowPaint.utilReset()
    canvas.save()
}

总结

Android 界面制作中,暗影是常见的 UI 元素之一,而 Android 原生供给的 elevation 特点虽然能够完成暗影作用,但往往不能满足 UI 规划的要求。因此,自定义 View 制作暗影的办法更为灵敏和实用。本文介绍了 ShadowView,它能够便利地制作圆角矩形和圆形的暗影,且支撑色彩、透明度和暗影形状的自定义。此外,本文还供给了运用 ShadowView 制作暗影的示例代码,可供读者参阅和运用。通过运用 ShadowView,能够愈加便利地完成杂乱、美观的暗影作用,提高 Android 使用的用户体会。

参阅文章

Android进阶:快速完成自定义暗影作用

ShadowView