思路: 在开始绘制九宫格之前,我们先重写onMeasure方法,主要是为了让九宫格成为一个正方形,
SurfaceView一般不是通过重写onDraw方法来绘制控件的,那么怎么获取到Canvas呢?主要是通过SurfaceHolder监听Callback事件来获取的 ,有了对象SurfaceHolder对象,我们就可以获取到Canvas对象了,下面开始真正的绘制工作。
步骤:
1.计算各位方块的位置
2.绘制每个奖品的方块(主要让界面更加好看)
3.绘制奖品图
4.计算旋转方块的下一步位置
5.绘制旋转方块
6.监听点击开始按钮事件
主要核心技术:
SurfaceView,SurfaceHolder
OK,有了基本步骤,接下来就是根据步骤一步一步来进行了。 代码如下
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.myapplication.MainActivity">
<com.example.myapplication.LotteryView
android:id="@+id/nl"
android:layout_width="368dp"
android:layout_height="495dp"
tools:layout_editor_absoluteY="8dp"
tools:layout_editor_absoluteX="8dp" />
android.support.constraint.ConstraintLayout>
package com.example.myapplication;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LotteryView nl;
setContentView(R.layout.activity_main);
nl = (LotteryView) findViewById(R.id.nl);
int[] prizesIcon = {R.drawable.navicon_a, R.drawable.navicon_b, R.drawable.navicon_c, R.drawable.navicon_d,
R.drawable.navicon_e, R.drawable.navicon_a, R.drawable.navicon_d, R.drawable.navicon_b, R.drawable.navicon_e};
final List prizes = new ArrayList();
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 LotteryView.OnTransferWinningListener() {
@Override
public void onWinning(int position) {
Toast.makeText(getApplicationContext(), prizes.get(position).getName(), Toast.LENGTH_SHORT).show();
}
});
}
}
package com.example.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
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;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class LotteryView extends SurfaceView implements Callback{
/**
* holder
*/
private SurfaceHolder mHolder;
private Listprizes;
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(Listprizes){
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,getMeasuredWidth())){
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;xint 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;xint 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 current,int len){
if(current+1return ++current;
}
if((current+1)%len==0¤t1){
return current+=len;
}
if(current%len==0){
return current-=len;
}
if(currentreturn --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() {
@Override
public void click() {
start();
}
});
} catch (Exception e) {
e.printStackTrace();
}finally{
if(canvas!=null)
mHolder.unlockCanvasAndPost(canvas);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
setStartFlags(false);
}
/**
* 重新测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(width, width);
}
}
package com.example.myapplication;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
/**
* Created by Cr on 2017/9/18.
* 奖品的属性
*/
class Prize {
int Id;
String Name;
Bitmap Icon;
int BgColor;
Rect rect;
public OnClickListener getListener() {
return listener;
}
public void setListener(OnClickListener listener) {
this.listener = listener;
}
OnClickListener listener;
public Rect getRect() {
return rect;
}
public void setRect(Rect rect) {
this.rect = rect;
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public Bitmap getIcon() {
return Icon;
}
public void setIcon(Bitmap icon) {
Icon = icon;
}
public int getBgColor() {
return BgColor;
}
public void setBgColor(int bgColor) {
BgColor = bgColor;
}
public interface OnClickListener{
void click();
}
public void click(){
listener.click();
}
public boolean isClick (Point touchPoint,int width){
if (touchPoint.x < width/3*2&touchPoint.x > width/3&touchPoint.y < width/3*2&touchPoint.y > width/3){
return true;
}else{
return false;
}
}
}