本文大部分转载自
https://blog.csdn.net/aigestudio/article/details/41316141
From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵权必究!
尊重版权,感谢者的分享
setMaskFilter(MaskFilter maskfilter)是paint中的方法,它可以用来对图像进行一定的处理。这个方法需要传入一个MaskFilter对象。但MaskFilter类中没有任何实现方法,所以我们就要认识下它的两个子类BlurMaskFilter和EmbossMaskFilter,前者为模糊遮罩滤镜而后者为浮雕遮罩滤镜。
BlurMaskFilter(float radius, BlurMaskFilter.Blur style)
但是在API 16的时候该类已经被标注为过时了,我们可以在View中通过 setLayerType(LAYER_TYPE_SOFTWARE, null) 来关闭单个View的硬件加速功能
BlurMaskFilter(float radius, BlurMaskFilter.Blur style)
/**
*参数解析:
*第一个radius很容易理解,值越大我们的阴影越扩散
*
*第二个参数style表示的是模糊的类型,上面我们用到的是SOLID,其效果就是在图
*像的Alpha边界外产生一层与Paint颜色一致的阴影效果而不影响图像本身
*除了SOLID还有三种,NORMAL,OUTER和INNER
*/
SOLID
在图像的Alpha边界外产生一层与Paint颜色一致的阴影效果而不影响图像本身。
NORMAL
将整个图像模糊掉。
OUTER
会在Alpha边界外产生一层阴影且会将原本的图像变透明。
INNER
会在图像内部产生模糊。可以看见阴影在色块的内部,有种淡淡的浮雕感。
INNER效果其实并不理想,实际应用中我们使用的也少。
public class BlurMaskFilterView extends View {
private Paint shadowPaint;// 画笔
private Context mContext;// 上下文环境引用
private Bitmap srcBitmap, shadowBitmap;// 位图和阴影位图
private int x, y;// 位图绘制时左上角的起点坐标
public BlurMaskFilterView(Context context) {
this(context, null);
}
public BlurMaskFilterView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
// 记得设置模式为SOFTWARE
setLayerType(LAYER_TYPE_SOFTWARE, null);
// 初始化画笔
initPaint();
// 初始化资源
initRes(context);
}
/**
* 初始化画笔
*/
private void initPaint() {
// 实例化画笔
shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
shadowPaint.setColor(Color.DKGRAY);
shadowPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));
}
/**
* 初始化资源
*/
private void initRes(Context context) {
// 获取位图
srcBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.a);
// 获取位图的Alpha通道图
shadowBitmap = srcBitmap.extractAlpha();
/*
* 计算位图绘制时左上角的坐标使其位于屏幕中心
*/
x = MeasureUtil.getScreenSize((Activity) mContext)[0] / 2 - srcBitmap.getWidth() / 2;
y = MeasureUtil.getScreenSize((Activity) mContext)[1] / 2 - srcBitmap.getHeight() / 2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 先绘制阴影
canvas.drawBitmap(shadowBitmap, x, y, shadowPaint);
// 再绘制位图
canvas.drawBitmap(srcBitmap, x, y, null);
}
}
常用性比较低,倒不是说EmbossMaskFilter很没用,只是相对于EmbossMaskFilter实现的效果来说远不及BlurMaskFilter给人的感觉霸气
EmbossMaskFilter
的常用性比较低,倒不是说EmbossMaskFilter很没用,只是相对于EmbossMaskFilter实现的效果来说远不及BlurMaskFilter给人的感觉霸气,说了半天那么EmbossMaskFilter到底是做什么的呢?
我们先来看一张图:
这么一个看着像巧克力的东西就是用EmbossMaskFilter实现了,正如其名,他可以实现一种类似浮雕的效果,说白了就是让你绘制的图像感觉像是从屏幕中“凸”起来更有立体感一样(在设计软件中类似的效果称之为斜面浮雕)。该类也只有一个含参的构造方法EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius),这些参数理解起来要比BlurMaskFilter困难得多,如果你没有空间想象力的话,首先我们来看第一个direction指的是方向,什么方向呢?光照的方向!如果大家接触过三维设计就一定懂,没接触也没关系,我跟你说明白。假设一个没有任何光线的黑屋子里有一张桌子,桌子上有一个小球,这时我们打开桌子上的台灯,台灯照亮了小球,这时候小球的状态与下图类似:
小球最接近光源的地方肯定是最亮的这个没有异议,在参数中specular就是跟高光有关的,其值是个双向值越小或越大高光越强中间值则是最弱的,那么再看看什么是ambient呢?同样我们看个球,你会发现即便只有一盏灯光,在球底部跟桌面相接的地方依然不会出现大片的“死黑”,这是因为光线在传播的过程中碰到物体会产生反射!这种反射按照物体介质的粗糙度可以分为漫反射和镜面反射,而这里我们的小球之所以背面没有直接光照但仍能有一定的亮度就是因为大量的漫反射在空间传播让光线间接照射到小球背面,这种区别于直接照明的二次照明我们称之为间接照明,产生的光线叫做环境光ambient,参数中的该值就是用来设置环境光的,在Android中环境光默认为白色,其值越大,阴影越浅,blurRadius则是设置图像究竟“凸”出多大距离的很好理解,最难理解的一个参数是direction,上面我们也说了是光照方向的意思,该数组必须要有而且只能有三个值即float[x,y,z],这三个值代表了一个空间坐标系,我们的光照方向则由其定义,那么它是怎么定义的呢?首先x和y很好理解,平面的两个维度嘛是吧,上面我们使用的是[1,1]也就是个45度角,而z轴表示光源是在屏幕后方还是屏幕前方,上面我们是用的是1,正值表示光源往屏幕外偏移1个单位,负值表示往屏幕里面偏移,这么一说如果我把其值改为[1,1,-1]那么我们的巧克力朝着我们的一面应该就看不到了对吧,试试看撒~~~这个效果我就不截图了,因为一片漆黑……但是你依然能够看到一点点灰度~就是因为我们的环境光ambient!,如果我们把值改为[1,1,2]往屏幕外偏移两个单位,那么我们巧克力正面光照将更强:
这里要提醒一点[x,y,z]表示的是空间坐标,代表光源的位置,那么一旦这个位置确定,[ax,ay,az]则没有意义,也就是说同时扩大三个轴向值的倍数是没有意义的,最终效果还是跟[x,y,z]一样!
public class EmbossMaskFilterView extends View {
private static final int H_COUNT = 2, V_COUNT = 4;// 水平和垂直切割数
private Paint mPaint;// 画笔
private PointF[] mPointFs;// 存储各个巧克力坐上坐标的点
private int width, height;// 单个巧克力宽高
private float coorY;// 单个巧克力坐上Y轴坐标值
public EmbossMaskFilterView(Context context) {
this(context, null);
}
public EmbossMaskFilterView(Context context, AttributeSet attrs) {
super(context, attrs);
// 不使用硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
// 初始化画笔
initPaint();
// 计算参数
cal(context);
}
/**
* 初始化画笔
*/
private void initPaint() {
// 实例化画笔
mPaint = new Paint();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(0xFF603811);
// 设置画笔遮罩滤镜
mPaint.setMaskFilter(new EmbossMaskFilter(new float[] {
1, 1, 1F }, 0.1F, 10F, 20F));
}
/**
* 计算参数
*/
private void cal(Context context) {
int[] screenSize = MeasureUtil.getScreenSize((Activity) context);
width = screenSize[0] / H_COUNT;
height = screenSize[1] / V_COUNT;
int count = V_COUNT * H_COUNT;
mPointFs = new PointF[count];
for (int i = 0; i < count; i++) {
if (i % 2 == 0) {
coorY = i * height / 2F;
mPointFs[i] = new PointF(0, coorY);
} else {
mPointFs[i] = new PointF(width, coorY);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);
// 画矩形
for (int i = 0; i < V_COUNT * H_COUNT; i++) {
canvas.drawRect(mPointFs[i].x, mPointFs[i].y, mPointFs[i].x + width, mPointFs[i].y + height, mPaint);
}
}
}