前言
根据启舰大大 的博客所学习的自定义View。
准备
使用离屏绘制
//新建图层
int layerID = canvas.saveLayer(0,0,width,height,mPaint,Canvas.ALL_SAVE_FLAG);
//TODO 核心绘制代码
//还原图层
canvas.restoreToCount(layerID);
一、方法介绍
public PorterDuffXfermode(PorterDuff.Mode mode)
- 模式的详解可以查阅上一节自定义View-第十九步:Paint之setColorFilter中混合模式的介绍。关于GOOGLE的模式为啥和那张图不一样,可以进入GOOGLE误导这个看看哈
二、举个栗子
点击时书面上升,不点击时水面下降。
目标图片live_zan 源图片heartflow
public class PorterDuffXfermodeMineView extends View {
private PorterDuffXfermode porterDuffXfermode;
private Bitmap disBitmap;
private Paint paint;
private Bitmap scrBitmap;
private int top;
public Timer timer;
public PorterDuffXfermodeMineView(Context context) {
super(context);
init(context);
}
public PorterDuffXfermodeMineView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PorterDuffXfermodeMineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
//设置模式,源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像。
porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
//初始化画笔
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setFilterBitmap(true);
paint.setDither(true);
//获取dst图片
disBitmap = ((BitmapDrawable) ContextCompat.getDrawable(context, R.mipmap.live_zan)).getBitmap();
//获取src图片
scrBitmap = ((BitmapDrawable) ContextCompat.getDrawable(context, R.mipmap.heartflow)).getBitmap();
}
@Override
protected void onDraw(Canvas canvas) {
int height = disBitmap.getHeight();
//使用离屏绘制
canvas.saveLayer(0, 0, disBitmap.getWidth(), height, null, Canvas.ALL_SAVE_FLAG);
//一定要先绘制目标图像!!!
canvas.drawBitmap(disBitmap, 0, 0, paint);
//再设置paint的xfermode模式!!!
paint.setXfermode(porterDuffXfermode);
//高度<=目标图像的1/3时,不再下降
if (top < height / 3) {
top = height / 3;
if (timer != null) {
timer.cancel();
timer = null;
}
}
else if (height + 10 < top) {
//高度最大为目标高度+10,主要是让覆盖后没有空白
top = height + 10;
}
//绘制源图像
canvas.drawBitmap(scrBitmap, 0, height - top, paint);
paint.setXfermode(null);
//还原画布
canvas.restore();
}
//点击时水面上升,不点击时则自动下降
public void click(boolean isClick) {
if (isClick) {
if (timer != null) {
timer.cancel();
timer = null;
}
top = top + 2;
}
else {
top = top - 2;
if (timer == null) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
top = top - 2;
postInvalidate();
}
}, 500, 100);
}
}
postInvalidate();
}
}
<com.crossroads.demo.demo.PorterDuffXfermodeMineView
android:layout_centerInParent="true"
android:id="@+id/heartView"
android:layout_width="60dp"
android:layout_height="60dp"/>
public class MainActivity extends Activity {
PorterDuffXfermodeMineView heartView;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (heartView != null) {
heartView.click(false);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
heartView = (PorterDuffXfermodeMineView) findViewById(R.id.heartView);
heartView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
zanStart();
}
});
}
private void zanStart() {
handler.removeMessages(1);
if (heartView != null) {
heartView.click(true);
}
handler.sendEmptyMessageDelayed(1, 1000);
}
}
刮刮卡效果,大家可以尝试自己写一下
简易刮刮卡效果public class MineView extends View {
Bitmap coverBitmap;
Bitmap answerBitmap;
Path path;
Paint paint;
Bitmap bitmapPath;
public MineView(Context context) {
this(context, null);
}
public MineView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
//初始化画笔
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(30);
paint.setAntiAlias(true);
//初始化
path = new Path();
coverBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.bear);//覆盖图
answerBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.answer);//谜底
bitmapPath = Bitmap.createBitmap(coverBitmap.getWidth(),coverBitmap.getHeight(), Bitmap.Config.ARGB_8888);//用于存储路径
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制谜底
canvas.drawBitmap(answerBitmap,0,0,paint);
//canvas调用saveLayer之后,开启了一个新的透明图层。绘制完成后再合并到上一个图层上
canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
//将手指行为保存并绘制路径
Canvas canvas1 = new Canvas(bitmapPath);
canvas1.drawPath(path, paint);
canvas.drawBitmap(bitmapPath,0,0,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
//绘制覆盖图
canvas.drawBitmap(coverBitmap,0,0,paint);
paint.setXfermode(null);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(x, y);
postInvalidate();
break;
}
return super.onTouchEvent(event);
}
// 启舰大大的touch事件是这样实现的,给大家贴出来,看看,肉眼没看出来用贝塞尔曲线效果和普通的有啥区别~
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// float mPreX = event.getX();
// float mPreY = event.getY();
// switch (event.getAction()) {
// case MotionEvent.ACTION_DOWN:
// path.moveTo(event.getX(),event.getY());
// mPreX = event.getX();
// mPreY = event.getY();
// return true;
// case MotionEvent.ACTION_MOVE:
// float endX = (mPreX+event.getX())/2;
// float endY = (mPreY+event.getY())/2;
// path.quadTo(mPreX,mPreY,endX,endY);
// mPreX = event.getX();
// mPreY =event.getY();
// postInvalidate();
// break;
// }
// return super.onTouchEvent(event);
// }
}
后记
1.刚刚看到一个 手把手教你画一个 逼格满满圆形水波纹loadingview Android的效果。
2.关于saveLayer的详细介绍请进入http://blog.csdn.net/harvic880925/article/details/51317746 ,蛮重要的,大家前往看看吧,这里不再赘述了O(∩_∩)O~
网友评论