自定义View->刮刮乐
原理:canvas画上背景加文字<奖项>,再画上遮罩层,通过paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 用户点击滑动后清除遮罩层。核心就是前面那句话。
package com.example.customshapedemo; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class GuaGuaKa extends View { Path path = new Path();// 用作划线 Paint paint = new Paint();// 初始化画笔 Bitmap mBitmap;// 最终要画在canvas上的bitmap Canvas mCanvas;// 用来给mBitmap上进行填充的画布 String text = ""; int text_size = 20; int background_color = Color.parseColor("#FFFAFA"); int text_color = Color.BLACK; int mask_color = Color.parseColor("#CFCFCF"); int strokeWidth = 20; Drawable mask_Drawable; public GuaGuaKa(Context context) { super(context); // TODO Auto-generated constructor stub initPaint(); } public GuaGuaKa(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub initParam(context, attrs); initPaint(); } public GuaGuaKa(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initParam(context, attrs); initPaint(); } // 解析参数 void initParam(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.GuaGuaKa); background_color = typedArray.getColor(0, background_color); text = typedArray.getString(1); text_color = typedArray.getColor(2, text_color); text_size = typedArray.getInt(3, text_size); mask_Drawable = typedArray.getDrawable(4); if (mask_Drawable instanceof ColorDrawable) { mask_color = typedArray.getColor(4, mask_color); } strokeWidth = typedArray.getColor(5, strokeWidth); typedArray.recycle(); } // 初始化画笔 void initPaint() { paint.setAntiAlias(true);// 消除锯齿 paint.setDither(true);// 消除色块 paint.setStrokeJoin(Paint.Join.ROUND); // 线条对接处圆润 paint.setStrokeCap(Paint.Cap.ROUND); // 线条圆润 paint.setStrokeWidth(strokeWidth); paint.setStyle(Paint.Style.STROKE); // 空心 } /** * 初始化刮刮卡的底层颜色,并且写上奖项 * * @param canvas */ void initPrizeLayer(Canvas canvas, String str) { Paint p = new Paint();// 初始化画笔 p.setStyle(Paint.Style.FILL); // 获取View的宽高 int w = canvas.getWidth(); int h = canvas.getHeight(); // 最底层的背景色 canvas.drawColor(background_color); // 初始化一个字体 Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD); p.setTypeface(font); p.setTextSize(text_size); p.setColor(text_color); // 获取字符串的宽高 Rect r = new Rect(); p.getTextBounds(str, 0, text.length(), r); int str_h = r.height(); int str_w = r.width(); // 给View的canvas中写上奖金 canvas.drawText(str, (w - str_w) / 2, (h + str_h) / 2, p); // 创建一个bitmap然后画上遮罩层 mBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888); mCanvas = new Canvas(mBitmap); if (!(mask_Drawable instanceof ColorDrawable)) { Bitmap bm = ((BitmapDrawable) mask_Drawable).getBitmap(); int ww = bm.getWidth(); int hh = bm.getHeight(); float scale_w=(float)w/ww; float scale_h=(float)h/hh; Matrix matrix = new Matrix(); matrix.postScale(scale_w, scale_h); Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, ww, hh, matrix, true); mCanvas.drawBitmap(newbm, 0, 0, null); } else { mCanvas.drawColor(mask_color); } } // 用户点击后划线操作 void drawPath(Canvas canvas) { mCanvas.drawPath(path, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub //如果擦除超过70%则清空遮罩层 if(isclear){ initPrizeLayer(canvas, text); drawPath(canvas); return; } initPrizeLayer(canvas, text); drawPath(canvas); canvas.drawBitmap(mBitmap, 0, 0, null); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(x, y); break; case MotionEvent.ACTION_MOVE: path.lineTo(x, y); break; case MotionEvent.ACTION_UP: new Thread(ClearPixelsCalc).start(); break; default: break; } invalidate();// 更新界面 return true; } boolean isclear=false; //计算擦掉的部分的线程 Runnable ClearPixelsCalc=new Runnable() { @Override public void run() { // TODO Auto-generated method stub int count=0; int w=getWidth(); int h=getHeight(); int[] pixels=new int[w*h]; mBitmap.getPixels(pixels, 0, w, 0, 0, w, h); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int idx=i+j*w; if(pixels[idx]==0){ count++; } } } if(count>0&&w*h>0){ if(count/(w*h*1.0f)>0.8){ isclear=true; postInvalidate(); } } } }; }
自定义属性:
<declare-styleable name="GuaGuaKa"> <attr name="backgroundColor" format="reference|color" /> <attr name="text" format="reference|string" /> <attr name="textColor" format="reference|color" /> <attr name="textSize" format="integer" /> <attr name="maskColor" format="reference|color" /> <attr name="strokeWidth" format="integer" /> </declare-styleable>
View引入:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:customshape="http://schemas.android.com/apk/res/com.example.customshapedemo" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <com.example.customshapedemo.GuaGuaKa android:layout_width="300dp" android:layout_height="100dp" customshape:text="奖金 5,000,000 RMB" customshape:textSize="30" customshape:strokeWidth="50" /> </RelativeLayout>