仿刮刮卡效果
实现方法:
1.在底层绘制一个中奖信息的图片
2.在上一层加一层图片作为刮的
3.手指在刮时,记录手指滑动的路径,将该路径与上面图片重合的区域透明
如下图:假设Dst为刮刮卡上面的图片,Src代表的是我们刮过的区域,当我们使用DstOut模式时,就让划过的区域透明了,此时,就可以看到最外层下面的中奖信息图片了
代码如下:
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; 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.util.TypedValue; import android.view.MotionEvent; import android.view.View; import com.tsgithub.R; /** * 刮刮卡 */ public class GuaGuaKa extends View { private Paint mOutterPaint; private Path mPath;//手指划屏幕的路径 private Canvas mCanvas; /** * 组合成的图片 */ private Bitmap mBitmap;//使用mOutterPaint在mBitmap上绘制 private int mLastX; private int mLastY; /** * 覆盖在刮刮卡上的图层 也就是最外层图片 */ private Bitmap mOutterBitmap; //--------------以上为遮盖层的变量 private String mText; private int mTextSize; private int mTextColor; private Paint mBackPaint;//绘制“谢谢参与”的画笔 private Rect mTextBound;//“谢谢参与”的矩形范围 /** * 判断擦除的比例是否达到60%,如果是清除最外层图片 */ private volatile boolean mComplete = false; public GuaGuaKa(Context context) { this(context, null); } public GuaGuaKa(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GuaGuaKa(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); //获得自定义属性 TypedArray a = null; try { a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GuaGuaKa, defStyleAttr, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.GuaGuaKa_text: mText = a.getString(attr); break; case R.styleable.GuaGuaKa_textColor: mTextColor = a.getColor(attr, 0x000000); break; case R.styleable.GuaGuaKa_textSize: //将22sp转为像素值 mTextSize = (int) a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics())); break; case R.styleable.GuaGuaKa_outImg: mOutterBitmap= BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0)); break; } } } finally { a.recycle(); } } /** * 初始化 一些默认值 */ private void init() { mOutterPaint = new Paint(); mPath = new Path(); mTextBound = new Rect(); mBackPaint = new Paint(); mText = "谢谢惠顾!"; mTextColor = Color.parseColor("#000000"); mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics()); //覆盖在最上面的图片 mOutterBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_ggk_out); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); int height = getMeasuredHeight(); //初始化bitmap mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); setupOutPaint();//设置“橡皮擦”画笔的属性 setupBackPaint();//设置绘制“谢谢参与”的画笔属性 //mCanvas.drawColor(Color.parseColor("#c0c0c0"));//在控件区域绘制一个灰色的图层 //画覆盖层的bitmap,是圆角矩形 mCanvas.drawRoundRect(new RectF(0, 0, width, height), 100, 100, mOutterPaint); mCanvas.drawBitmap(mOutterBitmap, null, new Rect(0, 0, width, height), null);//画“谢谢参与”bitmap } /** * 设置绘制“谢谢参与”的画笔属性 */ private void setupBackPaint() { mBackPaint.setColor(mTextColor); mBackPaint.setStyle(Paint.Style.FILL); mBackPaint.setTextSize(mTextSize); //获得画笔绘制文本的宽和高(矩形范围) mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound); } /** * 设置 橡皮擦 画笔的属性 * 因为使用的PorterDuff.Mode.DST_OUT模式,所以设置的颜色值其实没作用 */ private void setupOutPaint() { mOutterPaint.setColor(Color.parseColor("#ffcccc")); mOutterPaint.setAntiAlias(true); mOutterPaint.setDither(true); mOutterPaint.setStrokeJoin(Paint.Join.ROUND); mOutterPaint.setStrokeCap(Paint.Cap.ROUND); mOutterPaint.setStyle(Paint.Style.STROKE); mOutterPaint.setStrokeWidth(20); } @Override public boolean onTouchEvent(MotionEvent event) { //绘制path 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_UP: new Thread(mRunnable).start(); 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; break; } invalidate();//执行此方法会调用onDraw方法绘制 return true; } private Runnable mRunnable = new Runnable() { @Override public void run() { int width = getWidth();//拿到控件宽、高 int height = getHeight(); float wipeArea = 0;//已经擦除的比例 float totalArea = width * height; int[] mPixels = new int[width * height]; //获得bitmap的所有像素信息保存在mPixels中 mBitmap.getPixels(mPixels, 0, width, 0, 0, width, height); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int index = j * width + i; if (mPixels[index] == 0) { //代表该像素点是透明状态 wipeArea++; } } } if (wipeArea > 0 && totalArea > 0) { int percent = (int) (wipeArea * 100 / totalArea); Log.i("cool", percent + ""); if (percent > 60) { //清楚掉覆盖图层区域 mComplete = true; postInvalidate(); } } } }; @Override protected void onDraw(Canvas canvas) { //绘制“谢谢参与” canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2, getHeight() / 2 + mTextBound.height() / 2, mBackPaint);//绘制“谢谢参与”的文本 if (mComplete) { if (mListener != null) { mListener.onComplete(); } } if (!mComplete) { drawPath(); canvas.drawBitmap(mBitmap, 0, 0, null);//使bitmap显示到屏幕上,在内存中准备好bitmap,然后在屏幕上绘制出来 } } /** * 擦除的路径 */ private void drawPath() { mOutterPaint.setStyle(Paint.Style.STROKE); /** * 代表该路径都将会透明 */ mOutterPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//这个就是关键了 mCanvas.drawPath(mPath, mOutterPaint); } /** * 刮完的回调 */ public interface OnGuaGuaKaCompleteListener { void onComplete(); } private OnGuaGuaKaCompleteListener mListener; public void setOnGuaGuaKaCompleteListener(OnGuaGuaKaCompleteListener mListener) { this.mListener = mListener; } public void setText(String text){ this.mText = text; //获得画笔绘制文本的宽和高(矩形范围) mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound); } }
自定义属性:
<!--刮刮卡--> <declare-styleable name="GuaGuaKa"> <attr name="text" format="string"/> <attr name="textColor" format="color" /> <attr name="textSize" format="dimension"/> </declare-styleable>
使用如下:
<com.tsgithub.view.GuaGuaKa android:id="@+id/ggk" android:layout_width="300dp" android:layout_height="200dp" android:background="#ffcccc" app:text="一等奖" app:textColor="#ff0000" app:textSize="30sp" app:outImg="@drawable/icon_ggk_out"/>
效果图: