自定义View的混合模式的使用实例
Posted LQS_Android
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义View的混合模式的使用实例相关的知识,希望对你有一定的参考价值。
自定义View的混合模式的使用实例一:图片倒影
package com.xw.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import com.xw.avatarview.R;
/**
* Copyright (c)2021 网络科技有限公司
*
* @author: LQS
* @date: 2021/6/9
* @description: SRC_IN 模式 特性是根据目标图像透明度来决定如何显示源图像。源图像是小狗图像,目标图像是一张遮罩图,而这张遮罩图
* 看不清楚,它是一个个从上到下的白色填充渐变 白色的透明度从49%到0%。
*/
public class InvertedImageView_SRCIN extends View {
private Paint mBitPaint;
private Bitmap BmpDST, BmpSRC, BmpRevert;
public InvertedImageView_SRCIN(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mBitPaint = new Paint();
//目标图像是一张遮罩图,而这张遮罩图看不清楚,它是一个从上到下的白色填充渐变,白色的透明度从49%到0%。
BmpDST = BitmapFactory.decodeResource(getResources(), R.drawable.dog_invert_shade, null);
//源图像是小狗图像
BmpSRC = BitmapFactory.decodeResource(getResources(), R.drawable.dog, null);
Matrix matrix = new Matrix();
//使用matrix.setScale(1F, -1F);方法来实现图片的垂直翻转,这样使用避免了使用旋转变换的复杂计算
matrix.setScale(1F, -1F);
//通过Matrix将小狗的源图像进行翻转生成倒影的源图像
BmpRevert = Bitmap.createBitmap(BmpSRC, 0, 0, BmpSRC.getWidth(), BmpSRC.getHeight(), matrix, true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//int width = getWidth() * 2 / 3;
int width = getWidth();
int height = width * BmpDST.getHeight() / BmpDST.getWidth();
//先画出正着的小狗图片
canvas.drawBitmap(BmpSRC, null, new RectF(0, 0, width, height), mBitPaint);
//开启离屏绘制再画出倒影
int saveCount = canvas.save();
//画布向下移动源图像的高度height,准备绘制倒影
canvas.translate(0, height);
canvas.drawBitmap(BmpDST, null, new RectF(0, 0, width, height), mBitPaint);
//设置混合模式为PorterDuff.Mode.SRC_IN
mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(BmpRevert, null, new RectF(0, 0, width, height), mBitPaint);
//设置混合模式为空
mBitPaint.setXfermode(null);
canvas.restoreToCount(saveCount);
}
}
绘图原理在代码的注释中已经备注的很清晰了,这里不再解释说明。效果图如下:
自定义View的混合模式的使用实例二:模仿刮刮乐抽奖效果
package com.xw.view;
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.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.xw.avatarview.R;
/**
* Copyright (c)2021 网络科技有限公司
*
* @author: LQS
* @date: 2021/6/10
* @description:
*/
public class EraserView_SRCOUT extends View {
private Paint mBitPaint;
private Bitmap BmpDST, BmpSRC, BmpText;
private Path mPath;
private float mPreX, mPreY;
public EraserView_SRCOUT(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mBitPaint = new Paint();
mBitPaint.setColor(Color.RED);
mBitPaint.setStyle(Paint.Style.STROKE);
mBitPaint.setStrokeWidth(100);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
BmpText = BitmapFactory.decodeResource(getResources(), R.drawable.guaguaka_text, null);
BmpSRC = BitmapFactory.decodeResource(getResources(), R.drawable.dog, options);
BmpDST = Bitmap.createBitmap(BmpSRC.getWidth(), BmpSRC.getHeight(), Bitmap.Config.ARGB_8888);
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(BmpText, null, new RectF(0, 0, BmpDST.getWidth(), BmpDST.getHeight()), mBitPaint);
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
//先把手指轨迹画到目标Bitmap上
Canvas c = new Canvas(BmpDST);
c.drawPath(mPath, mBitPaint);
//然后把目标图像画到画布上
canvas.drawBitmap(BmpDST, 0, 0, mBitPaint);
//计算源图像区域
mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
canvas.drawBitmap(BmpSRC, 0, 0, mBitPaint);
mBitPaint.setXfermode(null);
canvas.restoreToCount(layerId);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.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;
mPath.quadTo(mPreX, mPreY, endX, endY);
mPreX = event.getX();
mPreY = event.getY();
break;
case MotionEvent.ACTION_UP:
break;
}
postInvalidate();
return super.onTouchEvent(event);
}
}
布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<com.xw.view.EraserView_SRCOUT xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</com.xw.view.EraserView_SRCOUT>
MainActivity中直接加载布局就可以了:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
效果图:
自定义View的混合模式的使用实例二:刮刮乐
package com.xw.guaguale.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;
import com.xw.bean.LotteryInfo;
import com.xw.guaguale.R;
import com.xw.guaguale.utils.LotteryManage;
/**
* Mode.SRC_OUT 模式刚好能够实现当目标图像为不透明时,不显示相交区域的源图像;
*/
public class GuaGuaLeView extends TextView {
//控件宽高
private int widget, height;
//上下文
private Context mContext;
//坐标点
private Paint mPaint;
//画布
private Canvas tempCanvas;
//图片类
private Bitmap mBitmap;
private float x, y, ox, oy;
//画笔类
private Path mPath;
//实体类
LotteryInfo info;
int messageCount;
//覆盖层颜色
int color = 0xFFD6D6D6;
//声明控件方法
public GuaGuaLeView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init(attrs);
}
//在次抽奖方法
public void againLotter() {
messageCount = 0;
//获取奖励信息
info = LotteryManage.getRandomLottery();
//设置覆盖层颜色
tempCanvas.drawColor(color);
//中奖信息文字
setText(info.getText());
//设置中奖信息文字颜色
setTextColor(Color.BLACK);
//设置字体加粗
getPaint().setFakeBoldText(true);
//拓展可设置奖区图片
// Drawable nav_up=getResources().getDrawable(R.drawable.ic_launcher);
// nav_up.setBounds(0, 0, nav_up.getMinimumWidth(), nav_up.getMinimumHeight());
// setCompoundDrawables(null, null, nav_up, null);
//设置背景为白色
setBackgroundResource(R.color.white);
}
//
private void init(AttributeSet attrs) {
// 获取控件大小值
TypedArray a = mContext.obtainStyledAttributes(attrs,
R.styleable.lotter);
//设置控件大小
widget = (int) a.getDimension(R.styleable.lotter_widget, 300);
height = (int) a.getDimension(R.styleable.lotter_height, 100);
//销毁对象
a.recycle();
// 初始化路径
mPath = new Path();
// 初始化画笔
mPaint = new Paint();
//设置画笔颜色
mPaint.setColor(mContext.getResources().getColor(R.color.view_color));
//设置透明度
mPaint.setAlpha(0);
//设置相交模式
mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
//设置防止锯齿
mPaint.setAntiAlias(true);
//设置画笔空心画笔
mPaint.setStyle(Style.STROKE);
//画笔宽度
mPaint.setStrokeWidth(50);
// 初始化Bitmap并且锁定到临时画布上
mBitmap = Bitmap.createBitmap(widget, height, Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas();
//绘制图片
tempCanvas.setBitmap(mBitmap);
//获取新的彩票
againLotter();
}
//绘制控件
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 将处理过的bitmap画上去
canvas.drawBitmap(mBitmap, 0, 0, null);
}
//手势判断
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN://按下事件
touchDown(event);
break;
case MotionEvent.ACTION_MOVE://手指移动事件
touchMove(event);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
break;
}
return true;
}
// 移动的时候
private void touchMove(MotionEvent event) {
//手指x坐标
x = event.getX();
//手机Y坐标
y = event.getY();
// 二阶贝塞尔曲线,实现平滑曲线;oX, oY为操作点 x,y为终点
mPath.quadTo((x + ox) / 2, (y + oy) / 2, x, y);
//绘制mPath进行绘制
tempCanvas.drawPath(mPath, mPaint);
ox = x;
oy = y;
//刷新控件
invalidate();
}
// 按下事件
private void touchDown(MotionEvent event) {
ox = x = event.getX();
oy = y = event.getY();
//逆时针
mPath.reset();
//移动画笔
mPath.moveTo(ox, oy);
}
}
效果图如下:
欢迎留言讨论!需要源码请留言!
以上是关于自定义View的混合模式的使用实例的主要内容,如果未能解决你的问题,请参考以下文章