Android刮刮卡自定义控件

ops/2024/10/18 16:52:34/
效果图
刮刮卡自定义控件
import android.content.Context;
import android.graphics.Bitmap;
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.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/*** 描述:* 作者: shawn* 时间: 2024/5/2711:20*/
public class ScratchView extends View {/*** 绘制线条的画笔*/private Paint mOutterPaint = new Paint();/*** 遮层画笔*/private Paint mMaskPaint = new Paint();/*** 最下面画笔*/private Paint mBackPint = new Paint();/*** mCanvas绘制内容在其上*/private Bitmap mBitmap;/*** 记录用户绘制的Path*/private Path mPath = new Path();/*** 内存中创建的Canvas*/private Canvas mCanvas;private boolean isComplete;private Rect mTextBound = new Rect();private String mText = "¥500,0000";private int mLastX;private int mLastY;private int measuredWidth;private int measuredHeight;public GuaGuaKaView(Context context) {this(context, null);}public GuaGuaKaView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public GuaGuaKaView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}private void init() {mPath = new Path();setUpOutPaint();setUpBackPaint();}/*** 初始化canvas的绘制用的画笔*/private void setUpBackPaint() {mBackPint.setStyle(Paint.Style.FILL);mBackPint.setTextScaleX(2f);mBackPint.setColor(Color.DKGRAY);mBackPint.setTextSize(32);mBackPint.getTextBounds(mText, 0, mText.length(), mTextBound);}@Overrideprotected void onDraw(Canvas canvas) {if (!isComplete) {drawPath();canvas.drawBitmap(mBitmap, 0, 0, null);} else {this.setVisibility(GONE);}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);measuredWidth = getMeasuredWidth();//宽高和父view的相同measuredHeight = getMeasuredHeight();// 初始化bitmapmBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);mCanvas = new Canvas(mBitmap);mMaskPaint.setColor(Color.parseColor("#000000"));//遮层透明mMaskPaint.setStyle(Paint.Style.FILL);mCanvas.drawRoundRect(new RectF(0, 0, measuredWidth, measuredHeight), 0, 0, mMaskPaint);
//        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
//                R.drawable.bg_withdraw_history), null, new RectF(0, 0, measuredWidth, measuredHeight), null);//遮层}/*** 设置画笔的一些参数*/private void setUpOutPaint() {// 设置画笔
//         mOutterPaint.setAlpha(0);mOutterPaint.setColor(Color.parseColor("#c0c0c0"));mOutterPaint.setAntiAlias(true);mOutterPaint.setDither(true);mOutterPaint.setStyle(Paint.Style.STROKE);mOutterPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角mOutterPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角// 设置画笔宽度mOutterPaint.setStrokeWidth(50);}/*** 绘制线条*/private void drawPath() {mOutterPaint.setStyle(Paint.Style.STROKE);mOutterPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//取俩者的交集mCanvas.drawPath(mPath, mOutterPaint);}@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();int x = (int) event.getX();int y = (int) event.getY();switch (action) {case MotionEvent.ACTION_DOWN:mLastX = x;mLastY = y;mPath.moveTo(mLastX, mLastY);break;case MotionEvent.ACTION_MOVE:int dx = Math.abs(x - mLastX);int dy = Math.abs(y - mLastY);if (dx > 3 || dy > 3)mPath.lineTo(x, y);mLastX = x;mLastY = y;new Thread(mRunnable).start();break;case MotionEvent.ACTION_UP:new Thread(mRunnable).start();break;}invalidate();return true;}/*** 统计擦除区域任务*/private Runnable mRunnable = new Runnable() {private int[] mPixels;@Overridepublic void run() {int w = getWidth();int h = getHeight();float wipeArea = 0;float totalArea = w * h;Bitmap bitmap = mBitmap;mPixels = new int[w * h];/*** 拿到所有的像素信息*/bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);/*** 遍历统计擦除的区域*/for (int i = 0; i < w; i++) {for (int j = 0; j < h; j++) {int index = i + j * w;if (mPixels[index] == 0) {wipeArea++;}}}/*** 根据所占百分比,进行一些操作*/if (wipeArea > 0 && totalArea > 0) {int percent = (int) (wipeArea * 100 / totalArea);Log.e("TAG", "清除区域 = " + percent);if (percent > 75) {isComplete = true;postInvalidate();}}}};/*** 将布局转换成bitmap* @param addViewContent* @return*/private Bitmap getViewBitmap(View addViewContent) {addViewContent.setDrawingCacheEnabled(true);addViewContent.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));addViewContent.layout(0, 0,addViewContent.getMeasuredWidth(),addViewContent.getMeasuredHeight());addViewContent.buildDrawingCache();Bitmap cacheBitmap = addViewContent.getDrawingCache();Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);return bitmap;}
}
 如何使用?
<RelativeLayout>
<!-- 显示层 -->
<ImageViewandroid:id="@+id/iv_holder"android:layout_width="0dp"android:layout_height="100dp"android:layout_marginStart="14dp"android:layout_marginTop="60dp"android:layout_marginEnd="14dp"android:scaleType="fitXY"android:src="@drawable/bg_drama_top"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" />
<!-- 刮奖层 -->
<ScratchViewapp:layout_constraintTop_toTopOf="@id/iv_holder"app:layout_constraintBottom_toBottomOf="@id/iv_holder"app:layout_constraintStart_toStartOf="@id/iv_holder"app:layout_constraintEnd_toEndOf="@id/iv_holder"android:layout_width="0dp"android:layout_height="0dp"/>
</RelativeLayout>


http://www.ppmy.cn/ops/44286.html

相关文章

【QT】实时语言切换

前言:一个完整的软件开发通常需要支持多种语言,本文主要讲述实时语言切换开发时的相关解决方案。 目录 1. 制作字库文件 3. 加载翻译文件 4. 实时切换 5. 常见问题

VPN的详细理解

VPN&#xff08;Virtual Private Network&#xff0c;虚拟私人网络&#xff09;是一种在公共网络上建立加密通道的技术&#xff0c;通过这种技术可以使远程用户访问公司内部网络资源时&#xff0c;实现安全的连接和数据传输。以下是对VPN的详细介绍&#xff1a; 选择代理浏览器…

zabbix自定义监控项

文章目录 1、配置conf文件(zabbix_agent2)linuxwindows 2、配置监控项3、配置触发器4、查看监控数据 示例自定义程序 hash_tool&#xff1a;输出指定目录的哈希值 调用指令&#xff1a; hash_tool --path [指定目录] 1、配置conf文件(zabbix_agent2) linux vim /etc/zabbix/z…

Python学习备份

2023年1月19日15:25:16 1. vsIDE编程python python路径&#xff1a;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_86 python_pip路径(可添加到环境变量)&#xff1a;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_86\Scripts 第三方库路…

PCIe (1)

计算PCIe的吞吐 PCIe吞吐依赖以下因素 >protocol overhead >payload size >completion latency >flow control update latency >characteristics of the devices that form the link Protocol Overhead 如果是8B/10B的编码,那么需要25%的开销。 对于Gen…

BE115配置2个或6个RS485/RS232串口

多协议网关BE115是一款多协议转多上行协议的综合性转换网关&#xff0c;支持IEC104、MQTT、OPC UA、Modbus RTU、Modbus TCP、SNMP等多种通信协议。上行协议包括IEC104、MQTT、OPC、Modbus RTU、Modbus TCP、SNMP&#xff0c;而下行协议涵盖DL/T645、Modbus RTU、Modbus TCP、I…

【Qt常用控件】—— 布局管理器

目录 前言 &#xff08;一&#xff09;垂直布局 &#xff08;二&#xff09;水平布局 &#xff08;三&#xff09;网格布局 &#xff08;四&#xff09;表单布局 &#xff08;五&#xff09;分组布局 &#xff08;六&#xff09;Spacer 总结 前言 之前使⽤Qt在界⾯上…

Python魔法之旅-魔法方法(01)

目录 一、概述 1、定义 2、作用 二、主要应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类…