直接拿来用的Android刮奖控件
更新时间:2016年09月05日 15:47:39 作者:cmeiyuan
这篇文章主要为大家分享了可以直接拿来用的Android刮奖控件,非常棒的刮奖控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
直接上效果图
功能特色:
1、可以设置刮开后显示文字或图片
2、可以统计已刮开区域所占百分比
Demo下载地址:RubberDemo.rar
下面是源码:
@SuppressLint("HandlerLeak") public class RubberView extends TextView { private static final int W = 480; private static final int H = 800; private static final int MV = 1; private static final int SW = 50; private static final int MC = 0xFFD6D6D6; private int mWidth; private int mHeight; private int mMaskColor; private int mStrokeWidth; private float mX; private float mY; private boolean mRun; private boolean caculate; private Path mPath; private Paint mPaint; private Paint mBitmapPaint; private Canvas mCanvas; private Bitmap mBitmap; private int[] mPixels; private Thread mThread; private onWipeListener mWipeListener; public RubberView(Context context) { super(context); init(context); } public RubberView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private final void init(Context context) { mMaskColor = MC; mStrokeWidth = SW; mPath = new Path(); mBitmapPaint = new Paint(); mPaint = new Paint(); mPaint.setAntiAlias(true);// 抗锯齿 mPaint.setDither(true);// 递色 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); // 前圆角 mPaint.setStrokeCap(Paint.Cap.ROUND); // 后圆角 mPaint.setStrokeWidth(mStrokeWidth); // 笔宽 mBitmap = Bitmap.createBitmap(W, H, Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mCanvas.drawColor(mMaskColor); mRun = true; mThread = new Thread(mRunnable); mThread.start(); setGravity(Gravity.CENTER); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mCanvas.drawPath(mPath, mPaint); canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int w = MeasureSpec.getSize(widthMeasureSpec); int h = MeasureSpec.getSize(heightMeasureSpec); if (w > 0 && h > 0) { mWidth = w; mHeight = h; } } public void reset() { mPath.reset(); mCanvas.drawPaint(mPaint); mCanvas.drawColor(mMaskColor); invalidate(); } public void setOnWipeListener(onWipeListener listerer) { this.mWipeListener = listerer; } public void setStrokeWidth(int width) { this.mStrokeWidth = width; mPaint.setStrokeWidth(width); } public void setMaskColor(int color) { this.mMaskColor = color; reset(); } @Override public boolean onTouchEvent(MotionEvent event) { boolean invalidate = false; boolean consume = false; int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: consume = true; touchDown(event); break; case MotionEvent.ACTION_MOVE: consume = true; invalidate = touchMove(event); break; case MotionEvent.ACTION_UP: consume = true; touchUp(event); break; } if (invalidate) { invalidate(); } if (consume) { return true; } return super.onTouchEvent(event); } // 手指点下屏幕时调用 private void touchDown(MotionEvent event) { caculate = false; // 重置绘制路线,即隐藏之前绘制的轨迹 mPath.reset(); float x = event.getX(); float y = event.getY(); mX = x; mY = y; // mPath绘制的绘制起点 mPath.moveTo(x, y); } // 手指在屏幕上滑动时调用 private boolean touchMove(MotionEvent event) { caculate = false; final float x = event.getX(); final float y = event.getY(); final float previousX = mX; final float previousY = mY; // 设置贝塞尔曲线的操作点为起点和终点的一半 float cX = (x + previousX) / 2; float cY = (y + previousY) / 2; final float dx = Math.abs(x - previousX); final float dy = Math.abs(y - previousY); boolean move = false; if (dx >= MV || dy >= MV) { // 二次贝塞尔,实现平滑曲线;cX, cY为操作点 x,y为终点 mPath.quadTo(cX, cY, x, y); // 第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值 mX = x; mY = y; move = true; } return move; } private void touchUp(MotionEvent event) { caculate = true; mRun = true; } private Runnable mRunnable = new Runnable() { @Override public void run() { while (mRun) { SystemClock.sleep(100); // 收到计算命令,立即开始计算 if (caculate) { caculate = false; int w = mWidth; int h = mHeight; float wipeArea = 0; float totalArea = w * h; // 计算耗时100毫秒左右 Bitmap bitmap = mBitmap; if (mPixels == null) { mPixels = new int[w * h]; } 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); Message msg = mHandler.obtainMessage(); msg.what = 0x1; msg.arg1 = percent; mHandler.sendMessage(msg); } } } } }; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (mWipeListener != null) { int percent = msg.arg1; mWipeListener.onWipe(percent); } }; }; public interface onWipeListener { public void onWipe(int percent); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mRun = false; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
解析:继承ViewGroup后的子类如何重写onMeasure方法
本篇文章是对继承ViewGroup后的子类如何重写onMeasure方法进行了详细的分析介绍,需要的朋友参考下2013-06-06Android开发中Looper.prepare()和Looper.loop()
Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,具体调用方法大家可以通过本文学习2016-11-11
最新评论