zoukankan      html  css  js  c++  java
  • 电商活动中刮刮卡的实现

    一、实现原理

    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>



  • 相关阅读:
    请求分页中的内存分配
    Android开发实例总结
    出现java.lang.IllegalArgumentException异常
    请求分页中的内存分配之续
    HTTPCLIENT使用学习
    传输控制层协议TCP概述抄书
    freemarker中空值 null的处理 ?exists ?if_exists ?default(“”)
    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring 大新博客 推酷 360安全浏览器 7.1
    jade 学习笔记 gulp 自动编译
    @resource和@autowired的区别是什么CSDN论坛CSDN.NET中国最大的IT技术社区 Google Chrome
  • 原文地址:https://www.cnblogs.com/sdksdk0/p/5585082.html
Copyright © 2011-2022 走看看