Android 视图高度和阴影的那点事儿

CharmainGra 8年前
   <p>Material Design 规范针对 UI 元素提出了“高度”这一概念,使过去流行于拟物化设计中的阴影效果,在扁平化设计中消失了很久之后,再次显现。不过,虽然视图高度更多的是以阴影的形式直观地表现在界面中,但更多地是强调一个元素相对重要性的问题。在三维空间中,拥有更高高度的 UI 元素,显然对于用户来讲,相比于其他元素,更加凸显其重要性,更加希望被用户注意到,甚至被频繁操作,这也是设计人员最想表达的初衷。</p>    <h2>Android 中的视图高度: Z 属性</h2>    <p>了解三维空间中的 Z 属性,引用 官网 的一段介绍:</p>    <p>由 Z 属性所表示的视图高度将决定其阴影的视觉外观:拥有较高 Z 值的视图将投射更大且更柔和的阴影。 拥有较高 Z 值的视图将挡住拥有较低 Z 值的视图;不过视图的 Z 值并不影响视图的大小。</p>    <p>阴影是由提升的视图的父项所绘制,因此将受到标准视图裁剪的影响,而在默认情况下裁剪将由父项执行。</p>    <p>具体体现在 API 上,请看这一表达式:</p>    <p>Z = elevation + translationZ</p>    <p>也就是说,视图高度由 elevation 和 translationZ 属性决定:</p>    <ul>     <li><strong>elevation</strong> :高度,静态组件,用于提升 UI 元素高度的属性;</li>     <li><strong>translationZ</strong> :Z 值转换,动态组件,常用于操作 UI 元素时交互动画的属性。</li>    </ul>    <p>不同视图高度呈现出的阴影效果如图所示:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0b388e17c89b2f201455c7ef79415c91.png"></p>    <h2>elevation 属性</h2>    <p>UI 控件的 elevation 属性可以设置其高度,呈现在界面中的直观效果就是阴影效果,在 xml 布局文件中,通过 android:elevation 属性设置,在 java 代码中通过 View 类提供的 setElevation() 方法设置。但是这个属性存在版本兼容问题,是 Android 5.0 引进的 API。所以,当 minSdkVersion 值小于21时,系统会在 xml 的对应使用地方给出一个 lint 提示:</p>    <p>Attribute elevation is only used in API level 21 and higher</p>    <p>当然你也可以选择忽略这个提示,或者使用 tools:targetApi 属性消除这个提示,这样做的话,在低于 5.0 版本的系统中将不会出现阴影效果。然而,有一个更好的办法做到兼容,那就是借助 ViewCompat 这个万能的兼容类,使 View 的 elevation 属性兼容至低版本中:</p>    <p>ViewCompat.setElevation(View view, float elevation)</p>    <p>注意:尤其要注意,视图的阴影一定是由有轮廓的视图投射出来的。简单来说,就是需要设置控件的背景,即 android:background 属性。我们可以选择图片作为背景,也可以使用 <shape> 标签定义一个 drawable 形状,事实上,后者更为常用。</p>    <h2>translationZ 属性</h2>    <p>前面提到,elevation 偏向于一个高度上的静态提升属性,而 translationZ 偏向于一个高度上的动态转换属性,可用于设置动画,比如元素触摸状态的转换效果,如果你了解 CardView 的设计规范的话,一定了解这个概念 。</p>    <p>我们可以通过属性动画动态改变 translationZ 属性值,为视图添加高度动画,也可以在 drawable 目录下定义一个资源文件,然后通过 android:stateListAnimator="@drawable/selector_elevation" 属性显式地设置给相应的 View 控件。其中, selector_elevation 文件可以这样定义(名字可以自由编写):</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <selector xmlns:android="http://schemas.android.com/apk/res/android">      <item android:state_enabled="true" android:state_pressed="true">          <objectAnimator              android:duration="@android:integer/config_shortAnimTime"              android:propertyName="translationZ"              android:valueTo="@dimen/dp_4"              android:valueType="floatType" />      </item>      <item>          <objectAnimator              android:duration="@android:integer/config_shortAnimTime"              android:propertyName="translationZ"              android:valueTo="0dp"              android:valueType="floatType" />      </item>  </selector>  </code></pre>    <h2>实现阴影的其他方式</h2>    <p>可以看出,通过设置视图高度可以实现阴影效果。这里需要提及一点,不要与 TextView 控件的 shadow 相关属性混为一谈,后者实现的是内容文字的投影效果,具体由 shadowColor、shadowRadius、shadowDx、shadowDy 四个属性控制,与本文中介绍的视图阴影概念大相径庭。</p>    <p>像 support:design 包中的 FloatingActionBar、CardView 控件默认都实现了高度上的阴影效果。需要注意的是,前面我们提到的阴影效果都是由于视图 Z 属性提升带来的结果,形状由视图的轮廓所决定的,比如圆形、方形等,至于阴影颜色,所有 UI 元素都是一致的,是无法改变的。</p>    <p>那么还有没有其他方式实现呢,如果我想改变阴影颜色呢,或者只是局部投影呢?答案是肯定的,那就是使用带阴影的背景图,常见如 .9 图。比如,系统就给我们提供了一个带阴影效果的 .9 背景图,你可以这样使用:</p>    <pre>  <code class="language-java">android:background="@android:drawable/dialog_holo_light_frame"  </code></pre>    <p>或者你也可以通过 <layer-list> 标签去一层一层定义形状和颜色,不过比较繁琐,不如直接使用 .9 背景图片。这里给大家推荐一个在线工具,通过 GUI 方式制作 .9 阴影背景图, Android 9-patch shadow generator ,如图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b51bf932674193ad31a70c750173b3d3.png"></p>    <p>再或者,你可以尝试一下 GitHub 上的这个开源库,借鉴一下作者的思路,更灵活地实现 Android App 中的 UI 阴影效果:</p>    <p><a href="/misc/goto?guid=4959644046957523829" rel="nofollow,noindex">https://github.com/dmytrodanylyk/shadow-layout</a></p>    <p> </p>    <p>来自:http://yifeng.studio/2017/02/26/android-elevation-and-shadow/</p>    <p> </p>