幸运大转盘

版权声明:叮叮叮!!!! https://blog.csdn.net/Xuexx_520/article/details/83684917

surfaceview要在子线程中绘制

​
​

public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback,Runnable {
    private SurfaceHolder mHolder;
    private Canvas mCanvas;
    /*
    用于绘制的线程
     */
    private Thread mThread;
    /*
    线程的控制开关
     */
    private boolean isRunning;
    public SurfaceViewTempalte(Context context) {
        this(context,null);
    }

    public SurfaceViewTempalte(Context context, AttributeSet attrs) {
        super(context, attrs);
        mHolder=getHolder();//holder管理surface的生命周期,获得canvas
        mHolder.addCallback(this);//让这个类实现callback
        //可获得焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        //设置常亮
        setKeepScreenOn(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
      isRunning=true;
      mThread=new Thread(this);
      mThread.start();//开启线程
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    isRunning=false;//关闭线程
    }

    @Override
    public void run() {
        //不断进行绘制
      while (isRunning){
          draw();
      }
    }

    private void draw() {
        /*
        当按下Home时候,surface会被销毁,但是可能已经进入这个方法,canvas可能为null,所以判空,
        另一种情况,虽然surface,但是线程不容易销毁,可能会报一些异常。
        当再次回到主界面又会执行surfaceChanged方法
         */
        try {
            mCanvas=mHolder.lockCanvas();//从holder中获取canvas
            if(mCanvas!=null){
                //draw something
            }
        } catch (Exception e){

        }finally {
            mHolder.unlockCanvasAndPost(mCanvas);//绘制结束的时候释放canvas
        }

    }
}

​

​

新建一个类LuckPan,延用SurFaceViewTemplate类的方法,对转盘进行绘制

​
​


public class LuckyPan extends SurfaceView implements SurfaceHolder.Callback,Runnable {
    private SurfaceHolder mHolder;
    private Canvas mCanvas;
    /*
    用于绘制的线程
     */
    private Thread mThread;
    /*
    线程的控制开关
     */
    private boolean isRunning;
 
   //设置文字和图片
    private String[] mTexts=new String[]{"单反相机","ipad","恭喜发财","IPHONE","服装一套","恭喜发财"};
    private int[] mImgs=new int[]{R.mipmap.danfan,
            R.mipmap.ipad,
            R.mipmap.f040,
            R.mipmap.iphone,
            R.mipmap.meizi,
            R.mipmap.f015};
    //与图片对应的bitmap的数组
    private Bitmap [] mBitmaps;
    private Bitmap mBgBitmap=BitmapFactory.decodeResource(getResources(),R.mipmap.bg2);
    //盘块颜色
    private int[] mColors=new int[]{Color.parseColor("#FFC125"),Color.YELLOW,
            Color.parseColor("#FFC125"),Color.YELLOW,
            Color.parseColor("#FFC125"),Color.YELLOW};
    //数量
    private int count=6;

    //绘制盘块的画笔,是弧形
    private Paint mArcPaint;
    //绘制文本的画笔
    private Paint mTextPaint;

    //文字大小,盘块颜色
    private float mTextSize=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
            20,getResources().getDisplayMetrics());


  /*
  2.整个盘块的范围
   */
  private RectF mRange=new RectF();
  /*
  整个盘块的直径
   */
  private int mRadius;
    //转盘的中心位置
    private int mCenter;
    //因为是圆形,所以这里padding为0,直接以paddingleft为准
    private int mPadding;

    //3.滚动的速度
    private double mSpeed=0;
    //绘制的角度,用这个变量声明,保持线程间可见性,因为会使用两个线程去更新他
    private volatile int mStartAngle=0;
    //判断是否点击了停止按钮
    private boolean isShouldEnd;



    public LuckyPan(Context context) {
        this(context,null);
    }

    public LuckyPan(Context context, AttributeSet attrs) {
        super(context, attrs);
        mHolder=getHolder();//holder管理surface的生命周期,获得canvas
        mHolder.addCallback(this);//让这个类实现callback
        //可获得焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        //设置常量
        setKeepScreenOn(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //转盘的边长
        int width=Math.min(getMeasuredWidth(),getMeasuredHeight());
        mPadding=getPaddingLeft();
        //直径
        mRadius=width-mPadding*2;
        //中心点
        mCenter=width/2;
        setMeasuredDimension(width,width);

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning=true;

     //初始化绘制盘块的画笔
        mArcPaint=new Paint();
		//防锯齿
        mArcPaint.setAntiAlias(true);
		//防抖动
        mArcPaint.setDither(true);
        //初始化绘制文本的画笔
        mTextPaint=new Paint();
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(mTextSize);
        //初始化盘块范围
        mRange=new RectF(mPadding,mPadding,mPadding+mRadius,mPadding+mRadius);
        //初始化图片
        mBitmaps =new Bitmap[count];
        for (int i = 0; i < count; i++) {
            mBitmaps[i]=BitmapFactory.decodeResource(getResources(),mImgs[i]);

        }
        new Thread(this).start();

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    isRunning=false;//关闭线程
    }

    @Override
    public void run() {
        //不断进行绘制
      while (isRunning){
          long start=System.currentTimeMillis();

          draw();
          long end=System.currentTimeMillis();
          if(end-start<50){
              try {
                  //如果在50毫秒绘制完成,那么让他休息,一直休息到50毫秒后再继续
                  Thread.sleep(50-(end-start));
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

          }
      }
    }
  //在里面绘制背景,文字,图片
    private void draw() {
        /*
        当按下Home时候,surface会被销毁,但是可能已经进入这个方法,canvas可能为null,所以判空,
        另一种情况,虽然surface,但是削成不容易销毁,可能会报一些异常。
        当再次回到主界面又会执行surfaceChanged方法
         */
        try {
            mCanvas=mHolder.lockCanvas();//从holder中获取canvas
            if(mCanvas!=null){
                //绘制背景
                drawBg();
                //绘制盘块
                float tmpAngle=mStartAngle;//起始角度,绘制时候角度进行改变
                float sweepAngle=360/count;

                for (int i = 0; i <count ; i++) {
                    mArcPaint.setColor(mColors[i]);

                    //绘制盘块,参数:区域,起始角度,每块盘块的角度,要不要使用中心圆点,绘制盘块的画笔
                    mCanvas.drawArc(mRange,tmpAngle,sweepAngle,true,mArcPaint);
                    //绘制文本
                    //文本是弧形,所以用Path
                    drawText(tmpAngle,sweepAngle,mTexts[i]);
                    //绘制图片
                    drawIcon(tmpAngle,mBitmaps[i]);
                    tmpAngle+=sweepAngle;
                    
                }
                mStartAngle+=mSpeed;
                //如果点击了停止按钮
                if(isShouldEnd){
                    mSpeed-=1;
                }
                if(mSpeed<=0){
                    mSpeed=0;
                    isShouldEnd=false;
                }
                //draw something
            }
        } catch (Exception e){

        }finally {
            mHolder.unlockCanvasAndPost(mCanvas);//绘制结束的时候释放canvas
        }

    }
    public void LuckyStart(){
        mSpeed=50;
        isShouldEnd=false;
    }
    public void LuckyEnd(){
        isShouldEnd=true;

    }
    //转盘是否在旋转
    public boolean isStart(){
        return mSpeed!=0;
    }
    //停止按钮是否按下
    public boolean isShouldEnd(){
        return isShouldEnd;
    }
    /*
    绘制Icon
     */
    private void drawIcon(float tmpAngle, Bitmap bitmap) {
        //要知道图片宽高,为直径1/8
        int imgWidth=mRadius/8;
        //图片的角度=每个盘块的角度的一半乘π/180 1度=π/180
        float angle= (float) ((tmpAngle+360/count/2)*Math.PI/180);
        //中心点的位置
        //x坐标
        int x= (int) (mCenter+mRadius/4*Math.cos(angle));
        //y坐标
        int y= (int) (mCenter+mRadius/4*Math.sin(angle));

        //确定图片的位置
        Rect rect=new Rect(x-imgWidth/2,y-imgWidth/2,x+imgWidth/2,y+imgWidth/2);
        mCanvas.drawBitmap(bitmap,null,rect,null);

    }

    /*
    绘制每个盘块的文本
     */
    private void drawText(float tmpAngle, float sweepAngle, String text) {
        //用Path绘制弧形文本
        Path path=new Path();
        path.addArc(mRange,tmpAngle,sweepAngle);
        //水平偏移
        //圆的直径乘π除以数量等于每个盘块的长度/2-文本长度/2
        float textWeith=mTextPaint.measureText(text);
        int hOffset= (int) (mRadius*Math.PI/count/2-textWeith/2);
        //垂直偏移量,半径6分之一
        int vOffset=mRadius/2/6;
        //ho水平偏移,vo垂直偏移
        mCanvas.drawTextOnPath(text,path,hOffset,vOffset,mTextPaint);

    }

    /*
    绘制背景
     */
    private void drawBg() {

     mCanvas.drawColor(Color.WHITE);
     //背景在绘制盘的外面,宽度为padding的2分之一
     mCanvas.drawBitmap(mBgBitmap,null,new Rect(mPadding/2,mPadding/2,
             getMeasuredWidth()-mPadding/2,
             getMeasuredHeight()-mPadding/2),
             null);
    }
}

​

​

在MainActivity里面进行转盘的点击



public class MainActivity extends AppCompatActivity {

    private LuckyPan luck;
    private ImageView start;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //如果转盘不在旋转
                if(!luck.isStart()){
                    luck.LuckyStart();//让他旋转
                    start.setImageResource(R.mipmap.stop);
                } else {//还在旋转
                    //如果停止按钮没有按
                    if(!luck.isShouldEnd()){
                        //点击一下就让他停止
                        luck.LuckyEnd();
                        start.setImageResource(R.mipmap.start);

                    } else {
                        //如果还在旋转,但是停止按钮已经按了,按钮不起作用
                        start.setImageResource(R.mipmap.start);
                    }
                }
            }
        });
    }

    private void initView() {
        luck = (LuckyPan) findViewById(R.id.luck);
        start = (ImageView) findViewById(R.id.start);
    }
}

这样,转盘就完成啦

猜你喜欢

转载自blog.csdn.net/Xuexx_520/article/details/83684917