package com.applite.androidallinone.scratchcard;
import java.text.BreakIterator;
import com.applite.androidallinone.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
/**
* @author pcher_000
*
*/
public class ScratchCradView extends View {
//画笔 外部
private Paint mOutterPaint;
//记录用户绘制路径
private Path mPath;
//画布
private Canvas mCanvas;
//图片
private Bitmap mBitmap;
private int mLastX;
private int mLastY;
//背景图
private Bitmap backgroundBitmap;
//刮刮卡内容区域外的图片
private Bitmap mOutterBitmap;
//绘制的文本
private String mText;
public void setText(String mText) {
this.mText = mText;
//注意 字体设置后 重新设置
mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
//设置刮刮卡文字大小
private int mTextSize;
//设置刮刮卡字体颜色
private int mTextColor;
//
private Paint mBackPaint;
/**
* 记录刮刮卡刮奖信息文本的宽和高
*/
private Rect mTextBound;
//判断遮盖区域是否消除达到阈值
//注意并发 脏读和可见性
volatile boolean mComplete=false;
/*
* 刮完的回调
* */
public interface OnScratchCompleteListener{
void complete();
};
private OnScratchCompleteListener mListener;
public ScratchCradView(Context context) {
this(context,null);
// TODO Auto-generated constructor stub
}
public ScratchCradView(Context context, AttributeSet attrs) {
this(context, attrs,0);
// TODO Auto-generated constructor stub
}
//自定义属性的话 还是调用两个参数的构造函数 调用三个参数的方法,必须显式的调用 系统一般不会自动调用
/**
* @param context
* @param attrs
* @param defStyleAttr
*/
public ScratchCradView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
//读取自定义属性
TypedArray array = null;
try {
array=context.getTheme().obtainStyledAttributes(attrs, R.styleable.ScratchCradView, defStyleAttr,0);
int length=array.getIndexCount();
for (int i = 0; i < length; i++) {
int index=array.getIndex(i);
switch (index) {
case R.styleable.ScratchCradView_text:
mText=array.getString(index);
break;
case R.styleable.ScratchCradView_textSize:
mTextSize=(int)array.getDimension(index, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics()));
break;
case R.styleable.ScratchCradView_textColor:
mTextColor=array.getColor(index, 0x000000);
break;
}
}
} finally {
if(array!=null)
{
array.recycle();
}
}
}
/**
* 初始化操作
*/
private void init()
{
mOutterPaint=new Paint();
mPath=new Path();
backgroundBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.t2);
mOutterBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.fg_guaguaka);
mText="我中了500万啦";
mTextBound=new Rect();
mBackPaint=new Paint();
mTextSize=(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics());;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
//widthMeasureSpec和heightMeasureSpec用来描述当前正在处理的视图可以获得的最大宽度和高度
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//拿到空间的宽和高
int width=getMeasuredWidth();
int height=getMeasuredHeight();
//bitmap的配置 不同配置 字节占用不同
mBitmap=Bitmap.createBitmap(width, height, Config.ARGB_8888);
mCanvas=new Canvas(mBitmap);
setupOutPaint();
setupBackPaint();
//画布灰色 遮住获奖信息
//mCanvas.drawColor(Color.parseColor("#c0c0c0"));
mCanvas.drawRoundRect(new RectF(0,0,width,height), 30, 30, mOutterPaint);
mCanvas.drawBitmap(mOutterBitmap, null, new Rect(0,0,width,height), null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action=event.getAction();
//获取坐标值
int x=(int)event.getX();
int y=(int)event.getY();
Log.d("d", "x:"+x+"y:"+y);
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastX=x;
mLastY=y;
mPath.moveTo(mLastX, mLastY);//代表开启了一个新的路径
break;
case MotionEvent.ACTION_MOVE:
//坐标差值
int dx=Math.abs(x-mLastX);
int dy=Math.abs(y-mLastX);
if(dx>3||dy>3)
{
//注意注意 错误写成moveto
mPath.lineTo(x, y);
}
mLastX=x;
mLastY=y;
break;
case MotionEvent.ACTION_UP:
new Thread(mRunnable).start();
break;
default:
break;
}
//?请求重绘View树
invalidate();
return true;
}
private Runnable mRunnable=new Runnable() {
@Override
public void run() {
int width=getWidth();
int height=getHeight();
//擦除区域面积
float wipeArea=0;
float totalArea=width*height;
Bitmap bitmap=mBitmap;
int[] mPixels=new int[width*height];
//获取bitmap上所有的像素信息
bitmap.getPixels(mPixels, 0, width, 0, 0, width, height);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
//获取每个像素点的索引
int index=i+j*width;
if(mPixels[index]==0)
{
wipeArea++;
}
}
}
if(wipeArea>0&&totalArea>0)
{
//擦除区域百分比
int percent=(int)(wipeArea*100/totalArea);
Log.d("d", percent+"");
if(percent>60)
{
//清除图层区域
mComplete=true;
//子线程 调用postInvalidate() 注意不能直接调用invalidate()
postInvalidate();
}
}
}
};
@Override
protected void onDraw(Canvas canvas) {
//canvas.drawBitmap(backgroundBitmap, 0, 0, null);
//图片显示在最底层
canvas.drawText(mText, getWidth()/2-mTextBound.width()/2, getHeight()/2+mTextBound.height()/2, mBackPaint);
if(mComplete)
{
//放到主线程中
if(mListener!=null)
{
mListener.complete();
}
}
//需要好好理解清除到了阈值后
if(!mComplete)
{
drawPath();
canvas.drawBitmap(mBitmap,0,0,null);
}
}
private void drawPath(){
mOutterPaint.setStyle(Style.STROKE);
mOutterPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
//
mCanvas.drawPath(mPath, mOutterPaint);
}
//alt+shift+m 选中代码 生成方法
// 设置绘制path画笔的一些属性
private void setupOutPaint() {
mOutterPaint.setColor(Color.parseColor("#c0c0c0"));
mOutterPaint.setAntiAlias(true);//设置防止锯齿
mOutterPaint.setDither(true);//设置防止抖动
mOutterPaint.setStrokeJoin(Join.ROUND);//设置接洽点类型
mOutterPaint.setStrokeCap(Cap.ROUND);//
mOutterPaint.setStyle(Style.FILL);//设置画笔样式
mOutterPaint.setStrokeWidth(40);
}
/*
* 设置获奖信息的画笔
* */
private void setupBackPaint(){
mBackPaint.setColor(mTextColor);
mBackPaint.setStyle(Style.FILL);
mBackPaint.setTextSize(mTextSize);
/*
* 获取当前画笔绘制文本的宽和高
* */
mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
}
public void setOnScratchCompleteListener(OnScratchCompleteListener listener) {
this.mListener = listener;
}
}