Android开发 View的阴影详解

摘要:
先给出彻底了解阴影效果实现能涉及到的属性或者Api表。translationZ="10dp"对应代码setTranslationZ()3.设置View阴影轮廓范围的模式 android:4.设置View的阴影颜色android:此条属性必需在高于Android10版本包含10的版本才有效果)5.设置View的阴影光环颜色。
前言

  Android的阴影概念是跟随Material Design设计风格出现的,因为Material Design的设计有Z轴概念,就是每个View都有自己的深度层级。Z轴的概念有了之后必然有表现这一概念的阴影效果的实现。所以google在Android5.0版本添加这阴影效果的支持。此篇博客不啰嗦Material Design的部分,我们只聊聊阴影的实现。

实现阴影功能的Api组件有那些?

  这里,先给出彻底了解阴影效果实现能涉及到的属性或者Api表。这样有一个笼统的概念,后面会一一讲解,就会了解这些组件各种涉及的功能范围。

1.设置View的Z轴高度  android:elevation="10dp"   对应代码  setElevation(); 

2.设置View的Z轴高度  android:translationZ="10dp" 对应代码 setTranslationZ()

3.设置View阴影轮廓范围的模式  android:outlineProvider="" 对应代码  setOutlineProvider();

4.设置View的阴影颜色 android:outlineSpotShadowColor="#03A9F4" 对应代码 setOutlineSpotShadowColor()(请注意!此条属性必需在高于Android10版本包含10的版本才有效果)

5.设置View的阴影光环颜色,但是基本看不到,非常迷惑的属性。 android:outlineAmbientShadowColor="#03A9F4" 对应代码 setOutlineAmbientShadowColor(请注意!此条属性必需在高于Android10版本包含10的版本才有效果)

6.设置View自定义形状的阴影 setOutlineProvider(new ViewOutlineProvider(){ //略..});

特别需要注意的地方

  在开始之前,还是说一下要避坑的地方。

  1. 请开启硬件加速功能 android:hardwareAccelerated="true" 现在的设备一般是默认开启硬件加速的。但是如果你主动设置关闭会出现没有阴影效果的问题。
  2. 请检查好自己的Android版本,必需在5.0以上。设置阴影颜色效果必需需要在10.0以上。
  3. 阴影是绘制于父控件上的,所以控件与父控件的边界之间需有足够空间绘制出阴影才行。
  4. 如果未设置 android:outlineProvider="bounds" ,那么控件这个属性会默认为android:outlineProvider="background", 这个时候View必须设置背景色,且不能为透明,否则会没有阴影。
  5. 不能将elevation 或者 translationZ 的值设置的比整个View还大,这样会有阴影效果。但是阴影的渐进效果会被拉的很长很长,会看不清楚阴影效果,你会错认觉得没有阴影效果。
android:elevation与android:translationZ

这两个属性都是设置View的Z轴高度,他们的关系是: 实际ViewZ轴高度 = elevation + translationZ

google为什么要这么别扭的弄出2个一样功能的实现来配置Z轴高度呢?这就是涉及到他们2个的区别:

  • elevation 是View的默认值Z轴高度
  • translationZ 是View的动态Z轴高度,什么是动态高度? 就是假设你需要实现阴影动画,改变Z轴高度,你就应该使用此条属性。

实现阴影动画例子

xml:

    <TextView
        android:id="@+id/view_1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="内容1"
        android:elevation="10dp"
        android:gravity="center"
        android:layout_marginTop="30dp"
        android:outlineProvider="bounds"
        android:outlineSpotShadowColor="#FF1100"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </TextView>

注意,因为下面的效果图是git,但是git图压缩的很厉害,为了阴影效果看的更清楚,所以我这里设置了 android:outlineProvider="bounds" 属性 与 改变了阴影颜色 android:outlineSpotShadowColor="#FF1100" 让下面的效果图更明显。 如果你是自己实验此代码可以忽略这2个属性。

java

     mView1 = findViewById(R.id.view_1);
        mView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                float[] floats = new float[]{50, 30, 0};
                ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView1, "translationZ", floats);
                objectAnimator.setDuration(10 * 1000);
                objectAnimator.setInterpolator(new CycleInterpolator(3f));
                objectAnimator.start();
            }
        });

效果图:

Android开发 View的阴影详解第1张

android:outlineSpotShadowColor 与 android:outlineAmbientShadowColor

 在上面已经说明过了,就是改变阴影的颜色,但是此api一定得需要Android10.0以上(包含10)版本才能生效。效果图也可以参考上面的。

android:outlineProvider

   阴影有一个轮廓的概念,那就是这个View的是什么形状的,换句话说这个View背景是什么形状的,阴影就需要根据View的背景形状而改变阴影形状的。举一个栗子:假如有一个圆形背景的View出现了一个正方形轮廓的阴影。多么怪异,阴影都到圆形的外面了,不是环绕的圆形阴影。所以,深入了解android:outlineProvider可以配置4个属性对你需要什么轮廓的阴影是非常有意义的。

background

设置这个属性,阴影轮廓将跟随 android:background="@drawable/circle" 设置的shape形状改变。 但是其实非常鸡肋,个人亲自验证过只有 以下2种shape才会有轮廓阴影如下。其他2个ring与line,空心矩形,都不支持。另外不支持矢量图与位图,这2个别多想了

支持的圆形

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@color/colorAccent"/>
</shape>

支持的圆角矩形

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/colorAccent"/>
    <corners android:radius="20dp"/>
</shape>

例子:

    <TextView
        android:id="@+id/view_1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="内容1"
        android:elevation="10dp"
        android:gravity="center"
        android:background="@drawable/circle"
        android:outlineProvider="background"
        android:layout_marginTop="30dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </TextView>

效果图:

Android开发 View的阴影详解第2张

none

设置阴影轮廓为null,设置后View将没有阴影。

bounds

设置这个属性,为视图View的边界生成不透明的轮廓

paddedBounds

 与bounds类似,设置这个属性,为视图View的填充边界生成不透明的轮廓。

setOutlineProvider

   此api其实就是对应android:outlineProvider这个属性的,除了可以在代码上设置3种不同的属性 BACKGROUNDBOUNDSPADDED_BOUNDS (是的,少了none)。

3个预设属性

        mView1.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
        mView1.setOutlineProvider(ViewOutlineProvider.BOUNDS);
        mView1.setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS);

与直接设置android:outlineProvider不同的地方是,它可以自定义阴影轮廓。所以,这里就只重点关注怎么自定义阴影轮廓

自定义阴影轮廓

        mView1.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {

            }
        });

实现自定义,我们需要new一个ViewOutlineProvider抽象方法,重写getOutline方法。这里面Outline这个返回值是处理阴影轮廓的重点。

Outline的Api

  • public void setOval(int left, int top, int right, int bottom)                设置圆形阴影轮廓,参数是4个边的坐标值
  • public void setOval(@NonNull Rect rect)                    设置圆形阴影轮廓,包含4个坐标值的Rect
  • public void setRoundRect(int left, int top, int right, int bottom, float radius)      设置圆角矩形阴影轮廓,参数是4个边的坐标值与一个圆角半径
  • public void setRoundRect(@NonNull Rect rect, float radius)                            设置圆角矩形阴影轮廓,包含4个坐标值的Rect与一个圆角半径
  • public void setEmpty()                             设置为空,无阴影
  • public void set(@NonNull Outline src)                    设置另一个Outline并且复制成为当前View的阴影轮廓
  • public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha)         设置阴影的透明度,取值范围是0.0到 1.0
  • public void setConvexPath(@NonNull Path convexPath)             设置传入一个凸Path,成为阴影轮廓
  • public void offset(int dx, int dy)                       设置阴影的坐标偏移

setOval()

设置阴影轮廓为圆形

xml

    <TextView
        android:id="@+id/view_1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="内容1"
        android:elevation="20dp"
        android:background="@android:color/holo_orange_dark"
        android:gravity="center"
        android:layout_marginTop="30dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </TextView>

java

        mView1.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                outline.setOval(0, 0, view.getWidth(), view.getHeight());
            }
        });
        mView1.setClipToOutline(true);//开启裁剪到轮廓

这里设置 mView1.setClipToOutline(true); 这个属性,在设置阴影轮廓为圆形的同时,也会将View的背景裁剪成圆。所以,有一些人会有一些奇思妙想,比如把这个作为裁剪View的手段。比如把ImageView裁剪成圆形,这样设置的ImageView的图片也会变成圆形。这种用法没错,但是与google的目的有些背道而驰,google只是希望快速的方便你根据阴影形状改变下View的背景形状,而不是将它作为裁剪View背景的方法。如果将setOutlineProvidersetClipToOutline的组合理解成裁剪View的背景,那就大错特错了。并且setClipToOutline 这个方法十分鸡肋,根本无法满足你裁剪View背景的需求,这个后面在说。(裁剪View的背景的正道还是自定义View,自己去实现onDraw方法)

效果图:

Android开发 View的阴影详解第3张

setRoundRect()

设置阴影轮廓为圆角矩形

xml

与上面圆形阴影一样

java

        mView1.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30);
            }
        });
        mView1.setClipToOutline(true);//开启裁剪到轮廓

效果图:

Android开发 View的阴影详解第4张

setConvexPath()

这个方法就很有趣了,我经过多次尝试终于明白了,这个方法怎么使用。 这些说明setConvexPath方法的特别注意点:

1.setConvexPath 设置的Path必需是凸的

2.setConvexPath 无法配合 setClipToOutline方法裁剪View的背景,所以在前面说setClipToOutline其实很鸡肋。

setConvexPath 设置的Path必需是凸的

这里我用2个图片举例,你就会明白什么是凸的图像。

凸图像:

凸图像的意思是,这个图像必需是闭合且是实心的。不能只是2个线条,必需是3个以上的线条组成的一个闭合实心图像。这个矩形就是凸的图像,它有4个边线组成且是实心的。

Android开发 View的阴影详解第5张

不是凸的图像:

这个空心矩形就不是凸的。

Android开发 View的阴影详解第6张

给一个View是三角形背景加阴影轮廓的例子

给一个View是三角形背景加阴影轮廓,假设我们现在需要给下面的矢量图背景添加一个阴影轮廓。

Android开发 View的阴影详解第7张

如果我们只使用xml属性的,期望android:outlineProvider="background" 这个属性实现阴影,可以看到完全没有阴影的View。因为之前说了 background 这个属性不支持矢量图与位图的。

xml

    <TextView
        android:id="@+id/view_1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="内容1"
        android:elevation="20dp"
        android:background="@drawable/ic_triangle"
        android:gravity="center"
        android:layout_marginTop="30dp"
        android:outlineProvider="background"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </TextView>

没有阴影效果的View:

Android开发 View的阴影详解第8张

通过自定义阴影轮廓给View加上一个三角形的阴影轮廓

xml

    <TextView
        android:id="@+id/view_1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="内容1"
        android:elevation="30dp"
        android:background="@drawable/ic_triangle"
        android:gravity="center"
        android:layout_marginTop="30dp"
        android:outlineProvider="bounds"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </TextView>

java

        mView1.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                Path path = new Path();
                path.moveTo(0,0);
                path.lineTo(view.getWidth(), 0);
                path.lineTo(0, view.getHeight());
                //闭合路径
                path.close();
                outline.setConvexPath(path);

            }
        });

带三角形阴影轮廓的效果图:

Android开发 View的阴影详解第9张

如何取消Button控件阴影?

android:elevation="0dp" 设置为0就已经取消了控件的阴影.但是这里Button有一个坑...

关于Button坑

在Android5.1之后Button控件其实是强制保持在所有控件最上面的,android:elevation="0dp" 无法让Button的强制最上层属性被改变.这个时候需要就需要android:stateListAnimator="@null"这个属性.

 
 
End

免责声明:文章转载自《Android开发 View的阴影详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇设置安卓开机动画、开机logoredis 常用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

四、 MySQL客户端工具及SQL讲解

一.客户端命令介绍 mysql客户端命令 ​ 1、用于数据库的连接管理 1) 连接(略) 2) 管理: 3)接收用户的SQL语句 #MySQL接口自带的命令 h 或 help 或? 查看帮助,查看mysql的管理命令 G 格式化查看数据(结果以key:value形式展示) T 或 tee...

Bmob云IM实现头像更换并存入Bmob云数据库中(1.拍照替换,2.相册选择)

看图效果如下: 1.个人资料界面 2.点击头像弹出对话框 3.点击拍照 4.切割图片,选择合适的部分   5.点击保存,头像替换完毕,下面看从相册中选择图片。 6.点击相册 7.任选一张图片 8.切割图片  9.图片替换成功 亲测退出账户后重新登陆或者换模拟器登陆有效!!! 图片已经上传到云端了!!! 下面先上xml代码: 里面出现的可能报...

安卓ImageButton圆角按钮设置

首先图片要做成圆角的,使用美图秀秀,这个不多说。 之后使用设置了圆角的按钮,效果有缺陷,按钮会有灰色的边角。 类似这样: 去掉的方法是将layout的  android:src="http://t.zoukankan.com/@drawable/xx" 改为  android:background="@drawable/xx" 达成效果:...

Unity2019使用Android Studio 4出安卓包

前言 在我所经历的项目组中有这几种方法来生成APK 直接在Unity生成APK,可以接入SDK 使用Unity导出Android Studio工程手动生成APK 使用Unity导出Android Studio工程命令行离线生成APK 这里记录一下我在项目组使用Android Studio出包的笔记。 使用Unity导出Android Studio工程前...

ReactNative 问题集合

在线流畅播放视频 (建议调用原生的视频组件, 或者在成熟的安卓 ios组件封装一层) 如何指定页面横屏 (在这个组件react-native-orientation基础上改写) webSocket不和http共享cookies 图片缓存 (react-native-fetch-blob) scrollView如何滚动 (refs获取元素在scrollTo)...

Mybatis标签及使用1

Mysatis的特点是以SQL语句为核心的不完全的ORM(关系型映射)框架 parameterType:在SQL映射文件中指定输入参数类型的,基本类型(int、float)、包装数据类型(String、Integer)以及用户自己编写的JavaBean封装类 resultType:指定数据库返回信息对应的Java的数据类型。在加载SQL配置,并绑定指定输入...