安卓:制作一个刮奖控件
1.创建自定义控件,如果要显示文字则继承TextView。
2.设置好画笔的颜色,粗细,空心还是实心,透明度,有无锯齿,等参数。
3.画笔还要设置交叉颜色的类型。
4.从资源图片获得覆盖奖品图片的图案。
1 package com.example.scratcharea; 2 3 import com.example.scratcharea.ScratchController.OnScratchListener; 4 5 import android.R.drawable; 6 import android.R.integer; 7 import android.app.ActionBar.LayoutParams; 8 import android.content.Context; 9 import android.content.res.Resources; 10 import android.content.res.TypedArray; 11 import android.graphics.Bitmap; 12 import android.graphics.Bitmap.Config; 13 import android.graphics.BitmapFactory; 14 import android.graphics.Canvas; 15 import android.graphics.Color; 16 import android.graphics.Matrix; 17 import android.graphics.Paint; 18 import android.graphics.Path; 19 import android.graphics.PorterDuff; 20 import android.graphics.PorterDuffXfermode; 21 import android.graphics.drawable.BitmapDrawable; 22 import android.graphics.drawable.Drawable; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.util.AttributeSet; 26 import android.util.Log; 27 import android.view.MotionEvent; 28 import android.view.ViewGroup; 29 import android.widget.ImageView; 30 import android.widget.Toast; 31 import android.media.AudioManager; 32 import android.media.SoundPool; 33 34 public class ScratchController extends ImageView{ 35 36 private Context context; 37 private Paint pen; 38 private Path drawPath; 39 private Paint bitmapPen; 40 41 private Canvas canvas; 42 private float mx,my; 43 private SoundPool sp; 44 int scratchSound; 45 int streamId; 46 boolean isplaying=false; 47 OnScratchListener scratchListener; 48 boolean canCalculate=false; 49 50 private Bitmap maskbitmap; 51 52 int picWidth; 53 int picHeight; 54 55 int maskWidth; 56 int maskHeight; 57 58 int picColorPixels; 59 int maskColorPixels; 60 61 public interface OnScratchListener{//事件监听接口 62 void onScratch(int persent); 63 } 64 65 public void setOnScratchListener(OnScratchListener listener){ 66 this.scratchListener = listener; 67 } 68 69 Handler scratchHandler = new Handler(){ 70 public void handleMessage(Message msg){ 71 if(scratchListener!=null){ 72 int persent = msg.arg1; 73 scratchListener.onScratch(persent); 74 } 75 } 76 }; 77 78 Runnable calMaskRunnable = new Runnable() { 79 80 @Override 81 public void run() { 82 maskColorPixels=calColorPixels(maskbitmap);//计算所有有色像素的个数 83 // Log.i("calMaskRunnable","maskColorPixels:"+maskColorPixels); 84 } 85 }; 86 87 Runnable calPercentRunnable = new Runnable() { 88 89 @Override 90 public void run() { 91 if(canCalculate){//计算后来的有色像素和初始有色像素的比值并增大100倍。。。 92 int colorPixels=calColorPixels(maskbitmap); 93 // Log.i("calMaskRunnable","colorPixels: "+colorPixels); 94 int percent =100-(int)((colorPixels*1.0/maskColorPixels)*100); 95 Message msg= scratchHandler.obtainMessage();//从message pool中获取一个message 并且将message 的target属性指向改handler 96 msg.arg1 =percent;// 97 scratchHandler.sendMessage(msg); 98 } 99 } 100 }; 101 102 private int calColorPixels(Bitmap bitmap){ 103 int colorPixels = 0; 104 int w=bitmap.getWidth(); 105 int h=bitmap.getHeight(); 106 int arrLen = w*h; 107 int [] pixels = new int [arrLen]; 108 // Log.i("calColorPixels","w: "+w+" h: "+h); 109 bitmap.getPixels(pixels, 0, w, 0, 0, w, h);//获取像素的点 110 for(int i=0;i<arrLen;i++){ 111 if(pixels[i]!=0){ 112 colorPixels++; 113 } 114 } 115 return colorPixels; 116 } 117 118 public ScratchController(Context context, AttributeSet attrs) { 119 super(context, attrs); 120 this.context=context; 121 TypedArray tArray = context.obtainStyledAttributes(attrs, R.styleable.ScratchArea); 122 int len = tArray.length(); 123 for(int i=0;i<len;i++){ 124 if(R.styleable.ScratchArea_pic==tArray.getIndex(i)){ 125 int id = tArray.getResourceId(R.styleable.ScratchArea_pic, 0); 126 if(id!=0){ 127 setPic(id); 128 } 129 } 130 if(R.styleable.ScratchArea_mask==tArray.getIndex(i)){ 131 int id = tArray.getResourceId(R.styleable.ScratchArea_mask, 0); 132 if(id!=0){ 133 if(id!=0){ 134 setMask(id); 135 } 136 } 137 } 138 } 139 tArray.recycle(); 140 } 141 142 public void setPic(int resId){ 143 this.setImageResource(resId); 144 this.setScaleType(ImageView.ScaleType.FIT_XY); 145 // ViewGroup.LayoutParams params = this.getLayoutParams(); 146 // picWidth = params.width; 147 // picHeight = params.height; 148 } 149 150 @Override 151 public void setLayoutParams(ViewGroup.LayoutParams params){ 152 super.setLayoutParams(params); 153 picWidth = params.width; 154 picHeight = params.height; 155 } 156 157 public void startInit(){ 158 init(); 159 } 160 private void init() { 161 pen = new Paint(); 162 pen.setAntiAlias(true);//抗锯齿 163 //pen.setAlpha(220);//设置透明度 164 pen.setDither(true);//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 165 //pen.setColor(Color.WHITE); 166 pen.setStyle(Paint.Style.STROKE); 167 pen.setStrokeWidth(35); 168 pen.setStrokeJoin(Paint.Join.ROUND);//前端是圆的 169 pen.setStrokeCap(Paint.Cap.ROUND);//后端是圆的 170 pen.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//设置颜色交叉模式为清除 171 172 bitmapPen=new Paint(); 173 drawPath = new Path(); 174 175 176 177 178 canvas = new Canvas(maskbitmap); 179 //canvas.drawColor(maskColor); 180 sp= new SoundPool(1,AudioManager.STREAM_SYSTEM,3);// 181 scratchSound = sp.load(this.getContext(), R.raw.scratch3,1); 182 183 canCalculate= false; 184 } 185 186 @Override 187 protected void onDraw(Canvas canvas) { 188 super.onDraw(canvas); 189 190 this.canvas.drawPath(drawPath, pen); 191 canvas.drawBitmap(maskbitmap, 0, 0, bitmapPen); 192 } 193 194 @Override 195 public boolean onTouchEvent(MotionEvent event) {//事件处理函数 196 switch (event.getAction()){ 197 case MotionEvent.ACTION_DOWN: 198 touchDown(event); 199 //Toast.makeText(this.context, "touchDown", Toast.LENGTH_SHORT).show(); 200 break; 201 case MotionEvent.ACTION_MOVE: 202 touchMove(event); 203 //Toast.makeText(this.context, "touchMove", Toast.LENGTH_SHORT).show(); 204 break; 205 case MotionEvent.ACTION_UP: 206 touchUp(event); 207 break; 208 default: 209 break; 210 } 211 return true; 212 } 213 214 private void touchUp(MotionEvent event) { 215 if(isplaying){ 216 sp.stop(streamId); 217 isplaying = false; 218 } 219 canCalculate = true; 220 new Thread(calPercentRunnable).start(); 221 } 222 223 private void touchMove(MotionEvent event) { 224 225 //Toast.makeText(this.context, "touchMove", Toast.LENGTH_SHORT).show(); 226 227 float preX=mx; 228 float preY=my; 229 mx = event.getX(); 230 my = event.getY(); 231 232 if(Math.abs(preX-mx)>1||Math.abs(preY-my)>1){ 233 234 float cx=(preX+mx)/2; 235 float cy=(preY+my)/2; 236 237 drawPath.quadTo(cx, cy, mx, my);//贝塞尔曲线平滑处理 238 if(!isplaying) 239 streamId = sp.play(scratchSound, 1, 1, 0, -1, (float)0.5); 240 isplaying =true; 241 invalidate(); 242 } 243 244 } 245 246 private void touchDown(MotionEvent event) { 247 248 // Toast.makeText(this.context, "touchDown", Toast.LENGTH_SHORT).show(); 249 mx=event.getX(); 250 my=event.getY(); 251 252 drawPath.reset(); 253 drawPath.moveTo(mx, my); 254 255 } 256 257 public void setMask(int mask){ 258 Resources res = getResources(); 259 maskbitmap = BitmapFactory.decodeResource(res, mask).copy(Bitmap.Config.ARGB_8888, true); 260 // bitmap = Bitmap.createBitmap(480, 800, Config.ARGB_8888); 261 int width = maskbitmap.getWidth(); 262 //Log.i("ScratchController","width:"+width); 263 //Toast.makeText(this.context, width, Toast.LENGTH_LONG).show(); 264 int height = maskbitmap.getHeight(); 265 //Log.i("ScratchController","height:"+height); 266 267 maskWidth=picWidth; 268 //Log.i("ScratchController","maskWidth:"+maskWidth); 269 maskHeight =picHeight; 270 //Log.i("ScratchController","maskHeight:"+maskHeight); 271 272 float scaleWidth = ((float)maskWidth)/width; 273 float scaleHeight = ((float)maskHeight)/height; 274 Matrix matrix = new Matrix(); 275 matrix.postScale(scaleWidth, scaleHeight);//放缩变换 276 maskbitmap = Bitmap.createBitmap(maskbitmap,0,0,width,height,matrix,true);//以maskbitmap为模板创建bitmap 277 278 new Thread(calMaskRunnable).start(); 279 } 280 281 282 }