电商活动中刮刮卡的实现

一、实现原理

Paint.setXferMode();

a、绘制我们的圆形
b、setXferMode(SrcIn)
c、绘制矩形(正方形)图片


二、主要思想:


将一个view设计成多层:背景层,含中奖信息等;


遮盖层,用于刮奖,使用关联一个Bitmap的Canvas


在该Bitmap上,使用它的canvas.drawPath的api来处理 手势滑动(类似刮奖的动作)


使用paint.setXfermode 来进行消除手势滑动区域


当刮开90%的时候会全部消失。

三、代码实现

public class GuaGuaKa extends View
{
	private Paint mOutterPaint;
	private Path mPath;
	private Canvas mCanvas;
	private Bitmap mBitmap;

	private int mLastX;
	private int mLastY;

	private Bitmap mOutterBitmap;

	// -------------------------------

	// private Bitmap bitmap;

	private String mText;
	private Paint mBackPaint;

	/**
	 * 记录刮奖信息文本的宽和高
	 */
	private Rect mTextBound;
	private int mTextSize;
	private int mTextColor;

	// 判断遮盖层区域是否消除达到阈值
	private volatile boolean mComplete = false;

	/**
	 * 刮刮卡刮完的回调
	 * 
	 * 
	 */
	public interface OnGuaGuaKaCompleteListener
	{
		void complete();
	}

	private OnGuaGuaKaCompleteListener mListener;

	public void setOnGuaGuaKaCompleteListener(
			OnGuaGuaKaCompleteListener mListener)
	{
		this.mListener = mListener;
	}

	public GuaGuaKa(Context context)
	{
		this(context, null);
	}

	public GuaGuaKa(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
	}

	public GuaGuaKa(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
		init();
		TypedArray a = null;
		try
		{
			a = context.getTheme().obtainStyledAttributes(attrs,
					R.styleable.GuaGuaKa, defStyle, 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_textSize:
					mTextSize = (int) a.getDimension(attr, TypedValue
							.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22,
									getResources().getDisplayMetrics()));
					break;
				case R.styleable.GuaGuaKa_textColor:
					mTextColor = a.getColor(attr, 0x000000);
					break;
				}

			}

		} finally
		{
			if (a != null)
				a.recycle();
		}

	}

	public void setText(String mText)
	{
		this.mText = mText;
		// 获得当前画笔绘制文本的宽和高
		mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		int width = getMeasuredWidth();
		int height = getMeasuredHeight();
		// 初始化我们的bitmap
		mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
		mCanvas = new Canvas(mBitmap);

		// 设置绘制path画笔的一些属性
		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);

	}

	/**
	 * 设置我们绘制获奖信息的画笔属性
	 */
	private void setUpBackPaint()
	{
		mBackPaint.setColor(mTextColor);
		mBackPaint.setStyle(Style.FILL);
		mBackPaint.setTextSize(mTextSize);
		// 获得当前画笔绘制文本的宽和高
		mBackPaint.getTextBounds(mText, 0, mText.length(), mTextBound);

	}

	/**
	 * 设置绘制path画笔的一些属性
	 */
	private void setupOutPaint()
	{
		mOutterPaint.setColor(Color.parseColor("#c0c0c0"));
		mOutterPaint.setAntiAlias(true);
		mOutterPaint.setDither(true);
		mOutterPaint.setStrokeJoin(Paint.Join.ROUND);
		mOutterPaint.setStrokeCap(Paint.Cap.ROUND);
		mOutterPaint.setStyle(Style.FILL);
		mOutterPaint.setStrokeWidth(20);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		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_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;
		case MotionEvent.ACTION_UP:
			if (!mComplete)
				new Thread(mRunnable).start();
			break;
		}
		if (!mComplete)
			invalidate();
		return true;

	}

</pre>我们在ACTION_UP的时候就行计算,首先我们还是给大家灌输下计算的原理,如果大家用心看了,应该知道我们所有的操作基本都在mBitmap,现在我们获得mBItmap上所有的像素点的数据,统计被清除的区域(被清除的像素为0);最后与我们图片的总像素数做个除法元算,就可以拿到我们清除的百分比了;不过,计算可能会是一个耗时的操作,具体速度跟图片大小有关,所以我们决定使用异步的方式去计算:<pre name="code" class="java">
	private Runnable mRunnable = new Runnable()
	{
		@Override
		public void run()
		{
			int w = getWidth();
			int h = getHeight();

			float wipeArea = 0;
			float totalArea = w * h;
			Bitmap bitmap = mBitmap;
			int[] mPixels = new int[w * h];

			// 获得Bitmap上所有的像素信息
			bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);

			for (int i = 0; i < w; i++)
			{
				for (int j = 0; j < h; j++)
				{
					int index = i + j * w;
					if (mPixels[index] == 0)
					{
						wipeArea++;
					}
				}
			}

			if (wipeArea > 0 && totalArea > 0)
			{
				int percent = (int) (wipeArea * 100 / totalArea);

				Log.e("TAG", percent + "");

				if (percent > 90)
				{
					// 清除掉图层区域
					mComplete = true;
					postInvalidate();

				}

			}

		}
	};

	@Override
	protected void onDraw(Canvas canvas)
	{
		// canvas.drawBitmap(bitmap, 0 , 0, null);

		canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2,
				getHeight() / 2 + mTextBound.height() / 2, mBackPaint);

		if (!mComplete)
		{
			drawPath();
			canvas.drawBitmap(mBitmap, 0, 0, null);
		}

		if (mComplete)
		{
			if (mListener != null)
			{
				mListener.complete();
			}
		}

	}

	private void drawPath()
	{
		mOutterPaint.setStyle(Style.STROKE);
		mOutterPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
		mCanvas.drawPath(mPath, mOutterPaint);
	}

	/**
	 * 进行一些初始化操作
	 */
	private void init()
	{
		mOutterPaint = new Paint();
		mPath = new Path();
		
		mOutterBitmap = BitmapFactory.decodeResource(getResources(),
				cn.zhilinghui.guaguaka.R.drawable.fg_guaguaka);
		mText = "谢谢惠顾";
		mTextBound = new Rect();
		mBackPaint = new Paint();
		mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
				22, getResources().getDisplayMetrics());

	}

}
view的自定义控件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:hyman="http://schemas.android.com/apk/res/cn.zhilinghui.guaguaka"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <cn.zhilinghui.guaguaka.view.GuaGuaKa
        android:id="@+id/id_guaguaka"
        android:layout_width="300dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        hyman:text="¥500,0000"
        hyman:textColor="#ff00f0"
        hyman:textSize="30sp" />

</RelativeLayout>



posted @ 2016-01-20 22:13  朱培  阅读(298)  评论(0编辑  收藏  举报