这样,下面我开始根据我的想法,把自定义九宫格的步骤说一下。
步骤:
1.计算各位方块的位置
2.绘制每个奖品的方块(主要让界面更加好看)
3.绘制奖品图
4.计算旋转方块的下一步位置
5.绘制旋转方块
6.监听点击开始按钮事件
主要核心技术:
SurfaceView,SurfaceHolder
OK,有了基本步骤,接下来就是根据步骤一步一步来进行了。
在开始绘制九宫格之前,我们先重写onMeasure方法,主要是为了让九宫格成为一个正方形,这样看起来体验更好,基本代码如下:
public class LotteryView extends SurfaceView{/** * holder */private SurfaceHolder mHolder;private List<Prize>prizes;private boolean flags;//抽奖开关private int lottery=6;//设置中奖号码private int current=2;//抽奖开始的位置private int count=0;//旋转次数累计private int countDown;//倒计次数,快速旋转完成后,需要倒计多少次循环才停止//旋转抽奖的方块默认颜色private int transfer= 0xffff0000;private int MAX=50;//最大旋转次数/*** 重新测量 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = Math.min(getMeasuredWidth(), getMeasuredHeight()); setMeasuredDimension(width, width); }}SurfaceView一般不是通过重写onDraw方法来绘制控件的,那么怎么获取到Canvas呢?主要是通过SurfaceHolder监听Callback事件来获取的
/** * holder */private SurfaceHolder mHolder;public LotteryView(Context context, AttributeSet attrs) {super(context, attrs);mHolder = this.getHolder();//监听CallBackmHolder.addCallback(this);}public LotteryView(Context context) {this(context,null);}现在有了对象SurfaceHolder对象,我们就可以获取到Canvas对象了,下面开始真正的绘制工作。
//绘制背景private void drawBg(Canvas canvas) {//清除已绘制的图形canvas.drawColor(Color.WHITE, Mode.CLEAR);//获取控件的宽度,因为要绘制九宫格,所以要平局分成三列int width = getMeasuredWidth()/3;int x1=0;int y1=0;int x2=0;int y2=0;int len = (int) Math.sqrt(prizes.size());for(int x=0;x<len*len;x++){Prize prize = prizes.get(x);int index=x;x1=getPaddingLeft()+width*(Math.abs(index)%len);y1=getPaddingTop()+width*(index/len);x2=x1+width;y2=y1+width;Rect rect=new Rect(x1,y1,x2,y2);Paint paint=new Paint();//绘制方块canvas.drawRect(rect, paint);}}解析:prizes 是一个集合,里面封装了奖品的一些基本信息,x1,y1,x2,y2分别是绘制奖品容器正方形的左上顶点和右下顶点,
通过观察发现,每一个方块位置都有一定的关系,即 x1=getPaddingLeft()+width*(Math.abs(index)%len);
y1=getPaddingTop()+width*(index/len); x2=x1+width; y2=y1+width;有了这些点的关系,就可以通过canvas.drawRect(rect, paint);绘制出方块了
//绘制奖品private void drawPrize(Canvas canvas) {int width = getMeasuredWidth()/3;int x1=0;int y1=0;int x2=0;int y2=0;int len = (int) Math.sqrt(prizes.size());for(int x=0;x<len*len;x++){Prize prize = prizes.get(x);int index=x;x1=getPaddingLeft()+width*(Math.abs(index)%len);y1=getPaddingTop()+width*(index/len);x2=x1+width;y2=y1+width;Rect rect=new Rect(x1+width/6,y1+width/6,x2-width/6,y2-width/6);prize.setRect(rect);canvas.drawBitmap(prize.getIcon(), null, rect, null);}}通过了步骤1,2知道了方块的位置关系,就可以轻松的根据这些关系绘制出奖品来,Rect rect=new Rect(x1+width/6,y1+width/6,x2-width/6,y2-width/6);是让奖品比方块缩小一些,这样看起来会更自然一点。
//下一步public int next(int position,int len){int current=position;if(current+1<len){return ++current;}if((current+1)%len==0&¤t<len*len-1){return current+=len;}if(current%len==0){return current-=len;}if(current<len*len){return --current;}return current;}position是当前旋转方块的位置,len是3
//绘制旋转的方块private void drawTransfer(Canvas canvas) {int width = getMeasuredWidth()/3;int x1;int y1;int x2;int y2;int len = (int) Math.sqrt(prizes.size());//得到下一步方块的位置current=next(current, len);x1=getPaddingLeft()+width*(Math.abs(current)%len);y1=getPaddingTop()+width*((current)/len);x2=x1+width;y2=y1+width;Rect rect=new Rect(x1,y1,x2,y2);Paint paint=new Paint();paint.setColor(transfer);canvas.drawRect(rect, paint);}6.监听点击开始按钮事件
private OnTransferWinningListener listener;public void setOnTransferWinningListener(OnTransferWinningListener listener){this.listener=listener;}public interface OnTransferWinningListener{/** * 中奖回调 * @param position */void onWinning(int position);}@Overridepublic boolean onTouchEvent(MotionEvent event) {handleTouch(event);return super.onTouchEvent(event);}/** * 触摸 * @param event */public void handleTouch(MotionEvent event) {Point touchPoint=new Point((int)event.getX()-getLeft(),(int)event.getY());switch(event.getAction()){case MotionEvent.ACTION_DOWN:Prize prize = prizes.get(Math.round(prizes.size())/2);if(prize.isClick(touchPoint)){if(!flags){setStartFlags(true);prize.click();}}break ;default:break ;}}//控制旋转private void controllerTransfer() {if(count>MAX){countDown++;SystemClock.sleep(count*5);}else{SystemClock.sleep(count*2);}count++;if(countDown>2){if(lottery==current){countDown=0;count=0;setStartFlags(false);if(listener!=null){//切换到主线程中运行post(new Runnable() {@Overridepublic void run() {listener.onWinning(current);}});}}}}至此,基本的自定义工作已经差不多了,使用demo如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><com.example.test.LotteryViewandroid:id="@+id/nl" android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout>
public class HomeActivity extends Activity {LotteryView nl;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.act_home);nl=(LotteryView) findViewById(R.id.nl);int[]prizesIcon={R.drawable.danfan,R.drawable.meizi,R.drawable.iphone,R.drawable.f015,R.drawable.arrow,R.drawable.f040,R.drawable.ipad,R.drawable.spree_icon,R.drawable.spree_success_icon};final List<Prize>prizes=new ArrayList<Prize>();for(int x=0;x<9;x++){Prize lottery=new Prize();lottery.setId(x+1);lottery.setName("Lottery"+(x+1));Bitmap bitmap = BitmapFactory.decodeResource(getResources(), prizesIcon[x]);lottery.setIcon(bitmap);if((x+1)%2==0){lottery.setBgColor(0xff4fccee);}else if(x==4){lottery.setBgColor(0xffffffff);}else{lottery.setBgColor(0xff00ff34);}prizes.add(lottery);}nl.setPrizes(prizes);nl.setOnTransferWinningListener(new OnTransferWinningListener() {@Overridepublic void onWinning(int position) {Toast.makeText(getApplicationContext(), prizes.get(position).getName(), Toast.LENGTH_SHORT).show();}});}}运行效果非常流畅
package com.example.test;import java.util.List;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Point;import android.graphics.PorterDuff;import android.graphics.PorterDuff.Mode;import android.graphics.Rect;import android.os.SystemClock;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceHolder.Callback;import android.view.SurfaceView;public class LotteryView extends SurfaceView implements Callback{ /** * holder */ private SurfaceHolder mHolder; private List<Prize>prizes; private boolean flags; private int lottery=6; //设置中奖号码 private int current=2; //抽奖开始的位置 private int count=0; //旋转次数累计 private int countDown; //倒计次数,快速旋转完成后,需要倒计多少次循环才停止 private int transfer= 0xffff0000; private int MAX=50; //最大旋转次数 private OnTransferWinningListener listener; public void setOnTransferWinningListener(OnTransferWinningListener listener){ this.listener=listener; } public interface OnTransferWinningListener{ /*** 中奖回调* @param position*/ void onWinning(int position); } /** * 设置中奖号码 * @param lottery */ public void setLottery(int lottery) { if(prizes!=null&&Math.round(prizes.size()/2)==0){throw new RuntimeException("开始抽奖按钮不能设置为中奖位置!"); } this.lottery = lottery; } /** * 设置转盘颜色 * @param transfer */ public void setTransfer(int transfer) { this.transfer = transfer; } /** * 设置奖品集合 * @param prizes */ public void setPrizes(List<Prize>prizes){ this.prizes=prizes; } @Override public boolean onTouchEvent(MotionEvent event) { handleTouch(event); return super.onTouchEvent(event); } /** * 触摸 * @param event */ public void handleTouch(MotionEvent event) { Point touchPoint=new Point((int)event.getX()-getLeft(),(int)event.getY()); switch(event.getAction()){ case MotionEvent.ACTION_DOWN:Prize prize = prizes.get(Math.round(prizes.size())/2);if(prize.isClick(touchPoint)){if(!flags){ setStartFlags(true); prize.click();}}break ; default:break ; } } private class SurfaceRunnable implements Runnable{ @Override public void run() {while(flags){Canvas canvas=null;try { canvas = mHolder.lockCanvas(); drawBg(canvas); drawTransfer(canvas); drawPrize(canvas); controllerTransfer();} catch (Exception e) { e.printStackTrace();}finally{ //涓轰簡璁╂瘡娆$粯鍒跺浘褰㈡椂鑳藉椤哄埄杩涜锛屾渶濂藉皢瑙i攣鏀惧埌寮傚父涓繘琛屽鐞嗭紝涔熷氨鏄锛屽鏋渃anvas涓嶄负绌猴紝閮藉皢鍏跺叧闂紝璁╀笅涓�娆″惊鐜兘澶熼『鍒╄繘琛岀粯鍒� if(canvas!=null) mHolder.unlockCanvasAndPost(canvas); }} } } //绘制背景 private void drawBg(Canvas canvas) { canvas.drawColor(Color.WHITE, Mode.CLEAR); int width = getMeasuredWidth()/3; int x1=0; int y1=0; int x2=0; int y2=0; int len = (int) Math.sqrt(prizes.size()); for(int x=0;x<len*len;x++){Prize prize = prizes.get(x);int index=x;x1=getPaddingLeft()+width*(Math.abs(index)%len);y1=getPaddingTop()+width*(index/len);x2=x1+width;y2=y1+width;Rect rect=new Rect(x1,y1,x2,y2);Paint paint=new Paint();paint.setColor(prize.getBgColor());canvas.drawRect(rect, paint); } } //绘制旋转的方块 private void drawTransfer(Canvas canvas) { int width = getMeasuredWidth()/3; int x1; int y1; int x2; int y2; int len = (int) Math.sqrt(prizes.size()); current=next(current, len); x1=getPaddingLeft()+width*(Math.abs(current)%len); y1=getPaddingTop()+width*((current)/len); x2=x1+width; y2=y1+width; Rect rect=new Rect(x1,y1,x2,y2); Paint paint=new Paint(); paint.setColor(transfer); canvas.drawRect(rect, paint); } //控制旋转 private void controllerTransfer() { if(count>MAX){countDown++;SystemClock.sleep(count*5); }else{SystemClock.sleep(count*2); } count++; if(countDown>2){if(lottery==current){countDown=0;count=0;setStartFlags(false);if(listener!=null){ //切换到主线程中运行 post(new Runnable() { @Override public void run() {listener.onWinning(current); } });}} } } public void setStartFlags(boolean flags){ this.flags=flags; } //绘制奖品 private void drawPrize(Canvas canvas) { int width = getMeasuredWidth()/3; int x1=0; int y1=0; int x2=0; int y2=0; int len = (int) Math.sqrt(prizes.size()); for(int x=0;x<len*len;x++){Prize prize = prizes.get(x);int index=x;x1=getPaddingLeft()+width*(Math.abs(index)%len);y1=getPaddingTop()+width*(index/len);x2=x1+width;y2=y1+width;Rect rect=new Rect(x1+width/6,y1+width/6,x2-width/6,y2-width/6);prize.setRect(rect);canvas.drawBitmap(prize.getIcon(), null, rect, null); } } public void start() { setLottery(getRandom()); ExecutorService service = Executors.newCachedThreadPool(); service.execute(new SurfaceRunnable()); } //获取随机中奖数,实际开发中一般中奖号码是服务器告诉我们的 private int getRandom(){ Random r=new Random(); int nextInt =r.nextInt(prizes.size()); if(nextInt%(Math.round(prizes.size()/2))==0){//随机号码等于中间开始位置,需要继续摇随机号return getRandom(); } return nextInt; } //下一步 public int next(int position,int len){ int current=position; if(current+1<len){return ++current; } if((current+1)%len==0&¤t<len*len-1){return current+=len; } if(current%len==0){return current-=len; } if(current<len*len){return --current; } return current; } public LotteryView(Context context, AttributeSet attrs) { super(context, attrs); mHolder = this.getHolder(); mHolder.addCallback(this); } public LotteryView(Context context) { this(context,null); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { Canvas canvas=null; try {canvas = mHolder.lockCanvas();drawBg(canvas);drawPrize(canvas);Prize prize = prizes.get(Math.round(prizes.size()/2));prize.setListener(new Prize.OnClickListener() {@Overridepublic void onClick() { start();}}); } catch (Exception e) {e.printStackTrace(); }finally{if(canvas!=null)mHolder.unlockCanvasAndPost(canvas);} } @Override public void surfaceDestroyed(SurfaceHolder holder) { setStartFlags(false); } /*** 重新测量 */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = Math.min(getMeasuredWidth(), getMeasuredHeight());setMeasuredDimension(width, width);}}以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。