阴影效果 ShadowLayout 布局实现(让控件实现立体效果)

效果

第二张和第三张图是加入了阴影效果的,是不是觉得立体感很强,感觉图片是浮在屏幕上。这个效果也可以用Google 提供扩展包下的CardView控件来实现,而这篇文章是带大家自己来实现这样一个效果。

原理

我们仔细观察上图,可以发现,,有带阴影效果的图和没带阴影效果的图,其实就一个地方不同,就是在图片的底下绘制了阴影效果,而图片的大小都没变。所以我们要做的就是给子 View 绘制阴影。那么阴影部分怎么绘制呢?这里是整个效果实现的一个难点;阴影部分其实就是一张 bitmap 图片,而接下来的工作就是如何生成一张这样效果的 bitmap 图,还有就是 bitmap 图片绘制位置的确定。

实现

1、阴影效果的 bitmap 图片的生成 最简单的办法叫美工做一张,我们把他转化成.9图片,这是一种方法;还有一种方法就是用代码生成这样一张 bitmap,要实现这样的效果,我们需要用到 Paint 画笔中的一个属性

public MaskFilter setMaskFilter(MaskFilter maskfilter) {//…}

这个 MaskFilter有一个子类BlurMaskFilter就能实现这样的效果,一般把它叫为毛玻璃效果。这个类的实现需要传两个参数

public BlurMaskFilter(float radius, Blur style) {//…}

radius:渐变效果的距离。

style:模式,这里有四中模式

public enum Blur {/*** Blur inside and outside the original border.*/NORMAL(0),/*** Draw solid inside the border, blur outside.*/SOLID(1),/*** Draw nothing inside the border, blur outside.*/OUTER(2),/*** Blur inside the border, draw nothing outside.*/INNER(3);Blur(int value) {native_int = value;}final int native_int;}

这几种模式到底是怎么的呢?来看看下面那张图

以上图形是通过

(RectF rect, Paint paint) {;}

看到这张图加上上面几种模式的注解,应该很清楚了。 这里有一个注意点是:我们绘制矩形的时候,如果没有设置这种模糊效果,这绘制的图形的大小就是矩形的大小,如果绘制了模糊效果,则图形的大小需要加上实例化BlurMaskFilter时候的radius,就是渐变的距离。 创建 bitmap 的代码如下:

//设置画笔的 stylemPaint.setStyle(Paint.Style.FILL);//设置画笔的模糊效果mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));//设置画笔的颜色mPaint.setColor(Color.BLACK);//创建 bitmap 图片mShadowBitmap = Bitmap.createBitmap(mOriginRect.width(), mOriginRect.height(), Bitmap.Config.ARGB_8888);//绑定到画布上Canvas canvas = new Canvas(mShadowBitmap);//让画布平移,这里为什么要平移,看了前面图片就知道canvas.translate(BLUR_WIDTH,BLUR_WIDTH);//绘制阴影效果canvas.drawRoundRect(mDesRecF, mRadius, mRadius, mPaint);

2、bitmap 图片绘制位置的确定 bitmap 的绘制,是放在

protected void dispatchDraw(Canvas canvas) {//…}

这里有各地方需要注意,需要先绘制 bitmap,在调用

super.dispatchDraw(canvas);

为什么?很好理解了,因为super.dispatchDraw(canvas);是分发绘制机制,Layout 的所有子类的绘制都需要通过它来分发,如果先绘制子类,那么 bitmap 阴影部分就会显示在子类的上面,会把子类覆盖。 代码如下:

@Overrideprotected void dispatchDraw(Canvas canvas) {int N = getChildCount() ;for (int i = 0; i < N ; i ++){View view = getChildAt(i) ;if (view.getVisibility() == GONE ||view.getVisibility() == INVISIBLE||view.getAlpha() == 0){continue;}int left = view.getLeft() ;int top = view.getTop() ;/*保存画布的位置*/canvas.save() ;/*平移画布*/canvas.translate(left + (1-mDepth)*80,top + (1-mDepth)*80);/*设置绘制阴影画笔的透明度*/mAlphaPaint.setAlpha((int) (125 + 100 * (mDepth)));/*获取阴影的绘制宽度*/mDesRecF.right = view.getWidth() ;/*获取阴影的绘制高度*/mDesRecF.bottom = view.getHeight() ;/*绘制阴影*/canvas.drawBitmap(mShadowBitmap, mOriginRect, mDesRecF, mAlphaPaint);/*还原画笔*/canvas.restore();}super.dispatchDraw(canvas);}

到这里整个效果的 Layout 布局就写完了,代码非常简洁,总共100行代码不到,索性就全部贴出来吧

/** * Created by moon.zhong on 2015/3/25. */{private float mDepth = 0.5f;private Bitmap mShadowBitmap;private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);BLUR_WIDTH = 5 ;private final Rect mOriginRect = new Rect(0,0,150+ 2*BLUR_WIDTH,150+2*BLUR_WIDTH) ;private RectF mDesRecF = new RectF(0,0,150,150) ;private int mRadius = 6 ;private Paint mAlphaPaint ;public ShadowLayout(Context context) {super(context);initView(context);}public ShadowLayout(Context context, AttributeSet attrs) {super(context, attrs);initView(context);}public ShadowLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context);}(Context context) {setWillNotDraw(false);//设置画笔的 stylemPaint.setStyle(Paint.Style.FILL);//设置画笔的模糊效果mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));//设置画笔的颜色mPaint.setColor(Color.BLACK);//创建 bitmap 图片mShadowBitmap = Bitmap.createBitmap(mOriginRect.width(), mOriginRect.height(), Bitmap.Config.ARGB_8888);//绑定到画布上Canvas canvas = new Canvas(mShadowBitmap);//让画布平移,这里为什么要平移,看了前面图片就知道canvas.translate(BLUR_WIDTH,BLUR_WIDTH);//绘制阴影效果canvas.drawRoundRect(mDesRecF, mRadius, mRadius, mPaint);mAlphaPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ;}(float depth){mDepth = depth ;invalidate();}(Canvas canvas) {int N = getChildCount() ;for (int i = 0; i < N ; i ++){View view = getChildAt(i) ;if (view.getVisibility() == GONE ||view.getVisibility() == INVISIBLE||view.getAlpha() == 0){continue;}int left = view.getLeft() ;int top = view.getTop() ;/*保存画布的位置*/canvas.save() ;/*平移画布*/canvas.translate(left + (1-mDepth)*80,top + (1-mDepth)*80);/*设置绘制阴影画笔的透明度*/mAlphaPaint.setAlpha((int) (125 + 100 * (mDepth)));/*获取阴影的绘制宽度*/mDesRecF.right = view.getWidth() ;/*获取阴影的绘制高度*/mDesRecF.bottom = view.getHeight() ;/*绘制阴影*/canvas.drawBitmap(mShadowBitmap, mOriginRect, mDesRecF, mAlphaPaint);/*还原画笔*/canvas.restore();}super.dispatchDraw(canvas);}}

再来看一下动态的效果图

总结

整体实现不是特别难,最主要的是 Paint类中 的

mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));忘掉失败,不过要牢记失败中的教训。

阴影效果 ShadowLayout 布局实现(让控件实现立体效果)

相关文章:

你感兴趣的文章:

标签云: