学习内容来自“慕课网”
很多电商APP中都有刮刮卡活动,刮开涂层,获取刮刮卡内部信息
原理图:
刮刮卡效果:通过画笔画笔来实现,黄色涂层,蓝色涂层,刮动则将两涂层共有的部分去掉, 就是DstOut对应的 效果
MainActivity.java
1 package com.example.gauguaka;
2
3 import android.os.Bundle;
4 import android.app.Activity;
5 import android.view.Menu;
6
7 public class MainActivity extends Activity {
8
9 @Override
10 protected void onCreate(Bundle savedInstanceState) {
11 super.onCreate(savedInstanceState);
12 setContentView(R.layout.activity_main);
13 }
14
15
16 }
新建一个包guaguaka.java 在包中新建类Guaguaka.java
1 package guaguaka.view;
2
3 import com.example.gauguaka.R;
4
5 import android.content.Context;
6 import android.graphics.Bitmap;
7 import android.graphics.Bitmap.Config;
8 import android.graphics.BitmapFactory;
9 import android.graphics.Canvas;
10 import android.graphics.Color;
11 import android.graphics.Paint;
12 import android.graphics.Paint.Style;
13 import android.graphics.Path;
14 import android.graphics.PorterDuff.Mode;
15 import android.graphics.PorterDuffXfermode;
16 import android.graphics.Rect;
17 import android.graphics.RectF;
18 import android.util.AttributeSet;
19 import android.util.Log;
20 import android.view.MotionEvent;
21 import android.view.View;
22
23 public class Guaguaka extends View{
24 //画笔
25 private Paint moutterpaint;
26 //记录绘制路径
27 private Path mpath;
28 //画布
29 private Canvas mcanvas;
30 //图片
31 private Bitmap mbitmap;
32 //绘制坐标值
33 private int mlastx;
34 private int mlasty;
35 /*----------------------*/
36 private Bitmap bitmap;
37 private Bitmap moutterbitmap;
38 // 判断遮盖层区域是否消除达到阈值
39 private volatile boolean mComplete = false;
40
41
42
43 public Guaguaka(Context context) {
44 // TODO Auto-generated constructor stub
45 this(context,null);
46 }
47 public Guaguaka(Context context, AttributeSet attrs) {
48 this(context, attrs,0);
49 // TODO Auto-generated constructor stub
50 }
51 public Guaguaka(Context context, AttributeSet attrs,int defStyle) {
52 super(context, attrs ,defStyle);
53 // TODO Auto-generated constructor stub
54 init();
55 }
56 //获得控件的宽度和高度
57 @Override
58 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
59 // TODO Auto-generated method stub
60 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
61
62 int width = getMeasuredWidth();
63 int height = getMeasuredHeight();
64 // 初始化我们的bitmap
65 mbitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
66 mcanvas = new Canvas(mbitmap);
67 // 设置绘制path画笔的一些属性
68 setupOutPaint();
69 //setUpBackPaint();
70 //mcanvas.drawColor(Color.parseColor("#c0c0c0"));
71 //设置刮刮卡框架为圆角
72 mcanvas.drawRoundRect(new RectF(0, 0, width, height), 30, 30,moutterpaint);
73 //显示刮刮卡未刮开是的图案
74 mcanvas.drawBitmap(moutterbitmap, null, new Rect(0, 0, width, height),null);
75
76
77 }
78 //初始化操作
79 private void init() {
80 // TODO Auto-generated method stub
81 moutterpaint = new Paint();
82 mpath = new Path();
83 //刮开后的图片(chaji_1是一个茶壶的图片)
84 bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.chaji_1);
85 //刮刮卡未刮时候的图案(fg_guaguaka 是一个刮刮卡字样的图片)
86 moutterbitmap = BitmapFactory.decodeResource(getResources(),R.drawable.fg_guaguaka);
87 }
88 /**
89 * 设置绘制path画笔的一些属性
90 */
91 private void setupOutPaint()
92 {
93 //画笔颜色 --红色
94 moutterpaint.setColor(Color.parseColor("#c0c0c0"));
95 //锯齿
96 moutterpaint.setAntiAlias(true);
97 moutterpaint.setDither(true);
98 //线条圆角
99 moutterpaint.setStrokeJoin(Paint.Join.ROUND);
100 moutterpaint.setStrokeCap(Paint.Cap.ROUND);
101 moutterpaint.setStyle(Style.FILL);
102 //画笔宽度
103 moutterpaint.setStrokeWidth(20);
104 }
105 /**
106 * 设置我们绘制获奖信息的画笔属性
107 */
108
109 //绘制事件
110 @Override
111 public boolean onTouchEvent(MotionEvent event)
112 {
113 int action = event.getAction();
114
115 int x = (int) event.getX();
116 int y = (int) event.getY();
117
118 switch (action)
119 {
120 case MotionEvent.ACTION_DOWN://按下
121
122 mlastx = x;
123 mlasty = y;
124 mpath.moveTo(mlastx, mlasty);
125 break;
126 case MotionEvent.ACTION_MOVE://移动
127
128 int dx = Math.abs(x - mlastx);
129 int dy = Math.abs(y - mlasty);
130
131 if (dx > 3 || dy > 3)
132 {
133 mpath.lineTo(x, y);
134 }
135 //更新坐标
136 mlastx = x;
137 mlasty = y;
138
139 break;
140 case MotionEvent.ACTION_UP://抬起
141 new Thread(mRunnable).start();// 统计擦除区域任务
142 break;
143 }
144
145 invalidate();
146 return true;
147
148 }
149 @Override
150 protected void onDraw(Canvas canvas)
151 {
152 canvas.drawBitmap(bitmap, 0 , 0, null);
153 //注意任务结束,会把一个mComplete设置为true;当为true时,直接展现刮奖区
154 if (!mComplete)
155 {
156 drawPath();
157 canvas.drawBitmap(mbitmap, 0, 0, null);
158 }
159 }
160
161 private void drawPath()
162 {
163 moutterpaint.setStyle(Style.STROKE);
164 moutterpaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
165 mcanvas.drawPath(mpath, moutterpaint);
166 }
167 /**
168 * 统计擦除区域任务
169 */
170 private Runnable mRunnable = new Runnable()
171 {
172 private int[] mPixels;
173
174 @Override
175 public void run()
176 {
177
178 int w = getWidth();
179 int h = getHeight();
180
181 float wipeArea = 0;
182 float totalArea = w * h;
183
184 Bitmap bitmap = mbitmap;
185
186 mPixels = new int[w * h];
187
188 /**
189 * 拿到所有的像素信息
190 */
191 bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);
192
193 /**
194 * 遍历统计擦除的区域
195 */
196 for (int i = 0; i < w; i++)
197 {
198 for (int j = 0; j < h; j++)
199 {
200 int index = i + j * w;
201 if (mPixels[index] == 0)
202 {
203 wipeArea++;
204 }
205 }
206 }
207
208 /**
209 * 根据所占百分比,进行一些操作
210 */
211 if (wipeArea > 0 && totalArea > 0)
212 {
213 int percent = (int) (wipeArea * 100 / totalArea);
214 Log.e("TAG", percent + "");
215
216 if (percent > 70)
217 {
218 mComplete = true;
219 postInvalidate();
220 }
221 }
222 }
223
224 };
225 }
将布局文件修改:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 >
6
7 <guaguaka.view.Guaguaka
8 android:id="@+id/id_guaguaka"
9 android:layout_width="300dp"
10 android:layout_height="100dp"
11 android:layout_centerInParent="true"
12 />
13 </RelativeLayout>
效果图:
接下来就行效果的优化。
当刮开涂层达到总面积的多少的时候,将全部图案显示出来
首先定义一个布尔值
1 // 判断遮盖层区域是否消除达到阈值
2 private volatile boolean mComplete = false;
添加计算刮开区域面积的线程
1 private Runnable mRunnable = new Runnable()
2 {
3 private int[] mPixels;
4
5 @Override
6 public void run()
7 {
8
9 int w = getWidth();
10 int h = getHeight();
11
12 float wipeArea = 0;
13 float totalArea = w * h;
14
15 Bitmap bitmap = mbitmap;
16
17 mPixels = new int[w * h];
18
19 /**
20 * 拿到所有的像素信息
21 */
22 bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);
23
24 /**
25 * 遍历统计擦除的区域
26 */
27 for (int i = 0; i < w; i++)
28 {
29 for (int j = 0; j < h; j++)
30 {
31 int index = i + j * w;
32 if (mPixels[index] == 0)
33 {
34 wipeArea++;
35 }
36 }
37 }
38
39 /**
40 * 根据所占百分比,进行一些操作
41 */
42 if (wipeArea > 0 && totalArea > 0)
43 {
44 int percent = (int) (wipeArea * 100 / totalArea);
45 Log.e("TAG", percent + "");
46
47 if (percent > 70) //如果刮开面积达到70% 则将mComplete布尔值设为true 将全部图案显示出来
48 {
49 mComplete = true;
50 postInvalidate();
51 }
52 }
53 }
54
55 };
在ACTION_UP,即松开触屏的时候调用
1 case MotionEvent.ACTION_UP://抬起
2 new Thread(mRunnable).start();// 统计擦除区域任务
3 break;
任务结束,会把一个mComplete设置为true;当为true时,直接展现刮奖区
1 @Override
2 protected void onDraw(Canvas canvas)
3 {
4 drawBackText(canvas);
5
6 if (!isComplete)
7 {
8 drawPath();
9 canvas.drawBitmap(mBitmap, 0, 0, null);
10 }
11
12 }
效果图: