Android刮刮卡自定义控件

效果图
刮刮卡自定义控件
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.mzph.cn/diannao/17393.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

类和对象03

六、继承 我们发现&#xff0c;定义这些类时&#xff0c;下级别的成员除了拥有上一级的共性&#xff0c;还有自己的特性。 这个时候我们就可以考虑利用继承的技术&#xff0c;减少重复代码 6.1 继承的基础语法 例如我们看到很多网站中, 都有公共的头部&#xff0c;公共的底…

vscode配置cc++环境要点和难点常见报错和解决方案

在VSCode中配置C/C++环境,你可以按照以下步骤进行: 下载并安装VSCode: 访问VSCode的官方网站,下载适用于你操作系统的VSCode安装包。 双击下载的安装包,按照提示进行安装。 安装C/C++扩展: 打开VSCode,点击左侧边栏的“Extensions”图标(或使用快捷键Ctrl+Shift+X)…

TypeScript 类

1. 基本用法 在 TypeScript 中&#xff0c;可以使用 class 关键字来定义类&#xff0c;然后通过 new 关键字来创建类的实例。例如&#xff1a; class Person {name: string;age: number;constructor(name: string, age: number) {this.name name;this.age age;}greet() {co…

乡村振兴的乡村人才引进与培养:引进和培养乡村人才,激发乡村发展活力,为乡村振兴提供人才保障

目录 一、引言 二、乡村人才引进与培养的重要性 &#xff08;一&#xff09;人才是乡村振兴的核心动力 &#xff08;二&#xff09;人才是乡村文化传承的载体 &#xff08;三&#xff09;人才是乡村社会治理的基石 三、乡村人才引进与培养的现状 &#xff08;一&#xf…

备战秋招c++ 【持续更新】

T1 牛牛的快递 原题链接&#xff1a;牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目类型&#xff1a;模拟 审题&确定思路&#xff1a; 1、超过1kg和不足1kg有两种不同收费方案 ---- 起步价问题 2、超出部分不足1kg的按1kg计算 ----- 向上取整 3、向上取整的实现思路…

一文掌握Java中的CyclicBarrier、CountDownLatch和Semaphore

1.CountDownLatch 1.1 介绍和用途 CountDownLatch 是一个同步助手类&#xff0c;在完成一组正在其他线程中执行的操作之前&#xff0c;它允许一个或多个线程一直等待。 1.2 工作原理 它通过一个计数器来实现&#xff0c;我们初始化 CountDownLatch 对象时指定计数器的值&am…

Android基础-Activity的介绍

在Android系统中&#xff0c;Activity是一个重要的组件&#xff0c;它承载了用户与应用之间的交互界面。以下是关于Activity的功能、作用以及生命周期的详细介绍。 Activity的功能和作用 提供用户界面&#xff1a; Activity是Android应用程序中用于表示一个屏幕或用户界面的组…

d2-crud-plus 使用小技巧(五)—— 搜索时间(或下拉列表)后,点击X清除按钮后返回值为null,导致异常

问题 使用vue2elementUId2-crud-plus&#xff0c;时间组件自动清除按钮&#xff0c;点击清除按钮后对应的值被设置为null&#xff0c;原本应该是空数组&#xff08;[]&#xff09;&#xff0c;导致数据传到后端后报错。不仅适用于搜索&#xff0c;表单一样有效果。 解决方法 …

移动端应用订阅SDK接入攻略

本文档介绍了联想应用联运移动端订阅SDK接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运移动端订阅SDK。 接入前准备 1请先与联想商务达成合作意向。 2.联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#…

谷歌开发者账号身份验证不通过?该怎么办?

我们都清楚&#xff0c;随着谷歌上架行业的快速发展&#xff0c;谷歌政策也在不断更新变化&#xff0c;对开发者账号的审核标准也在不断提升。其中一项要求就是&#xff0c;开发者账号需要进行身份验证才能发布应用。 Your identity couldnt be verified&#xff01;“我们无法…

词法与语法分析器介绍

概述 词法和语法可以使用正则表达式和BNF范式表达&#xff0c;而最终描述文法含义的事状态转换图 Lex与YACC 词法分析器Lex 词法分析词Lex&#xff0c;是一种生成词法分析的工具&#xff0c;描述器是识别文本中词汇模式的程序&#xff0c;这些词汇模式是在特殊的句子结构中…

二叉树的实现(递归实现)

前言&#xff1a;本文讲解通过递归的方式实现二叉树的一些基本接口。 目录 通过左右子树的方式实现二叉树&#xff1a; 二叉树的遍历&#xff1a; 求二叉树结点的个数&#xff1a; 二叉树所有节点的个数&#xff1a; 二叉树叶子节点的个数&#xff1a; 求第k层节点的节点…

4,八种GPIO模式

资料来源:【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 仅作个人自学笔记&#xff0c;如有冒犯&#xf…

电子阅览室解决方案

一.方案概述 “电子阅览室”概念一经提出&#xff0c;就得到了广泛的关注&#xff0c;纷纷组织力量进行探讨、研究和开发&#xff0c;进行各种模型的试验。随着数字地球概念、技术、应用领域的发展&#xff0c;电子阅览室已成为数字地球家庭的成员&#xff0c;为信息高速公路提…

深度解读 chatgpt基本原理

ChatGPT&#xff08;Generative Pre-trained Transformer&#xff09;是由OpenAI开发的一种大规模语言模型&#xff0c;基于Transformer架构&#xff0c;采用自监督学习和生成式预训练方法。以下是ChatGPT的基本原理的深度解读&#xff1a; ### 1. Transformer架构 Transforme…

深入理解C++智能指针系列(五)

引言 前面两篇介绍了std::unique_ptr的自定义删除器以及如何优化删除器的使用。本文将介绍std::unique_ptr在使用过程中的一些“奇技淫巧”。 正文 删除器和std::move std::move是将对象的所有权转移给另一个对象&#xff0c;那如果通过std::move来转移带自定义删除器的std::…

uniCloud云存储uni-cdn七牛云扩展存储-开发uniapp项目节约开发成本

为什么要使用uniCloud的扩展存储&#xff0c;那就是省钱&#xff0c;而且DCloud也一直在推uni-cdn&#xff0c;我在项目中也使用七牛云的扩展存储&#xff0c;确实是省钱&#xff0c;如果你的项目使用到大量的图片后者音视频&#xff0c;这些的算计可以帮你省不少钱。下面就通过…

OSPF的数据库表 +LSA类别

<r1>display ospf sdb 查看OSPF数据库目录 LSDB中装载了所有可以学习到的LSA; LSA--链路状态通告 一条拓扑或一条路由条目被称为一条LSA OSPF协议的数据库是本地所有LSA的集合&#xff0c;不同网络环境下将产生不同类别的LSA LSA 在共享时基于 LSU 数据包传递…

【状态机动态规划】3129. 找出所有稳定的二进制数组 I

本文涉及知识点 动态规划汇总 LeetCode 3129. 找出所有稳定的二进制数组 I 给你 3 个正整数 zero &#xff0c;one 和 limit 。 一个 二进制数组 arr 如果满足以下条件&#xff0c;那么我们称它是 稳定的 &#xff1a; 0 在 arr 中出现次数 恰好 为 zero 。 1 在 arr 中出现…

leetCode.83. 删除排序链表中的重复元素

leetCode.83. 删除排序链表中的重复元素 代码 class Solution { public:ListNode* deleteDuplicates(ListNode* head) {auto p head;while(p){auto q p->next;while(q && p->val q->val) q q->next;if(p->next q) p p->next;else p->next …