ComposeShader、BitmapShader
用法参考网址:https://blog.csdn.net/iispring/article/details/50500106
先来看一张图,这个是从APIDemo中粘贴的代码运行出来的,路径:
/Users/huozhenpeng/Library/Android/sdk/samples/android-23/legacy/ApiDemos/src/com/example/android/apis/graphics/Xformodes.java
这个是运用ComposeShader的demo效果,就是两张图片在不同混合模式下产生的效果,实现这个效果有两个地方需要注意
先绘制目标图像(dst),然后设置ComposeShader,再绘制原图像(src),源像素(src)在Canvas中对应位置上的像素称作目标像素
两张图片是覆盖绘制
什么意思呢?
示例中,dst是黄色圆形,src是蓝色矩形,但是dst这张图片代表的区域(大小)不只是黄色区域
dst和src是宽高相同的两张图片,只是dst在左上部分画了个黄色圆形,src在右下部分画了个蓝色矩形
看下代码:
package com.dongnao.ffmpegmusic;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
/**
* 作者 huozhenpeng
* 日期 2018/9/14
* 邮箱 [email protected]
*/
public class PorterView extends View {
public PorterView(Context context) {
this(context,null);
}
public PorterView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,-1);
}
public PorterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private Paint paint;
private void init()
{
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
}
private int width;
private int height;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.saveLayer(0,0,width,height,paint);
canvas.drawBitmap(createDstBitmap(),0,0,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(createSrcBitmap(),0,0,paint);
paint.setXfermode(null);
canvas.restore();
}
private Bitmap createDstBitmap()
{
Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas();
canvas.setBitmap(bitmap);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0xFFFFCC44);
canvas.drawCircle(width/4,height/4,width/4,p);
return bitmap;
}
private Bitmap createSrcBitmap()
{
Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas();
canvas.setBitmap(bitmap);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0xFF66AAFF);
canvas.drawRect(width/4,height/4,width*3/4,height*3/4,p);
return bitmap;
}
}
显示的效果:
实现一张圆形图片
这个应用场景蛮多的,比如说app中的头像啊什么的
实现这个功能也有两种做法:
第一种用ComposeShader,第二种用BitmapShader
利用ComposeShader
原理就是,先绘制一个圆形的bitmap,设置ComposeShader为SRC_IN,再绘制一个图片(要裁剪为圆形的图片,比如头像啦)
package com.dongnao.ffmpegmusic;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
/**
* 作者 huozhenpeng
* 日期 2018/9/14
* 邮箱 [email protected]
*/
public class PorterView2 extends View {
public PorterView2(Context context) {
this(context,null);
}
public PorterView2(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,-1);
}
public PorterView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private Paint paint;
private void init()
{
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
}
private int width;
private int height;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.saveLayer(0,0,width,height,paint);
canvas.drawBitmap(createDstBitmap(),0,0,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(createSrcBitmap(),0,0,paint);
paint.setXfermode(null);
canvas.restore();
}
private Bitmap createDstBitmap()
{
Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas();
canvas.setBitmap(bitmap);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(0xFFFFCC44);
canvas.drawCircle(width/2,height/2,width/2,p);
return bitmap;
}
private Bitmap createSrcBitmap()
{
Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas();
canvas.setBitmap(bitmap);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
Bitmap source=BitmapFactory.decodeResource(getResources(),R.mipmap.a);
//图片有时候会太小,一般会给设置BitmapShader
p.setShader(new BitmapShader(source, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
canvas.drawRect(0,0,width,height,p);
return bitmap;
}
private Bitmap createSrcBitmap2()
{
Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas();
canvas.setBitmap(bitmap);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
Bitmap source=BitmapFactory.decodeResource(getResources(),R.mipmap.a);
Rect rectSrc=new Rect(0,0,source.getWidth(),source.getHeight());
Rect rectDst=new Rect(0,0,width,height);
canvas.drawBitmap(source,rectSrc,rectDst,p);
return bitmap;
}
}
注意我们一般用createSrcBitmap2(),就是为了防止实际要裁剪的图片过大或者过小。
看下效果
createSrcBitmap()
createSrcBitmap2()
利用BitmapShader
利用BitmapShader就比较简单了,原理是利用BitmapShader填充画笔,然后用画笔绘制圆形
package com.dongnao.ffmpegmusic;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
/**
* 作者 huozhenpeng
* 日期 2018/9/14
* 邮箱 [email protected]
*/
public class PorterView3 extends View {
public PorterView3(Context context) {
this(context,null);
}
public PorterView3(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,-1);
}
public PorterView3(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private Paint paint;
private void init()
{
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
Bitmap source=BitmapFactory.decodeResource(getResources(),R.mipmap.a);
paint.setShader(new BitmapShader(source, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR));
}
private int width;
private int height;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawCircle(width/2,height/2,width/2,paint);
}
}
这种情况需要src比较大时才会呈现比较好的效果,而且一般会使用bitmapShader.setLocalMatrix(shaderMatrix)对bitmapShader做变换,开源库CircleImageView就是这么做的。