转盘抽奖(SurfaceView)

SurfaceView的使用

surfaceView在子线程里绘制图形

一般的创建流程
1.先写构造方法
2.获得SurfaceHolder //getHolder()
3.holder.addcallback(this);
4.实现3个callback的回调方法
4.1 surfaceCreated() //设置线程标示为true,开启线程
4.2 surfacesurfaceChanged()
4.3 surfaceDestroyed()//设置线程标示为false
5.在线程里run()方法里绘制图形( draw() )
6.在draw()方法里获得 Canvas (带有try catch)

代码模板

package com.example.luckyturnplate;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class SurfaceViewTurnplate extends SurfaceView implements Callback, Runnable{

    private SurfaceHolder mHolder;
    private Canvas mCanvas;

    /**
     * 用于绘制的线程
     */
    private Thread t;

    /**
     * 用于控制线程的开关
     */
    private boolean isRunning;

    public SurfaceViewTurnplate(Context context) {
        //调用自身2个参数的构造方法
        this(context, null);
    }

    public SurfaceViewTurnplate(Context context, AttributeSet attrs) {
        super(context, attrs);
        //初始化 
        mHolder = getHolder();
        mHolder.addCallback(this);

        //设置可获得焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        //设置常量
        setKeepScreenOn(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning = true;
        t = new Thread(this);
        t.start();

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false;
    }

    @Override
    public void run() {
        while(isRunning) {
            draw();
        }

    }

    private void draw() {
        //1.为什么判空?
        //当按home或者back键时,surfaceView会销毁,这时候可能进入draw(),所以要判空
        //2.为什么要try catch?
        //同上情况, 这时候可能正在执行线程,通常线程有很多异常抛出,所以try catch包住比较安全
        try {
            mCanvas = mHolder.lockCanvas();
            if (mCanvas!=null) {
                //draw something
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (mCanvas!=null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
            }
        }
}

效果:

这里写图片描述

具体实现

SurfaceViewTurnplate

package com.example.luckyturnplate;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class SurfaceViewTurnplate extends SurfaceView implements Callback, Runnable{

    private SurfaceHolder mHolder;
    private Canvas mCanvas;

    /**
     * 用于绘制的线程
     */
    private Thread t;

    /**
     * 用于控制线程的开关
     */
    private boolean isRunning;

    //画笔
    private Paint mArcPaint,mTextPaint;
    //盘块的文字
    private String[] strs = new String[] {"单反相机","IPAD","IPHONE","谢谢","衣服一套","谢谢"};
    //
    private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
    //盘块的图片
    private int[] imgs = new int[] {R.drawable.danfan,R.drawable.ipad,R.drawable.iphone,R.drawable.f040,R.drawable.meizi,R.drawable.f040};
    private Bitmap[] bitmaps ;
    //盘块的背景颜色
    private int[] colors = new int[] {0xffffc300,0xfff17e01,0xffffc300,0xfff17e01,0xffffc300,0xfff17e01};
    //盘块的数量
    private int itemCount = 6;
    //整个盘块的
    private Rect mRect = new Rect();
    //盘块的半径
    private int mRadius;
    //盘块滚动的速度
    private double mSpeed = 0;
    private volatile float mStartAngle = 0;
    //是否点击停止按钮
    private boolean isShouldEnd;
    //转盘的中心位置
    private int mCenter;
    //padding以padding-left为准
    private int mPadding;
    //背景图
    private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2);


    public SurfaceViewTurnplate(Context context) {
        //调用自身2个参数的构造方法
        this(context, null);
    }

    public SurfaceViewTurnplate(Context context, AttributeSet attrs) {
        super(context, attrs);
        //初始化 
        mHolder = getHolder();
        mHolder.addCallback(this);

        //设置可获得焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        //设置常量
        setKeepScreenOn(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //初始化画笔
        mArcPaint = new Paint();
        mArcPaint.setAntiAlias(true);
        mArcPaint.setDither(true);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setDither(true);
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(mTextSize);

        //初始化盘块绘制的范围
        mRect = new Rect(mPadding, mPadding, mPadding+2*mRadius, mPadding+2*mRadius);

        //实例化bitmap
        bitmaps = new Bitmap[itemCount];
        for (int i=0;i<itemCount;i++) {
            bitmaps[i] = BitmapFactory.decodeResource(getResources(), imgs[i]);
        }



        isRunning = true;
        t = new Thread(this);
        t.start();

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false;
    }

    @Override
    public void run() {
        while(isRunning) {
            long start = System.currentTimeMillis();
            draw();
            long end = System.currentTimeMillis();

            //保持50毫秒绘制一次
            if (end-start<50) {
                try {
                    Thread.sleep(50-(end-start));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private void draw() {
        //1.为什么判空?
        //当按home或者back键时,surfaceView会销毁,这时候可能进入draw(),所以要判空
        //2.为什么要try catch?
        //同上情况, 这时候可能正在执行线程,通常线程有很多异常抛出,所以try catch包住比较安全
        try {
            mCanvas = mHolder.lockCanvas();
            if (mCanvas!=null) {
                //画布抗锯齿
                mCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
                //绘制背景
                drawBg();
                //绘制盘块
                drawPlate();

                mStartAngle += mSpeed;

                //是否点击停止按钮
                if(isShouldEnd) {
                    mSpeed -= 1;
                    if (mSpeed<=0) {
                        mSpeed = 0;
                        isShouldEnd = false;
                    }
                }



            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (mCanvas!=null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
            }
        }

    /**
     * 绘制盘块
     */
    private void drawPlate() {
        float tmpAngle = mStartAngle;
        float sweepAngle = 360/itemCount;

        for (int i =0;i<itemCount;i++) {
            mArcPaint.setColor(colors[i]);
            //绘制圆弧,弧度0是水平线的右边,然后顺时针绘制
            mCanvas.drawArc(new RectF(mRect), tmpAngle, sweepAngle, true, mArcPaint);
            //绘制文本
            drawText(tmpAngle, sweepAngle,i);
            //绘制图片
            drawIcon(tmpAngle,i);
            tmpAngle+=sweepAngle;
        }
    }

    private void drawIcon(float tmpAngle, int i) {
        //图片长, 宽
        int width = mRadius/4;
        float angle = (float) ((tmpAngle+360/itemCount/2) * Math.PI/180);// (* Math.PI/180)是转弧度 
        int x = (int) (mCenter+mRadius/2*Math.cos(angle));
        int y = (int) (mCenter+mRadius/2*Math.sin(angle));
        mCanvas.drawBitmap(bitmaps[i], null, new Rect(x-width/2, y-width/2, x+width/2, y+width/2), null);
    }

    /**
     * 绘制文本
     * @param tmpAngle
     * @param sweepAngle
     * @param i
     */
    private void drawText(float tmpAngle, float sweepAngle, int i) {
        Path path = new Path();
        path.addArc(new RectF(mRect), tmpAngle, sweepAngle);
        float textWidth =  mTextPaint.measureText(strs[i]);
        int hOffset =(int) ((2*mRadius*Math.PI/itemCount/2)-textWidth/2);
        int vOffset = mRadius/6;
        mCanvas.drawTextOnPath(strs[i], path, hOffset, vOffset, mTextPaint);
        //mCanvas.drawTextOnPath(text, path, hOffset, vOffset, paint)
        //hOffset水平偏移量
        //vOffset垂直偏移量
    }

    /**
     * 绘制背景
     */
        private void drawBg() {
            mCanvas.drawColor(Color.WHITE);
            mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding/2, mPadding/2, getMeasuredWidth()-mPadding/2, getMeasuredWidth()-mPadding/2), null);
    }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);

            int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
            setMeasuredDimension(width, width);

            mPadding = getPaddingLeft();
            mRadius = (width-mPadding*2)/2;
            //
            mCenter = width/2;

        }

        public boolean isStart() {
            return mSpeed != 0;
        }

        public void start() {
            mSpeed = 20;
            isShouldEnd = false;
        }

        /**
         * 作弊,index代表停的位置
         */
        public void start(int index) {
            //计算每一项的角度
            float angle = 360 / itemCount;
            //计算每一项中奖范围(当前index)
            //0->210~270
            //1->150~210

            float from = 270 - (index + 1) * angle;
            float end = from + angle;

            //设置停下来需要旋转的距离 
            float targetFrom = 3 * 360 + from;
            float targetEnd = 3 * 360 + end;

            //旋转的距离是一个等差数列的和(mSpeed的和)
            //套用公式可以获得速度
            float v1 = (float) ((-1 +Math.sqrt(1+8*targetFrom)) /2);
            float v2 = (float) ((-1 +Math.sqrt(1+8*targetEnd)) /2);

            mSpeed = v1 + Math.random()*(v2-v1) ;

            isShouldEnd = false;
        }

        public void stop() {
            isShouldEnd = true;
        }

        /**
         * 作弊
         */
        public void stop(String str) {
            mStartAngle = 0;
            isShouldEnd = true;
        }

        public boolean isShouldEnd() {
            // TODO Auto-generated method stub
            return isShouldEnd;
        }


}

xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
   >

   <com.example.luckyturnplate.SurfaceViewTurnplate 
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/sv_turnplater"
       android:layout_centerInParent="true"
       android:padding="30dp"/>

   <ImageView 
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/bt"
       android:src="@drawable/start"
       android:layout_centerInParent="true"/>

</RelativeLayout>

MainActivity

...
surfaceViewTurnplate = (SurfaceViewTurnplate) findViewById(R.id.sv_turnplater);
        button = (ImageView) findViewById(R.id.bt);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (!surfaceViewTurnplate.isStart()) {
//                  surfaceViewTurnplate.start();

                    //指定停在某一地方,index代表奖项位置
                    surfaceViewTurnplate.start(1);
                    button.setImageResource(R.drawable.stop);
                } else {
                    if (!surfaceViewTurnplate.isShouldEnd()) {
//                    surfaceViewTurnplate.stop();

                      //指定停在某一地方, 搭配使用
                      surfaceViewTurnplate.stop("bad");
                      button.setImageResource(R.drawable.start);
                    }
                }

            }
        });
        ...

转载于:http://www.imooc.com/learn/444

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IONIC 功能全演示 ===================== - 使用Ionic提供的UI 组件。Ionic本身是致力于建立统一的移动混合app构建平台,核心基础是Angular+Cordova。 - 通过Angular指令封装,以及预定义的CSS,提供了开箱即用的HTML5 Mobile组件。 - 构建与开发支持,能够直接运行www目录下的index.html进行开发调试。同时也支持发布人员利用gulp构建输出到dist目录 - 利用gulp,同样演示了单元测试以及场景测试。 - [在线演示,内有地址二维码,可手机浏览](http://1.thm1118.sinaapp.com/static/ionic/www/index.html) ## 预览 ![信息卡片](screenshot/card.png) ![下拉刷新](screenshot/pullrefress.png) ![表单元素](screenshot/form.png) ![菜单](screenshot/menu.png) ![列表左滑按钮](screenshot/option.png) ![弹出层](screenshot/pop.png) ![tab](screenshot/tab.png) ![幻灯](screenshot/slide.png) ![图片水平滚动](screenshot/hscroll.png) ![毛玻璃效果](screenshot/blure.png) ![2000条数据搜索](screenshot/search.png) ![输入自动完成](screenshot/autocomplete.png) ![列表自动分组](screenshot/autogroup.png) ![媒体相册](screenshot/galaxy.png) ![chartjs统计图](screenshot/chartjs.png) ![百度统计图](screenshot/echat.png) ![图片延时加载](screenshot/imageload.png) ## 基础环境 纯webapp运行或演示,只需要一个 web server部署即可。 ## 目录结构说明 - www 目录:源码目录 - dist目录:构建输出目录 ## 利于开发,测试和打包部署的nodejs环境 简单开发可以不依赖nodejs环境。但是有了基于nodejs的javascript完整开发周期环境,会极大提升开发效率,保障质量。 - nodejs 最新版。 - 有些node包的安装需要c++编译,x86版本只需要 x86的C++编译器,windows上的x64 c++编译器需要特别设置。 - npm 会很慢,要么使用代理,要么使用国内镜像,比如 [淘宝镜像](http://npm.taobao.org/) , 使用淘宝镜像后,npm命令需要替换成cnpm命令。 - `npm install -g gulp` - `npm install -g ionic` - 如需编译sass的话,安装 [ruby](https://www.ruby-lang.org/zh_cn/),再执行 `gem install sass`(如遇到ssl错误,修改为http源:gem source -a http://rubygems.org/) - `npm install -g node-gyp` - 有的node包依赖python编译,安装 [python2.7](https://www.python.org/) - c++编译环境[MSVStudio 免费版](https://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop).。注意根据studio不同版本指定 --msvs_version=2013 选项 - 安装项目开发依赖包,在项目根目录下运行 `npm install` ### “所见即所得”式开发 - 在项目根目录下运行 `ionic serve`,即可在www目录下开展“所见即所得”的方式开发 - 另外一种方式,在webstorm里对index.html 按debug运行,同样是“所见即所得”的方式开发 ### CROS支持 - 生产环境的 CROS支持要么使用jsonp技术,要么在服务端设置代理。 - 而开发环境下要么 基于不安全做法,服务端api 设置头`Access-Control-Allow-Origin:*" `,要么按如下便捷设置: 基于`ionic serve`, 可以在开发时使用本地代理。ionic.project 内设
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值