Android开发 控件阴影详情
前言
Android的阴影概念是跟随Material Design设计风格出现的,因为Material Design的设计有Z轴概念,就是每个View都有自己的深度层级。Z轴的概念有了之后必然有表现这一概念的阴影效果的实现。所以google在Android5.0版本添加这阴影效果的支持。此篇博客不啰嗦Material Design的部分,我们只聊聊阴影的实现。
实现阴影功能的Api组件有那些?
这里,先给出彻底了解阴影效果实现能涉及到的属性或者Api表。这样有一个笼统的概念,后面会一一讲解,就会了解这些组件各种涉及的功能范围。
.设置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(){ //略..});
特别需要注意的地方
在开始之前,还是说一下要避坑的地方。
- 请开启硬件加速功能 android:hardwareAccelerated="true" ,现在的设备一般是默认开启硬件加速的。但是如果你主动设置关闭会出现没有阴影效果的问题。
- 请检查好自己的Android版本,必需在5.0以上。设置阴影颜色效果必需需要在10.0以上。
- 阴影是绘制于父控件上的,所以控件与父控件的边界之间需有足够空间绘制出阴影才行。
- 如果未设置 android:outlineProvider="bounds" ,那么控件这个属性会默认为android:outlineProvider="background", 这个时候View必须设置背景色,且不能为透明,否则会没有阴影。
- 不能将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: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>
效果图:
none
设置阴影轮廓为null,设置后View将没有阴影。
bounds
设置这个属性,为视图View的边界生成不透明的轮廓
paddedBounds
与bounds类似,设置这个属性,为视图View的填充边界生成不透明的轮廓。
setOutlineProvider
此api其实就是对应android:outlineProvider这个属性的,除了可以在代码上设置3种不同的属性 BACKGROUND,BOUNDS,PADDED_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背景的方法。如果将setOutlineProvider与setClipToOutline的组合理解成裁剪View的背景,那就大错特错了。并且setClipToOutline 这个方法十分鸡肋,根本无法满足你裁剪View背景的需求,这个后面在说。(裁剪View的背景的正道还是自定义View,自己去实现onDraw方法)
效果图:
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);//开启裁剪到轮廓
效果图:
setConvexPath()
这个方法就很有趣了,我经过多次尝试终于明白了,这个方法怎么使用。 这些说明setConvexPath方法的特别注意点:
1.setConvexPath 设置的Path必需是凸的
2.setConvexPath 无法配合 setClipToOutline方法裁剪View的背景,所以在前面说setClipToOutline其实很鸡肋。
setConvexPath 设置的Path必需是凸的
这里我用2个图片举例,你就会明白什么是凸的图像。
凸图像:
凸图像的意思是,这个图像必需是闭合且是实心的。不能只是2个线条,必需是3个以上的线条组成的一个闭合实心图像。这个矩形就是凸的图像,它有4个边线组成且是实心的。
不是凸的图像:
这个空心矩形就不是凸的。
给一个View是三角形背景加阴影轮廓的例子
给一个View是三角形背景加阴影轮廓,假设我们现在需要给下面的矢量图背景添加一个阴影轮廓。
如果我们只使用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:
通过自定义阴影轮廓给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); }
});
带三角形阴影轮廓的效果图:
如何取消Button控件阴影?
android:elevation="0dp" 设置为0就已经取消了控件的阴影.但是这里Button有一个坑...
关于Button坑
在Android5.1之后Button控件其实是强制保持在所有控件最上面的,android:elevation="0dp" 无法让Button的强制最上层属性被改变.这个时候需要就需要android:stateListAnimator="@null"这个属性.
Android开发 控件阴影详情的更多相关文章
- Android 开源控件与常用开发框架开发工具类
Android的加载动画AVLoadingIndicatorView 项目地址: https://github.com/81813780/AVLoadingIndicatorView 首先,在 bui ...
- 【Android开发日记】之入门篇(十三)——Android的控件解析
Android的控件都派生自android.view.View类,在android.widget包中定义了大量的系统控件供开发者使用,开发者也可以从View类及其子类中,派生出自定义的控件. 一.An ...
- android 基础控件(EditView、SeekBar等)的属性及使用方法
android提供了大量的UI控件,本文将介绍TextView.ImageView.Button.EditView.ProgressBar.SeekBar.ScrollView.WebView ...
- Android 基本控件相关知识整理
Android应用开发的一项重要内容就是界面开发.对于用户来说,不管APP包含的逻辑多么复杂,功能多么强大,如果没有提供友好的图形交互界面,将很难吸引最终用户.作为一个程序员如何才能开发出友好的图形界 ...
- Github上star数超1000的Android列表控件
Android开发中,列表估计是最最常使用到的控件之一了.列表相关的交互如下拉刷新,上拉更多,滑动菜单,拖动排序,滑动菜单,sticky header分组,FAB等等都是十分常见的体验.Github中 ...
- 一个Demo让你掌握Android所有控件
原文:一个Demo让你掌握Android所有控件 本文是转载收藏,侵删,出处:"安卓巴士" 下面给出实现各个组件的源代码: 1.下拉框实现--Spinner packag ...
- android课程表控件、悬浮窗、Todo应用、MVP框架、Kotlin完整项目源码
Android精选源码 Android游戏2048 MVP Kotlin项目(RxJava+Rerotfit+OkHttp+Glide) Android基于自定义Span的富文本编辑器 android ...
- Delphi 7学习开发控件
我们知道使用Delphi快速开发,很大的一方面就是其强大的VCL控件,另外丰富的第三方控件也使得Delphi程序员更加快速的开发出所需要的程序.在此不特别介绍一些概念,只记录自己学习开发控件的步骤.假 ...
- Android基本控件之Menus
在我们的手机中有很多样式的菜单,比如:我们的短信界面,每条短信,我们长按都会出现一个菜单,还有很多的种类.那么现在,我们就来详细的讨论一下安卓中的菜单 Android的控件中就有这么一个,叫做Menu ...
随机推荐
- 报错:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the paren
今天在做Vue的时候,子组件关闭的时候,报如下错误 报错:vue.esm.js?65d7:610 [Vue warn]: Avoid mutating a prop directly since th ...
- topjui.common.js
function getTabWindow() { var curTabWin = null; if (topJUI.config.aloneUse) { curTabWin = window; } ...
- LED 发光二极管压降
常用发光二极管的压降 1. 直插超亮发光二极管压降 主要有三种颜色,然而三种发光二极管的压降都不相同,具体压降参考值如下: 红色发光二极管的压降为2.0--2.2V 黄色发光二极管的压降为1.8—2 ...
- POJ2406-Power Strings-KMP循环节/哈希循环节
Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc&quo ...
- adb shell 查看内存信息
1.根据包名来查看指定的APP指定数据adb shell "top | grep com.xxx.xxx" 由于这样打印出来的数据没有参数名,可以参考这个命令来看:adb shel ...
- 将excel表格或csv转换为Shapefile文件
读取csv转为shp 构造读取csv函数 def read_csv(fp): ret = [] with open(fp, 'rb') as f: for line in f: ret.append( ...
- hashmap1.7的死锁模拟
package com.cxy.springdataredis.hashmap; import javax.lang.model.element.VariableElement; import jav ...
- 调用第三方jar包_md5加密
vars.put是转换成jmeter格式
- shell 脚本 功能性语句 read,expr,test
1. read 从终端输入数据赋值给变量 read val 把读入的数据存放到val中 #!/bin/bash echo -n "please input two number :" ...
- thinkphp ASSIGN标签
ASSIGN标签用于在模板文件中赋值变量,用法如下: 直线电机厂家 <assign name="var" value="123" /> 在运行模板的 ...