Android自定义控件(一)——抽奖刮刮乐的实现

2024-02-18 22:20

本文主要是介绍Android自定义控件(一)——抽奖刮刮乐的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

飞来千丈玉蜈蚣,横驾三天白螮蝀,凿开万窍黄云洞。看星低落镜中,月华明秋影玲珑。赑屭金环重,狻猊石柱雄,铁锁囚龙。

今天小编专门准备开一个Android自定义控件栏目,来分析Android常用的各种自定义控件知识,而今天的开篇,就从Android的自定义控件刮刮乐讲起把,为了让大家感兴趣,第一篇就不赘述理论,直接来玩一个有趣的刮刮乐控件。

众所周知,手机APP中有许多的抽奖方式,比如转盘抽奖,翻牌抽奖等,而今天我们只将刮刮乐抽奖,因为这个在手机APP之中用的还是挺多了,相信以后基本都能用的到。

1.创建自定义View

说到自定义控件当然就需要自定义View来实现刮刮乐,所以选择首先就需要在Android Studio中创建View,实现View常用的三个构造函数,代码如下图所示:

public class ShaveView extends View {public ShaveView(Context context) {super(context);}public ShaveView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public ShaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}
}

其中第二个View构造函数,是我们最常用的,也就是将控件直接写在Layout.xml之中,就会调用此方法,所以我们的初始化工作会在这里进行,不过我们第一步还是要定义成员变量,下面就是用的的成员变量代码:

private float mPreX,mPreY;//刮刮乐手指定位的X,Y坐标
private Bitmap dstBitmap,srcBitmap;//目标图像(手指刮除图层(白色图层)),原图像也就是刮除的灰色图层
private Paint mPaint,mTextPaint;//图像画笔工具,文字画笔工具
private Path mPath;//手指刮除路径
private int strLength;//文字的长度
private int strHeight;//文字的高度
private String textStr="恭喜你中奖了";//刮除后显示的文字

2.初始化控件参数

作为自定义View来说,有一个值得关注的参数,那就是硬件加速,但是有的绘图函数并不支持硬件加速,比如今天小编讲的PorterDuffXfermode,他的部分函数并不支持硬件加速,如果你不知道哪些函数不支持硬件加速,最好关掉硬件加速设置:

setLayerType(LAYER_TYPE_SOFTWARE,null);

接着,我们初始化成员变量,避免后面调用的时候为空,造成空指针错误,代码如下:

this.mPaint=new Paint();
this.mPaint.setColor(Color.RED);//刮刮乐擦除线条颜色
this.mPaint.setStrokeWidth(45);//刮刮乐擦除线宽度
this.mPaint.setStyle(Paint.Style.STROKE);//设置为描边
this.mPath=new Path();
this.mTextPaint=new Paint();
this.mTextPaint.setColor(Color.BLACK);//设置字体颜色
this.mTextPaint.setTextSize(56);//设置字体大小
Rect rect = new Rect();
this.mTextPaint.getTextBounds(textStr,0,textStr.length(),rect);//获取文字的宽高,存储在rect中
this.strLength=rect.width();//获取文字的宽
this.strHeight=rect.height();//获取文字的高

3.onTouchEvent(MotionEvent event)实现

我们是在写一个刮刮乐控件,所以需要捕捉手势操作,而自定义View中的onTouchEvent()就是专门拦截用户手势的,这里我们利用贝济埃曲线将手势连接起来,形成手势轨迹,代码如下:

@Override
public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:mPath.moveTo(event.getX(),event.getY());//贝济埃曲线起点this.mPreX=event.getX();this.mPreY=event.getY();return true;case MotionEvent.ACTION_MOVE:float endX=(this.mPreX+event.getX())/2;float endY=(this.mPreY+event.getY())/2;mPath.quadTo(this.mPreX,this.mPreY,endX,endY);//画贝济埃曲线this.mPreX=event.getX();this.mPreY=event.getY();break;default:break;}postInvalidate();return super.onTouchEvent(event);
}

肯定有人会问什么是贝济埃曲线,这个后续也会将,这里你只需要知道,贝济埃曲线将手指两点之间的线条变得更平滑一些就行。这里代码的意思是,手指记录按下点,然后捕捉移动手指位置,计算得出贝济埃曲线的终点与起始点。

4.OnDraw(Canvas canvas)实现

接着就是画出原图层与目标图层呢?有过PS基础的应该都知道,PS中有一个混合模式,而今天介绍的PorterDuffXfermode也是混合模式,其中有18中混合模式,今天要使用的是PorterDuff.Mode.SRC_OUT混合模式,也就是当目标图层不透明时,计算结果将是透明的,简单的理解就是刮刮乐刮除的区域透明(灰色目标图层与手指刮除图层相交位置透明),也就显示了刮刮乐后面的文字。

理解了混合模式后,我们再来看看onDraw()前面代码:

canvas.drawColor(Color.RED);//设置自定义View背景为白色
if(this.dstBitmap==null || this.srcBitmap==null){//初始化目标图层与源图层
this.srcBitmap=Bitmap.createBitmap(getWidth()/4*3,getHeight()/4*3,Bitmap.Config.ARGB_8888);//源图层,也就是刮刮乐灰色图层
this.dstBitmap=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);//目标图层
this.srcBitmap.eraseColor(Color.GRAY);//设置源图层背景为灰色
}
canvas.drawText(textStr,getWidth()/2-strLength/2,getHeight()/2-strHeight/2,mTextPaint);//画文字

这里我们创建好了两个图层,也可以说是两个图片,比如srcBitmap源图层背景为灰色,同时直接将文字绘制到自定义View的中间位置,而文字的X,Y坐标如下图所示:

接着就是刮刮乐最核心的代码啦,所以需要认真仔细的看下,代码如下:

int layerId=canvas.saveLayer(0,0,getWidth(),getHeight(),null,Canvas.ALL_SAVE_FLAG);
Canvas c=new Canvas(dstBitmap);//目标图层
c.drawPath(mPath,mPaint);//绘制手指路径canvas.drawBitmap(dstBitmap,0,0,mPaint);//先画目标图层
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//设置混合模式
canvas.drawBitmap(srcBitmap,getWidth()/8,getHeight()/8,mPaint);//在画源图层this.mPaint.setXfermode(null);//设置混合模式为空
canvas.restoreToCount(layerId);

这里我们使用离屏绘制,什么是离屏绘制,后续小编会讲,你现在只需要知道离屏绘制的代码在canvas.save与canvas.restoreToCount中间即可。

其中mPath记录的是手指刮除的位置轨迹,把它先画到dstBitmap目标图层上,然后,根据Xfermode的混合模式,先后画出目标图层与源图层,记住,这个顺序不能变,这个是刮刮乐代码中最核心的代码。

可能有的小伙伴注意到了,这里小编源图层右上角的坐标为(getWidth()/8,getHeight()/8),这是因为我们使用中,大多数刮刮乐背景边缘并不是灰色,灰色图层在中间显示,所以这里小编将源图层移动到了整个画布的相对中间点的位置,这个可以随意调节,使得看起来更加美观。

Github代码下载地址:点击下载

 

这篇关于Android自定义控件(一)——抽奖刮刮乐的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/722633

相关文章

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin