赞
踩
Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种,这个方法跟我们上面讲到的setColorFilter蛮相似的。查看API文档发现其果然有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,这三个子类实现的功能要比setColorFilter的三个子类复杂得多。
由于AvoidXfermode, PixelXorXfermode都已经被标注为过时了,所以这次主要研究的是仍然在使用的PorterDuffXfermode:
该类同样有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),虽说构造方法的签名列表里只有一个PorterDuff.Mode的参数,但是它可以实现很多酷毙的图形效果!!而PorterDuffXfermode就是图形混合模式的意思,其概念最早来自于SIGGRAPH的Tomas Proter和Tom Duff,混合图形的概念极大地推动了图形图像学的发展,延伸到计算机图形图像学像Adobe和AutoDesk公司著名的多款设计软件都可以说一定程度上受到影响,而我们PorterDuffXfermode的名字也来源于这俩人的人名组合PorterDuff,那PorterDuffXfermode能做些什么呢?我们先来看一张API DEMO里的图片:
这张图片从一定程度上形象地说明了图形混合的作用,两个图形一圆一方通过一定的计算产生不同的组合效果,在API中Android为我们提供了18种(比上图多了两种ADD和OVERLAY)模式:
ADD:饱和相加,对图像饱和度进行相加,不常用
CLEAR:清除图像
DARKEN:变暗,较深的颜色覆盖较浅的颜色,若两者深浅程度相同则混合
DST:只显示目标图像
DST_ATOP:在源图像和目标图像相交的地方绘制【目标图像】,在不相交的地方绘制【源图像】,相交处的效果受到源图像和目标图像alpha的影响
DST_IN:只在源图像和目标图像相交的地方绘制【目标图像】,绘制效果受到源图像对应地方透明度影响
DST_OUT:只在源图像和目标图像不相交的地方绘制【目标图像】,在相交的地方根据源图像的alpha进行过滤,源图像完全不透明则完全过滤,完全透明则不过滤
DST_OVER:将目标图像放在源图像上方
LIGHTEN:变亮,与DARKEN相反,DARKEN和LIGHTEN生成的图像结果与Android对颜色值深浅的定义有关
MULTIPLY:正片叠底,源图像素颜色值乘以目标图像素颜色值除以255得到混合后图像像素颜色值
OVERLAY:叠加
SCREEN:滤色,色调均和,保留两个图层中较白的部分,较暗的部分被遮盖
SRC:只显示源图像
SRC_ATOP:在源图像和目标图像相交的地方绘制【源图像】,在不相交的地方绘制【目标图像】,相交处的效果受到源图像和目标图像alpha的影响
SRC_IN:只在源图像和目标图像相交的地方绘制【源图像】
SRC_OUT:只在源图像和目标图像不相交的地方绘制【源图像】,相交的地方根据目标图像的对应地方的alpha进行过滤,目标图像完全不透明则完全过滤,完全透明则不过滤
SRC_OVER:将源图像放在目标图像上方
XOR:在源图像和目标图像相交的地方之外绘制它们,在相交的地方受到对应alpha和色值影响,如果完全不透明则相交处完全不绘制
而上面这张图片对应的官方DEMO代码如下:https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/Xfermodes.java
- public class sampleActivity extends AppCompatActivity {
- // create a bitmap with a circle, used for the "dst" image
- static Bitmap makeDst(int w, int h) {
- Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(bm);
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
- p.setColor(0xFFFFCC44);
- c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p);
- return bm;
- }
- // create a bitmap with a rect, used for the "src" image
- static Bitmap makeSrc(int w, int h) {
- Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(bm);
- Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
- p.setColor(0xFF66AAFF);
- c.drawRect(w/3, h/3, w*19/20, h*19/20, p);
- return bm;
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(new SampleView(this));
- }
- private static class SampleView extends View {
- private static final int W = 200;
- private static final int H = 200;
- private static final int ROW_MAX = 4; // number of samples per row
- private Bitmap mSrcB;
- private Bitmap mDstB;
- private Shader mBG; // background checker-board pattern
- private static final Xfermode[] sModes = {
- new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
- new PorterDuffXfermode(PorterDuff.Mode.SRC),
- new PorterDuffXfermode(PorterDuff.Mode.DST),
- new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
- new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
- new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
- new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
- new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
- new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
- new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
- new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
- new PorterDuffXfermode(PorterDuff.Mode.XOR),
- new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
- new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
- new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
- new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
- };
- private static final String[] sLabels = {
- "Clear", "Src", "Dst", "SrcOver",
- "DstOver", "SrcIn", "DstIn", "SrcOut",
- "DstOut", "SrcATop", "DstATop", "Xor",
- "Darken", "Lighten", "Multiply", "Screen"
- };
- public SampleView(Context context) {
- super(context);
- mSrcB = makeSrc(W, H);
- mDstB = makeDst(W, H);
- // make a ckeckerboard pattern
- Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,
- 0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
- Bitmap.Config.RGB_565);
- mBG = new BitmapShader(bm,
- Shader.TileMode.REPEAT,
- Shader.TileMode.REPEAT);
- Matrix m = new Matrix();
- m.setScale(6, 6);
- mBG.setLocalMatrix(m);
- }
- @Override protected void onDraw(Canvas canvas) {
- canvas.drawColor(Color.WHITE);
- Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);
- labelP.setTextAlign(Paint.Align.CENTER);
- Paint paint = new Paint();
- paint.setFilterBitmap(false);
- canvas.translate(15, 35);
- int x = 0;
- int y = 0;
- for (int i = 0; i < sModes.length; i++) {
- // draw the border
- paint.setStyle(Paint.Style.STROKE);
- paint.setShader(null);
- canvas.drawRect(x - 0.5f, y - 0.5f,
- x + W + 0.5f, y + H + 0.5f, paint);
- // draw the checker-board pattern
- paint.setStyle(Paint.Style.FILL);
- paint.setShader(mBG);
- canvas.drawRect(x, y, x + W, y + H, paint);
- // draw the src/dst example into our offscreen bitmap
- int sc = canvas.saveLayer(x, y, x + W, y + H, null,
- Canvas.MATRIX_SAVE_FLAG |
- Canvas.CLIP_SAVE_FLAG |
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
- Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
- Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- canvas.translate(x, y);
- canvas.drawBitmap(mDstB, 0, 0, paint);
- paint.setXfermode(sModes[i]);
- canvas.drawBitmap(mSrcB, 0, 0, paint);
- paint.setXfermode(null);
- canvas.restoreToCount(sc);
- // draw the label
- canvas.drawText(sLabels[i],
- x + W/2, y - labelP.getTextSize()/2, labelP);
- x += W + 10;
- // wrap around when we've drawn enough for one row
- if ((i % ROW_MAX) == ROW_MAX - 1) {
- x = 0;
- y += H + 30;
- }
- }
- }
- }
- }
对于上面这些mode的详细介绍在GA_STUDIO的这篇文章和AIGESTUDIO的这篇文章都有非常详尽的介绍
以下是PorterDuffXfermode的一些使用场景:
1、自定义loading样式:
代码如下:
- public class LogoLoadingView extends View {
-
- private int totalW,totalH;
- private Paint paint;
- private Bitmap bitmap;
- private int currentTop;
- private RectF rectF;
- private PorterDuffXfermode xfermode;
-
- public LogoLoadingView(Context context) {
- super(context);
- init();
- }
-
- public LogoLoadingView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- private void init(){
- paint=new Paint();
- paint.setAntiAlias(true);//设置抗锯齿
- paint.setStyle(Paint.Style.FILL);//设置填充样式
- paint.setDither(true);//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
- paint.setFilterBitmap(true);//加快显示速度,本设置项依赖于dither和xfermode的设置
- bitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);//从资源文件中解析获取Bitmap
- xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
- /**
- * 设置当前矩形的高度为0
- */
- currentTop=bitmap.getHeight();
- rectF=new RectF(0,currentTop,bitmap.getWidth(),bitmap.getHeight());
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(bitmap.getWidth(),bitmap.getHeight());
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- rectF.top=currentTop;
- /**
- * 设置View的离屏缓冲。在绘图的时候新建一个“层”,所有的操作都在该层而不会影响该层以外的图像
- * 必须设置,否则设置的PorterDuffXfermode会无效,具体原因不明
- */
- int sc=canvas.saveLayer(0,0,totalW,totalH,paint,Canvas.ALL_SAVE_FLAG);
- canvas.drawBitmap(bitmap,0,0,null);
- paint.setXfermode(xfermode);
- paint.setColor(Color.RED);
- canvas.drawRect(rectF,paint);
- paint.setXfermode(null);
- /**
- * 还原画布,与canvas.saveLayer配套使用
- */
- canvas.restoreToCount(sc);
- if (currentTop>0){
- currentTop--;
- postInvalidate();
- }
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- totalW=w;
- totalH=h;
- }
- }
2、圆形图片
- 代码如下:
- public class CircleImageView extends View {
- private int resId;
- private Bitmap bitmap;
- private Paint paint;
- private int bitmapWidth,bitmapHeight;
- private int size;
- private PorterDuffXfermode xfermode;
-
- public CircleImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
- resId=array.getResourceId(R.styleable.CircleImageView_imageRes,R.mipmap.ic_launcher);
- array.recycle();
- init();
- }
-
- private void init(){
- paint=new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setDither(true);//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
- paint.setFilterBitmap(true);//加快显示速度,本设置项依赖于dither和xfermode的设置
- bitmap= BitmapFactory.decodeResource(getResources(),resId);
- bitmapWidth=bitmap.getWidth();
- bitmapHeight=bitmap.getHeight();
- xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
- size=Math.min(bitmapWidth,bitmapHeight);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(size,size);
- }
-
- /**
- * 生成圆形Bitmap
- * @return
- */
- private Bitmap makeCircle(){
- Bitmap bitmap=Bitmap.createBitmap(size,size, Bitmap.Config.ARGB_8888);
- Canvas canvas=new Canvas(bitmap);
- Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(Color.BLUE);
- paint.setStyle(Paint.Style.FILL);
- int radius=size/2;
- canvas.drawCircle(size/2,size/2,radius,paint);
- return bitmap;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int sc=canvas.saveLayer(0,0,size,size,paint,Canvas.ALL_SAVE_FLAG);
- Bitmap dst=makeCircle();
- canvas.drawBitmap(dst,0,0,paint);
- paint.setXfermode(xfermode);
- canvas.drawBitmap(bitmap,0,0,paint);
- paint.setXfermode(null);
- canvas.restoreToCount(sc);
- }
- }
对应属性定义:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="CircleImageView">
- <attr name="imageRes" format="reference"/>
- </declare-styleable>
- </resources>
关于圆形图片的详细介绍可以看鸿洋大大的这篇博文,介绍的非常详尽:
http://blog.csdn.net/lmj623565791/article/details/42094215
关于PorterDuffXfermode的应用还有非常多,这里简单介绍这几个。
以上内容大部分参考自:
http://blog.csdn.net/tianjian4592/article/details/44783283 //详解Xfermode
http://blog.csdn.net/aigestudio/article/details/41316141 //把api玩出了ps的效果,图片处理大牛
http://www.cnblogs.com/tianzhijiexian/p/4297172.html //也是详解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。