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

效果

这里写图片描述 
第二张和第三张图是加入了阴影效果的,是否是以为立体感很强,感受图片是浮在屏幕上。这个效果也能够用Google 提供扩展包下的CardView控件来实现,而这篇文章是带你们本身来实现这样一个效果。java

原理

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

实现

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

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

 

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

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

 

radius:渐变效果的距离。布局

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

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; }

 

这几种模式究竟是怎么的呢?来看看下面那张图 
这里写图片描述
以上图形是经过.net

public void drawRect(RectF rect, Paint paint) { ; }

 

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

//设置画笔的 style
        mPaint.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);

二、bitmap 图片绘制位置的肯定 
bitmap 的绘制,是放在code

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

 

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

super.dispatchDraw(canvas);

 

为何?很好理解了,由于super.dispatchDraw(canvas);是分发绘制机制,Layout 的全部子类的绘制都须要经过它来分发,若是先绘制子类,那么 bitmap 阴影部分就会显示在子类的上面,会把子类覆盖。 
代码以下:

@Override
    protected 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. */ public class ShadowLayout extends RelativeLayout { private float mDepth = 0.5f; private Bitmap mShadowBitmap; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final int 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); } private void initView(Context context) { setWillNotDraw(false); //设置画笔的 style mPaint.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) ; } public void setDepth(float depth){ mDepth = depth ; invalidate(); } @Override protected 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); } }

 

再来看一下动态的效果图 
这里写图片描述

总结

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

mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));

 

在建立 bitmap 的时候,bitmap 的大小必定要加上2倍的BLUR_WIDTH也就是

private final Rect mOriginRect = new Rect(0,0,150+ 2*BLUR_WIDTH,150+2*BLUR_WIDTH) ;

 

至于为何前面已经讲了。

 

http://blog.csdn.net/jxxfzgy/article/details/44644799

相关文章
相关标签/搜索