安卓阴影使用大总结

最近一段时间的开发一直都没离开阴影这个词,真就和别人说的那样,设计师有三宝透明、阴影和圆角,阴影这东西说起来就一句话,做起来可真是头疼,特别是开发地图 Markers 时的时候,硬要在 Markers 边上加阴影,形状还不固定,简直把我气死了,后面还是让设计师给图片解决的。

也看了很多博客,自己也试了很多方法,下面总结一下:

阴影背景

阴影背景一般是通过资源文件引进来的,可以直接是图片,一般使用 .9 文件(可拉伸),也可以是 shape 生成的,在需要的地方引入,使用方便。

  • .9 文件

    因为 .9 文件可以在宽高方向拉伸,所以制作成阴影背景还是很合适的,特别是按钮的背景,搭配 selector 一起使用,可以实现有阴影的点击效果 。

    优点:1. 上下左右可拉伸,使用起来简单方便。2. Android Studio 可制作。
    缺点:1. 需要注意阴影占据大小,内部内容不能覆盖阴影。2. 有限制,只能左右拉伸。

  • shape 阴影背景

    shape 阴影背景一般就是通过 layer-list 实现的,通过多层不同透明度的背景叠加生成阴影效果,用起来还是挺方便,也可以修改背景的参数

    <item>
        <layer-list>
            <item>
                <shape>
                    <corners android:radius="25dp"/>
                    <solid android:color="#E4E4E4"/>
                </shape>
            </item>
            <item android:left="2dp" android:top="2dp"
                  android:bottom="2dp" android:right="2dp">
                <shape>
                    <corners android:radius="25dp"/>
                    <solid android:color="#FFFFFF"/>
                </shape>
            </item>
        </layer-list>
    </item>
    

    优点:1. 使用方便,参数可控,易修改。
    缺点:1. 需要注意阴影占据大小,内部内容不能覆盖阴影。2. 有限制,只能左右拉伸。

阴影容器

说到阴影实际上想到最多就是 CardView 了,它继承了 FramLayout,能够显示阴影效果,并且有很好的向下兼容性,实际上还是要设置一定的 padding 值才能显示出阴影,是一种用容器来显示阴影的实现方法,但是却不太好控制阴影,设计师估计会不服。。。

下面简单讲讲使用容器实现阴影的办法:

  • elevation 属性

    用了那么久的 cardElevation,你知道其实 view 也有 elevation 属性吗?使用 elevation 属性可以拔高 view 的高度,Google 爸爸就会自动给它加上阴影效果,和 CardView 类似,但是要求安卓版本不低于 v21,不太好办。

    android:elevation="100dp"
    

    Attribute elevation is only used in API level 21 and higher (current min is 19)

    优点:1. 使用方便,直接修改属性值就可以。
    缺点:1. 要求安卓最低版本较高。2. 无法控制阴影效果,只是通过 elevation 值自动生效阴影。

  • CardView

    CardView 其实和上面类似,通过修改 cardElevation 值修改阴影,并自带圆角,大受欢迎。

    优点:1. 广为使用,直接修改属性值就可以。 2. 向下兼容性好,不限制安卓版本。
    缺点:1. 无法控制阴影效果,只是通过 cardElevation 值自动生效阴影。

  • 自定义阴影容器控件

    有了 CardView 能够实现阴影,可是很多时候真不能满足设计师要求,只能自己实现阴影空间了,我这里就贴点博客和源码吧,写的挺详细,不过内容我们后面要讲,所以不多说了。

    //开源库

    https://github.com/Devlight/ShadowLayout

    //一个自定义阴影效果的博客

    https://blog.csdn.net/Android_SE/article/details/89923751

    优点:1. 可以控制阴影效果。
    缺点:1. 使用的人少,自己维护。

文本控件阴影

在 Css 里面都能很容易的控制文本的阴影,我们安卓怎么可能没有呢?下面是两种使用形式

  • XML 实现

    <TextView
           …………
            android:shadowRadius="3"
            android:shadowDx="5"
            android:shadowDy="5"
            android:shadowColor="@android:color/darker_gray"/>
    

    这里的属性实际会调用我们后面要讲到的 setShadowLayer 函数,但这几个属性只有 TextVIew 及其派生类才会有,其它类是没有的,TextVIew 的派生类如下:

    在这里插入图片描述

    常用的 TextView 、EditText、Button 都在其中。

  • 代码实现

    代码实现和 XML 类似,下面时函数原型:

    //TextView中的设置阴影函数
    public void setShadowLayer(float radius, float dx, float dy, int color) ;
    

    具体使用方法:

    TextView tv = (TextView)findViewById(R.id.tv);
    tv.setShadowLayer(2,5,5, Color.GREEN);
    

Paint.setShadowLayer实现阴影效果

上面我们讲到了 TextView 之类的控件实际时通过 setShadowLayer 方法实现的,这个方法时 Paint 的方法,我们可以在自定义控件的 onDraw 方法或者 canvas 控件中使用,可以使文字和图片产生阴影效果,下面先看函数原型:

public void setShadowLayer(float radius, float dx, float dy, int color);
//清除ShadowLayer阴影
public void clearShadowLayer() 

下面时各参数的意义:

  • float radius:意思是模糊半径,radius越大越模糊,越小越清晰,但是如果radius设置为0,则阴影消失不见。
  • float dx:阴影的横向偏移距离,正值向右偏移,负值向左偏移
  • float dy:阴影的纵向偏移距离,正值向下偏移,负值向上偏移
  • int color:绘制阴影的画笔颜色,即阴影的颜色(对图片阴影无效)

使用案例我直接拿启舰老师的,下面看图和代码:

在这里插入图片描述

public class ShadowLayerView extends View {
    private Paint mPaint = new Paint();
    private Bitmap mDogBmp;
    public ShadowLayerView(Context context) {
        super(context);
        init();
    }
 
    public ShadowLayerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    public ShadowLayerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
 
    private void init(){
        //关闭硬件加速
        setLayerType( LAYER_TYPE_SOFTWARE , null);
        mPaint.setColor(Color.GREEN);
        mPaint.setTextSize(25);
        //阴影
        mPaint.setShadowLayer(1, 10, 10, Color.GRAY);
        mDogBmp = BitmapFactory.decodeResource(getResources(),R.drawable.dog);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        canvas.drawText("启舰大SB",100,100,mPaint);
 
        canvas.drawCircle(200,200,50,mPaint);
 
        canvas.drawBitmap(mDogBmp,null,new Rect(200,300,200+mDogBmp.getWidth(),300+mDogBmp.getHeight()),mPaint);
    }
}

这里需要注意几点问题:

  1. 绘制阴影的画笔颜色对图片无效

    使用setShadowLayer所产生的阴影,对于文字和绘制的图形的阴影都是使用自定义的阴影画笔颜色来画的,而图片的阴影则是直接产生一张相同的图片,仅对阴影图片的边缘进行模糊。

  2. setShadowLayer 只有文字绘制阴影支持硬件加速

    这里有一点需要非常注意的是setShadowLayer只有文字绘制阴影支持硬件加速,其它都不支持硬件加速,所以为了方便起见,我们需要在自定义控件中禁用硬件加速。

Paint.setMaskFilter实现阴影效果

这里还是 Paint 的一个方法,它接受一个 MaskFilter 对象,这个对象有两个派生类,分别是 BlurMaskFilter 和 EmbossMaskFilter,其中 BlurMaskFilter 可以实现发光效果,而 EmbossMaskFilter 是用来实现浮雕效果的,这里我们使用 BlurMaskFilter 来实现阴影效果。

需要注意的是,setMaskFilter 是不支持硬件加速的,必须关闭硬件加速才可以。

下面先看函数原型:

public BlurMaskFilter(float radius, Blur style)

其中:

  • float radius:用来定义模糊半径,同样是高斯模糊算法。
  • Blur style:发光样式,有内发光、外发光、和内外发光,分别对应:Blur.INNER (内发光)、Blur.SOLID (外发光)、Blur.NORMAL (内外发光)、Blur.OUTER (仅发光部分可见)。

先讲一下 BlurMaskFilter 的效果吧,还是看启舰老师的例子:

public class BlurMaskFilterView extends View {
    private Paint mPaint;
    public BlurMaskFilterView(Context context) {
        super(context);
        init();
    }
 
    public BlurMaskFilterView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    public BlurMaskFilterView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
 
    private void init(){
        //关闭硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        //设置 MaskFilter
        mPaint.setMaskFilter(new BlurMaskFilter(50, Blur.INNER));
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        canvas.drawCircle(200,200,100,mPaint);
    }
}

下面时具体的效果图:

  • Blur.INNER——内发光

在这里插入图片描述

  • Blur.SOLID——外发光

在这里插入图片描述

  • Blur.NORMAL——内外发光

在这里插入图片描述

  • Blur.OUTER——仅显示发光效果

在这里插入图片描述

下面开始讲解阴影的实现,这里不使用启舰老师的例子了,因为它那阴影时通过偏移显示的,我是觉得有点怪,下面就拿上一篇博客的滑块阴影简单讲讲:

  1. 在 init 函数中设置画笔的 BlurMaskFilter,使阴影外发光,设置发光颜色为黑色。

    // 实例化阴影画笔,抗锯齿、抗抖动
    mMaskShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
    mMaskShadowPaint.setColor(Color.BLACK);
    mMaskShadowPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.SOLID));
    
  2. 使用 Bitmap 的 extractAlpha 方法产生一个只有 Alpha 值的空白图像。

    //滑块阴影
    mMaskShadowBitmap = mMaskBitmap.extractAlpha();
    
  3. 使用 drawBitmap 方法通过设置好的画笔先画出只有 Alpha 值的空白图像,再绘制原图像。

    canvas.drawBitmap(mMaskShadowBitmap, -mCaptchaX + mDragerOffset, 0, mMaskShadowPaint);
    canvas.drawBitmap(mMaskBitmap, -mCaptchaX + mDragerOffset, 0, null);
    

实现起来很简单,把上面原理搞清楚了后,很 easy,当然我这做法可能不是最好的,有时间可以改进改进。

有关 Bitmap 的相关知识可以看下面这篇博客,写的非常好,令我佩服:

https://www.jianshu.com/p/eef3daeeecbc

结语

有关阴影的东西应该都在这了吧,其他内容都没有细讲,毕竟主题是阴影,希望能给读者帮助。

end

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值