android遮罩Xfermode的学习
Posted z8z87878
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android遮罩Xfermode的学习相关的知识,希望对你有一定的参考价值。
没有绝对的实力,就看运气吧。
先看看效果吧
根据官方APIDemo给出的Xfermode例子我们可以看到下图展示那样
但是,说实话,看到这张图,我是懵逼的,我们应该去自己试一试来加深下自己的理解,所以我画了下,得到的结果如下,仅供参考!最好自己试一试
我先画的正方形,后画的圆
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); //圆和正方形相交部分清除,圆与透明部分相交也清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); //覆盖在表面,相交部分正方形被清除,圆与透明相交不被清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST)); //清除覆盖在上面的圆,圆相交不相交部分都清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));//圆覆盖在表面,正方形内部没影响,圆与透明相交不被清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));//清除覆盖在上面的圆,圆与透明部分相交不清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//显示相交的,覆盖在上面的圆,清除不相交部分的圆和相交部分的正方形
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//圆被清除,相交部分随着圆的透明度变化而正比例变化
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//清除相交部分的圆和正方形,不相交不清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//圆被清除,相交部分随着圆的透明度变化而反比例
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));//显示相交的,覆盖在上面的圆,清除不相交部分的圆不清除相交部分的正方形,和SRC_IN对比
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));//相交部分圆被清除,相交部分随着圆的透明度变化而正比例变化,与DST_IN对比
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));//相交部分圆被清除,相交部分随着圆的透明度变化而反比例变化
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));//相交部分加黑色素,透明度越大,越黑
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));//相交部分加亮色素,透明度越大,越亮
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));//相交部分加黑色素,透明度越大,越黑,圆不相交部分被清除
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));//相交部分加亮色素,透明度越大,越亮,感觉和LIGHTEN 一样
仅供参考,最好自己试一试。
弄清楚各遮罩的效果,就可以开始做了,这里面,实现圆形头像我使用的是PorterDuff.Mode.SRC_IN
//显示相交的,覆盖在上面的圆,清除不相交部分的圆和相交部分的正方形
嗯,这可以先画一个实心圆,然后在把背景图片画上去,PorterDuff.Mode.SRC_IN会清除不相交部分的背景图,所以就只剩下相交部分的圆形背景图了,这样就实现了。原理就是这样,我们来看看实际怎么实现吧
/**
* Created by Administrator on 2016/10/16 0016.
*/
public class CircleView extends View
public CircleView(Context context)
this(context,null);
public CircleView(Context context, AttributeSet attrs)
super(context, attrs);
@Override
public void draw(Canvas canvas) //重写view的draw方法,view绘制的时候会调用此方法
Bitmap bitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas1 = new Canvas(bitmap); //bitmap为画纸,canvas1是画板
super.draw(canvas1); //把背景图画在canvas1这张画板上,但注意画是画在纸上的,即背景图在bitmap上
Bitmap bitmap2 = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);//注意这里要带A即支持透明
Canvas canvas2 = new Canvas(bitmap2); //再来一张新画纸,新画板
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
canvas2.drawARGB(0,0,0,0); //初始化画纸带透明
//画实心圆 paint的style默认是fill填充的
canvas2.drawCircle(bitmap.getWidth()/2,bitmap.getHeight()/2,bitmap.getWidth()/2,paint);
//设置遮罩的模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//前面我们已经通过super.draw(canvas1);把背景都画在了画纸bitmap上,即此时画背景即是画bitmap
canvas2.drawBitmap(bitmap,0,0,paint);//此时,其实我们想要的效果就得到了,但是如果就这么结束的话,
//是不行的,因为我们画在canvas2画板上!!!而view要显示是要画在,它自己带的参数canvas画板上的!!!
//所以我们这里把canvas2画板上的画纸bitmap2画上来,这样view就达到我们想要的效果了
canvas.drawBitmap(bitmap2,0,0,null);
addStroke(canvas);
/**增加描边*/
private void addStroke(Canvas canvas)
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(getWidth() / 2, getHeight() / 2,
(float) (getHeight() / 2 -1), paint);
布局
<com.and.xfmode.views.CircleView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:background="@mipmap/tou"/>
我注释写的还算详细吧,跟着注释跟着代码一起读觉得比较好理解.
接下来的微信效果其实也是大巫小巫的问题,不是问题,这里用的是PorterDuff.Mode.SRC_ATOP
//显示相交的,覆盖在上面的圆,清除不相交部分的圆不清除相交部分的正方形,和SRC_IN对比
它与SRC_IN不同的就是他不会清除相交部分 覆盖在下面的图形,然后我们改变上面的透明度就行了。选来看看那个图标
格子表示透明,好吧,中间那坨本来也是透明的,是我涂的白色,这里推荐一个阿里的图标网站http://www.iconfont.cn/,真的很好,雷锋啊。嗯,原理是这样,来看看怎么实现吧
<com.and.xfmode.views.GradientView
android:id="@+id/gv"
android:layout_width="120dp"
android:layout_height="60dp"
android:background="#10ea10"/>
public class GradientView extends View
public GradientView(Context context)
this(context,null);
public GradientView(Context context, AttributeSet attrs)
this(context, attrs,0);
int alpha = 255;
public GradientView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
final Timer timer = new Timer();
TimerTask task = new TimerTask()
@Override
public void run()
alpha -= 10; //每300毫秒背景色越透明
if (alpha < 0)
timer.cancel();
else
postInvalidate(); //主动调draw方法刷新视图
;
timer.schedule(task,1000,300);
public Bitmap icon;
public void setBitmap(Bitmap bitmap)
icon = bitmap; //外部传图标
postInvalidate();//主动调draw方法刷新视图
private String txt;
public void setText(String text)
txt = text; //外部传文字
postInvalidate();//主动调draw方法刷新视图
@Override
public void draw(Canvas canvas) //与上面的实现圆形头像一样,只是换了个遮罩模式
Bitmap bitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas1 = new Canvas(bitmap);
super.draw(canvas1); //背景色画在bitmap上
Bitmap bitmap1 = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas2 = new Canvas(bitmap1);
canvas2.drawARGB(0,0,0,0);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(13);
paint.setColor(Color.BLACK);
if(txt != null) //画文字
canvas2.drawText(txt,getWidth()/2,getHeight()-5,paint);
if(icon != null) //画图片
Matrix matrix = new Matrix(); //帮助实现bitmap缩放
matrix.postScale(getWidth()/3.0f/icon.getWidth(),getWidth()/3.0f/icon.getHeight());
canvas2.drawBitmap(Bitmap.createBitmap(icon,0,0,icon.getWidth(),icon.getHeight(),matrix,true),getWidth()/3,0,null);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
paint.setAlpha(alpha); //透明度变化
canvas2.drawBitmap(bitmap,0,0,paint); //将背景色画在图标和文字上面,相交的部分才显示
canvas.drawBitmap(bitmap1,0,0,null); //最后画在画板上,不理解回去看圆形图片实现
//四周的边框
Paint paint1 = new Paint();
paint1.setColor(Color.RED);
paint.setAntiAlias(true);
paint1.setStyle(Paint.Style.STROKE);
canvas.drawRect(0,0,getWidth(),getHeight(),paint1);
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circle);
GradientView gv = (GradientView) findViewById(R.id.gv);
gv.setBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.weixin_logo));
gv.setText("微信");
最重要的还是知道了各种遮罩的特性,有时间自己最好试一下,下次就用这个GradientView来实现微信的底部导航菜单吧
以上是关于android遮罩Xfermode的学习的主要内容,如果未能解决你的问题,请参考以下文章