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

相关文章

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位

Java使用Spire.Barcode for Java实现条形码生成与识别

《Java使用Spire.BarcodeforJava实现条形码生成与识别》在现代商业和技术领域,条形码无处不在,本教程将引导您深入了解如何在您的Java项目中利用Spire.Barcodefor... 目录1. Spire.Barcode for Java 简介与环境配置2. 使用 Spire.Barco

Java利用Spire.Doc for Java实现在模板的基础上创建Word文档

《Java利用Spire.DocforJava实现在模板的基础上创建Word文档》在日常开发中,我们经常需要根据特定数据动态生成Word文档,本文将深入探讨如何利用强大的Java库Spire.Do... 目录1. Spire.Doc for Java 库介绍与安装特点与优势Maven 依赖配置2. 通过替换

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求