Android刮刮卡自定义控件

news2024/9/25 3:20:52
效果图
刮刮卡自定义控件
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);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        if (!isComplete) {
            drawPath();
            canvas.drawBitmap(mBitmap, 0, 0, null);
        } else {
            this.setVisibility(GONE);
        }
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measuredWidth = getMeasuredWidth();//宽高和父view的相同
        measuredHeight = getMeasuredHeight();
        // 初始化bitmap
        mBitmap = 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);
    }
    @Override
    public 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;
        @Override
        public 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>
<!-- 显示层 -->
<ImageView
            android: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" />
<!-- 刮奖层 -->
<ScratchView
            app: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.coloradmin.cn/o/1706093.html

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

相关文章

2.开发环境介绍

开发环境介绍三种&#xff1a;第一种是在线开发环境、第二种是Windows下的开发环境、第三种是Linux下的开发环境。 1.在线开发环境 2.Windows下的开发环境 用的比较多的是Devc&#xff0c;新手适合使用&#xff0c;上手快&#xff0c;简单&#xff0c;方便。 Devc使用&#x…

Pushmall共享分销电商SaaS版2024年 5月模块开发优化完成

Pushmall共享分销电商 2024年 5月模块开发优化完成 1、**实现SaaS框架业务&#xff1a;**多租户、多商家、多门店&#xff0c;及商家入驻、商品管理。 2、租户小程序管理&#xff1a;对租户的小程序业务管理。 3、店铺小程序管理&#xff1a;对租户多店铺小程序绑定。 4、会员分…

机会就在眼前!2025-CISP深圳国际体育展的招展工作火热持续中...

2025-CISP中国&#xff08;深圳&#xff09;国际体育展的招展工作火热持续中&#xff0c;凭借越来越深远的影响力以及前两届的成功举办经验&#xff0c;展位多半已被“抢购”。但小编的同事们同时又反映出一个问题&#xff1a;有一批老展商和新展商已有明确的参展意向&#xff…

FTP协议——Pure-Ftpd安装(Linux)

1、简介 Pure-FTPd是一个高效、免费且开源的FTP服务器软件&#xff0c;广泛应用于各种Unix/Linux系统。它以其易用性、高安全性和功能丰富而闻名&#xff0c;适用于个人和企业的文件传输需求。 2、步骤 环境&#xff1a;Ubuntu 22.04.4 下载地址&#xff1a;Index of /pub/p…

选择快充时代下的理想充电器与电压诱骗芯片PW6606

随着科技的不断进步&#xff0c;我们的电子设备对于充电速度和效率的要求越来越高。在快充技术迅猛发展的今天&#xff0c;了解不同类型的充电器及其对应的快充协议&#xff0c;以及如何选择适合的电压诱骗芯片&#xff0c;对于提升充电体验和保障设备安全显得尤为重要。 一、快…

【启程Golang之旅】掌握Go语言数组基础概念与实际应用

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

如何搭建雾锁王国多人联机服务器,搭建教程分享

雾锁王国&#xff08;Enshrouded&#xff09;是一款融合了生存、制作以及动作RPG战斗的游戏&#xff0c;2024年1月24日在Steam平台以抢先体验形式发售&#xff0c;支持中文。游戏背景设定在一个基于体素构筑的辽阔大陆上。玩家将在这个开放世界中自由选择前进的方向&#xff0c…

你知道【无犯罪记录证明】怎么开具吗?

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 有些事情没有经历过&#xff0c;就不会知道&#xff0c;经历过一次也就晓得了。 所谓见多识广&#xff0c;很多就是见过或者听说过&#xff0c;像刘姥姥进大观园&#xff0c;很多事物是没见过&#xff0c;才会闹出很多…

升级 JDK17 一个不可拒绝的理由!

插&#xff1a; AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家(前言 – 人工智能教程 ) 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

Java入门-java的集合框架

集合概念 集合&#xff0c;有时也称作容器(Container), 是对象的持有者&#xff0c;它们可以有助于高效访问的方式存储的组织对象。以生活中的案例为例&#xff1a; 集合就像装衣服的柜子&#xff0c;衣服就是集合中的元素。 集合框架图 Collection中每次操作的都是一个对象&a…

【Python编程】JetBrains PyCharm IDE专业版 学生优惠过期怎么办?【妥协的解决方法】

写在前面 笔者临近硕士毕业&#xff0c;用了7年左右的JB学生包终于过期了&#xff08;依依不舍&#xff09;。。。之前用得顺手的PyCharm&#xff0c;WebStorm&#xff0c;CLion&#xff08;专业版&#xff09;等等IDE都暂时告别了。笔者无意以个人身份购买许可证&#xff0c;…

android studio 导入github里的项目后提示:Add Configuration

原文链接&#xff1a;https://blog.csdn.net/weixin_45677723/article/details/125940912 从github上面clone项目&#xff0c;出现下图问题&#xff1a; 解决问题&#xff1a; 我这个的情况是因为多文件嵌套了&#xff0c;我用Android Studio打开的是A文件&#xff0c;而B项…

oracle adg dup 一拖一拖一(一主两备)(dup)

oracle adg dup 一拖一拖一&#xff08;一主两备&#xff09; 1.配置Public IP ora1 nmcli connection modify ens33 ipv4.addresses 192.168.134.249/24 ipv4.gateway 192.168.134.2 ipv4.method manual autoconnect yes nmcli connection up ens33 nmcli connection show o…

金蝶云星空与旺店通·企业版对接集成采购入库查询打通创建采购入库单

金蝶云星空与旺店通企业版对接集成采购入库查询打通创建采购入库单 数据源系统:金蝶云星空 金蝶K/3Cloud&#xff08;金蝶云星空&#xff09;是移动互联网时代的新型ERP&#xff0c;是基于WEB2.0与云技术的新时代企业管理服务平台。金蝶K/3Cloud围绕着“生态、人人、体验”&…

嵌入式学习记录5.18(多点通信)

一、套接字属性设置相关函数 #include <sys/types.h> /* See NOTES */#include <sys/socket.h>int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);int setsockopt(int sockfd, int level, int optname,const void *op…

Python批量docx或doc文档转换pdf

说明&#xff1a; 1、因为项目需要&#xff0c;需要手动将十几个word文档转换成pdf文档 2、python请安装3.9.0以上&#xff0c;否则一些依赖库无法正常用 #! /usr/bin/python3 # -*- coding: utf-8 -*-import os import comtypes.client# 批量将docx文件转换pdf文件 def docx_t…

1109 擅长C(测试点0,1,2,3)

当你被面试官要求用 C 写一个“Hello World”时&#xff0c;有本事像下图显示的那样写一个出来吗&#xff1f; ..C.. .C.C. C...C CCCCC C...C C...C C...C CCCC. C...C C...C CCCC. C...C C...C CCCC. .CCC. C...C C.... C.... C.... C...C .CCC. CCCC. C...C C...C C...C C…

【马蹄集】— 百度之星 2023

BD202301公园 可以先 b f s bfs bfs统计一下 t , f t,f t,f到达每个点的距离&#xff0c;还有 n n n到达其他点的距离即其他点到达 n n n的距离 然后枚举每个点 直接计算得到最小值即可 注意特判有人无法到达 n n n的情况 code: #include<bits/stdc.h> #define endl \n…

品牌做电商控价的原因

品牌控价确实是一项至关重要的任务&#xff0c;它关乎着品牌形象、市场定位以及长期发展的稳定性。在电商平台上&#xff0c;价格的公开性和透明度使得消费者、经销商和其他渠道参与方都能够轻易地进行价格比较。因此&#xff0c;品牌方必须对电商渠道的价格进行严格的管控&…

电商API接口助力直播带货选品||助力电商平台搭建选品

如今&#xff0c;直播带货如火如荼。直播带货的核心是卖货、品牌盈利&#xff0c;那想要带货效果更好&#xff0c;选品及定价是最关键的环节。 事实上&#xff0c;品牌企业可以直接使用API接口工具来辅助自身选品及定价&#xff0c;这主要是因为比价工具在直播带货选品环节能起…