博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android进阶:十二、最简单的方式实现自定义阴影效果
阅读量:7039 次
发布时间:2019-06-28

本文共 6619 字,大约阅读时间需要 22 分钟。

网话说UI设计有三宝 :透明,阴影,加圆角。很多UI在做设计的时候都喜欢做卡片形式,然后添加阴影。卡片UI确实挺好看,但是对Android开发者来说,显示阴影却并不那么手到擒来,因为Android对阴影没有做出很好的支持。

CardView

谷歌也许早就注意到了UI的三宝之一阴影,于是开发了一个继承FrameLayout的CardView公开发这使用,这个控件虽然在v7包里,但是需要单独添加依赖才可以使用,就好像不是亲生的似的!

CardView本质上继承FrameLayout,需要添加依赖才可以使用:

compile 'com.android.support:cardview-v7:25.3.1'复制代码

当你知道它继承FrameLayout的时候你就知道怎么使用了,但是这个CardView有很多局限性,比如不能修改阴影的颜色,不能修改阴影的深浅。这就很诡异了,根本无法满足UI设计潮流的内心。

那为了产品蒸蒸日上,早日走上人生巅峰,实现财富自由,应该如何让你的APP支持修改阴影的颜色呢?

有个很暴力的办法,就是吧CardView的代码自己抠出来,然后自己定制.

但是现在我自己探索了一个新的较为简单的添加阴影的实现方案,仅供参考

ShadowCardView

思路:首先要明确阴影的实现思路是什么,其实就是颜色导致的视觉错觉。说白了就是在你的Card周围画一个渐变的体现立体感的颜色。

基于上述思路,我们在一个在一个view上画一个矩形的图形,让他周围有渐变色的阴影即可。于是我们想起几个API:

  • 类:Paint 用于在Android上画图的类,相当于画笔
  • 类:Canvas 相当于画布,Android上的view的绘制都与他相关
  • 方法:paint.setShadowLayer可以给绘制的图形增加阴影,还可以设置阴影的颜色

    如上图我们,红色部分使我们绘制的图形,边框以内,红色之外的是阴影的显示部分。

    有了以上的知识点已经知道可以自己画阴影了,但是什么时机开始画呢?

我们知道谷歌开发的CardView的控件继承了FrameLayout,方便我们自由扩展。那么我们也需要继承FrameLayout。

ShadowCardView继承FrameLayout之后,可以重写其一个方法:

@Override    protected void dispatchDraw(Canvas canvas) {        super.dispatchDraw(canvas);    }复制代码

这个方法是ViewGroup在绘制子View的时候调用的,那么我们可以在这个时候进行阴影的绘制。

首先,这个方法已经为我们提供了这个View的画布:Canvas,我们可以直接在上面进行阴影的绘制,代码如下:

Paint shadowPaint = new Paint();    shadowPaint.setColor(Color.RED);    shadowPaint.setStyle(Paint.Style.FILL);    shadowPaint.setAntiAlias(true);    float left = 45;    float top = 45;    float right = getWidth() - 45;    float bottom = getHeight() - 45;    shadowPaint.setShadowLayer(45, 0, 0, getContext().getResources().getColor(R.color.color_000000));    RectF rectF = new RectF(left, top, right, bottom);    canvas.drawRoundRect(rectF, 0, 0, shadowPaint);    canvas.save();复制代码
  • 创建画笔,设置画笔的颜色,风格
  • 获取绘画的范围:ShadowCard的范围减去需要的阴影的范围,假如阴影的宽度为45px,则在ShadowCard内部的45px内进行绘制
  • 给画笔设置阴影的颜色,阴影的模糊度,模糊度值越大越模糊,且不能为0
  • 创建RectF,最后开始绘画。

这样阴影就可以成功绘制了,这个方法代码量很少,很简单,也很实用。

效果如上图

为了更好的封装,我们可以为上面需要的参数进行定制,比如阴影的颜色,阴影的宽度,阴影的上下偏移,阴影的模糊度。

全部代码:

public class ShadowViewCard extends FrameLayout {    private static final int DEFAULT_VALUE_SHADOW_COLOR = R.color.shadow_default_color;    private static final int DEFAULT_VALUE_SHADOW_CARD_COLOR = R.color.shadow_card_default_color;    private static final int DEFAULT_VALUE_SHADOW_ROUND = 0;    private static final int DEFAULT_VALUE_SHADOW_RADIUS = 10;    private static final int DEFAULT_VALUE_SHADOW_TOP_HEIGHT = 5;    private static final int DEFAULT_VALUE_SHADOW_LEFT_HEIGHT = 5;    private static final int DEFAULT_VALUE_SHADOW_RIGHT_HEIGHT = 5;    private static final int DEFAULT_VALUE_SHADOW_BOTTOM_HEIGHT = 5;    private static final int DEFAULT_VALUE_SHADOW_OFFSET_Y = 0;    private static final int DEFAULT_VALUE_SHADOW_OFFSET_X = DEFAULT_VALUE_SHADOW_TOP_HEIGHT / 3;    private int shadowRound;    private int shadowColor;    private int shadowCardColor;    private int shadowRadius;    private int shadowOffsetY;    private int shadowOffsetX;    private int shadowTopHeight;    private int shadowLeftHeight;    private int shadowRightHeight;    private int shadowBottomHeight;    public ShadowViewCard(Context context) {        this(context, null);    }    public ShadowViewCard(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public ShadowViewCard(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context, attrs);    }    private void initView(Context context, AttributeSet attrs) {        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShadowViewCard);        shadowRound = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowRound, DEFAULT_VALUE_SHADOW_ROUND);        shadowColor = a.getColor(R.styleable.ShadowViewCard_shadowColor, getResources().getColor(DEFAULT_VALUE_SHADOW_COLOR));        shadowCardColor = a.getColor(R.styleable.ShadowViewCard_shadowCardColor, getResources().getColor(DEFAULT_VALUE_SHADOW_CARD_COLOR));        shadowTopHeight = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowTopHeight, dp2px(getContext(), DEFAULT_VALUE_SHADOW_TOP_HEIGHT));        shadowRightHeight = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowRightHeight, dp2px(getContext(), DEFAULT_VALUE_SHADOW_RIGHT_HEIGHT));        shadowLeftHeight = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowLeftHeight, dp2px(getContext(), DEFAULT_VALUE_SHADOW_LEFT_HEIGHT));        shadowBottomHeight = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowBottomHeight, dp2px(getContext(), DEFAULT_VALUE_SHADOW_BOTTOM_HEIGHT));        shadowOffsetY = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowOffsetY, dp2px(getContext(), DEFAULT_VALUE_SHADOW_OFFSET_Y));        shadowOffsetX = a.getDimensionPixelSize(R.styleable.ShadowViewCard_shadowOffsetX, dp2px(getContext(), DEFAULT_VALUE_SHADOW_OFFSET_X));        shadowRadius = a.getInteger(R.styleable.ShadowViewCard_shadowRadius, DEFAULT_VALUE_SHADOW_RADIUS);        a.recycle();        setPadding(shadowLeftHeight, shadowTopHeight, shadowRightHeight, shadowBottomHeight);        setLayerType(LAYER_TYPE_SOFTWARE, null);    }    public static int dp2px(Context context, float dipValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dipValue * scale + 0.5f);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    @Override    protected void dispatchDraw(Canvas canvas) {        Paint shadowPaint = new Paint();        shadowPaint.setColor(Color.WHITE);        shadowPaint.setStyle(Paint.Style.FILL);        shadowPaint.setAntiAlias(true);        float left = shadowLeftHeight;        float top = shadowTopHeight;        float right = getWidth() - shadowRightHeight;        float bottom = getHeight() - shadowBottomHeight;        shadowPaint.setShadowLayer(shadowRadius, shadowOffsetX, shadowOffsetX, shadowColor);        RectF rectF = new RectF(left, top, right, bottom);        canvas.drawRoundRect(rectF, shadowRound, shadowRound, shadowPaint);        canvas.save();        super.dispatchDraw(canvas);    }}复制代码

attr.xml

复制代码

color.xml

#1a000000
#ffffff
复制代码

喜欢我的系列性文章的话,动动你的小手指点个赞的

最后送福利了,现在关注我并且加入群聊可以获取包含源码解析,自定义View,动画实现,架构分享等。

内容难度适中,篇幅精炼,每天只需花上十几分钟阅读即可。
大家可以跟我一起探讨,欢迎加群探讨,有flutter—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料,还有更多面试题等你来拿~
群号:925019412

转载地址:http://orial.baihongyu.com/

你可能感兴趣的文章
Spring Security 学习之OpenID认证
查看>>
搭建开发使用的DNS服务器
查看>>
一般我只更新QQ空间和QQ微博
查看>>
JVM 内部运行线程介绍
查看>>
设计模式-策略模式
查看>>
一次jvm进程内存泄露问题的处理
查看>>
Centos7.2搭建SVN服务端完整配置
查看>>
基于zbus的MySQL透明代理(<100行)
查看>>
学习 Dialplan 1
查看>>
CentOS / Redhat EL 打开 sudo 功能
查看>>
我的友情链接
查看>>
每天一个linux命令(10):cat 命令
查看>>
使用Spring Interceptor实现URL访问校验
查看>>
关于awk多文件处理
查看>>
oracle分区索引和全局索引总结
查看>>
25本免费的Python电子书
查看>>
iOS新建target 管理类似的项目
查看>>
JSP学习
查看>>
改写webwind时遇到的问题
查看>>
Vector, ArrayList, LinkedList 区别与用法
查看>>