一、SurfaceView认识及的应用的思路

  • SurfaceView继承自(extends)View,View是在UI线程中进行绘制;
  • 而SurfaceView是在一个子线程中对自己进行绘制,优势:避免造成UI线程阻塞;
  • SurfaceView中包含一个专门用于绘制的Surface,Surface中包含一个Canvas;
  • 获得Canvas:可以从SurfaceView中方法的getHolder()获得SurfaceHolder,从holder获得Canvas;
  • holder还管理着SurfaceView的生命周期

surfaceCreated()创建子线程,子线程的run()方法中开启SurfaceView的绘制。

surfaceChanged()

           surfaceDestoryed()中关闭子线程。

二、SurfaceView的一般写法

 package com.example.luckypan;

 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 SurfaceViewTemplate extends SurfaceView implements Callback, Runnable { private SurfaceHolder mHolder;
private Canvas mCanvas;
/**
* 用于绘制线程
*/
private Thread thread;
/**
* 线程的控制开关
*/
private boolean isRunning;
public SurfaceViewTemplate(Context context) {
this(context, null);
}
public SurfaceViewTemplate(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder=getHolder();
mHolder.addCallback(this);
//可获得焦点
setFocusable(true);
setFocusableInTouchMode(true);
//设置常量
setKeepScreenOn(true);
}
public void surfaceCreated(SurfaceHolder holder) {
isRunning=true;
thread=new Thread(this);
thread.start(); }
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub }
public void surfaceDestroyed(SurfaceHolder holder) {
isRunning=false; }
public void run() {
//不断进行绘制
while (isRunning)
{
draw();
}
}
private void draw() {
try {
mCanvas=mHolder.lockCanvas();
if (mCanvas!=null) {
//
}
}
catch (Exception e) { }
finally
{
if (mCanvas!=null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
} }

SurfaceViewTemplate

三、代码编写

  • 绘制抽奖转盘的盘快
  1.         绘制背景:drawBg(), Canvas的两个方法:drawColor(color the color to draw onto the canvas),这里我设置背景色为白色0xFFFFFFFF、drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint),这个bitmap是背景图片,背景是一个矩形new Rect(),其他参数设置为null。
    1.  private void drawBg() {
      mCanvas.drawColor(0xFFFFFFFF);
      mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding/2, mPadding/2, getMeasuredWidth()-mPadding/2, getMeasuredHeight()-mPadding/2), null);
      }

      drawBg

  2. 绘制盘快:
 //绘制盘快
float tmpAngle=mStartAngle;
float sweepAngle=360/mItemCount;
for (int i = 0; i < mItemCount; i++) {
mArcPaint.setColor(mColor[i]);
//绘制盘快
mCanvas.drawArc(mRange, tmpAngle, sweepAngle,true, mArcPaint);
  • 绘制抽奖转盘的奖项文字
 /**
* 绘制每个盘快的文本
* @param tmpAngle
* @param sweepAngle
* @param string
*/
private void drawText(float tmpAngle, float sweepAngle, String string) {
Path path=new Path();
path.addArc(mRange, tmpAngle, sweepAngle);
//利用水平偏移量让文字居中
float textWidth=mTextPaint.measureText(string);
int hOffset=(int) (mRadius*Math.PI/mItemCount/2-textWidth/2);
int vOffset=mRadius/2/6;//垂直偏移量
mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);
}

drawText

  • 绘制抽奖转盘的图片
 /**
* 绘制图片
* @param tmpAngle
* @param bitmap
*/
private void drawIcon(float tmpAngle, Bitmap bitmap) {
//设置图片的宽度为直径的1/8
int imgWidth=mRadius/8;
float angle=(float) ((tmpAngle+360/mItemCount/2)*Math.PI/180);
int x=(int) (mCenter+mRadius/2/2*Math.cos(angle));
int y=(int) (mCenter+mRadius/2/2*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);
}

drawIcon

  • 转盘滚动及设置停止的指向
 private void draw() {
try {
mCanvas=mHolder.lockCanvas();
if (mCanvas!=null) {
//绘制背景
drawBg();
//绘制盘快
float tmpAngle=mStartAngle;
float sweepAngle=360/mItemCount;
for (int i = 0; i < mItemCount; i++) {
mArcPaint.setColor(mColor[i]);
//绘制盘快
mCanvas.drawArc(mRange, tmpAngle, sweepAngle,true, mArcPaint);
//绘制文本
drawText(tmpAngle,sweepAngle,mStrings[i]);
//绘制图片
drawIcon(tmpAngle,mImagBitmaps[i]);
tmpAngle+=sweepAngle;
}
mStartAngle+=mSpeed;
//判断是否点击停止按钮
if (isShouldEnd) {
mSpeed-=1;
}
if (mSpeed<=0)
{
mSpeed=0;
isShouldEnd=false;
}
}
}
catch (Exception e) { }
finally
{
if (mCanvas!=null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}

draw

四、抽奖转盘的秘密

 /**
* 电机启动旋转
* 控制指定盘快停止范围
* @param index
*/
public void luckyStart(int index)
{
//计算每一项的角度
float angle=360/mItemCount;
//计算每一项的中奖范围
//1->150~210
//0->210~270
float from=270-(index+1)*angle;
float end=from+angle;
// 设置停下来需要旋转的距离
float targetFrom=4*360+from;
float targetEnd=4*360+end;
/**
* <pre>
* v1->0 且每次-1
* (v1+0)*(v1+1)/2=targetFrom 等差数列求和公式;
* v1*v1+v1-2*targetFrom=0;
* v1=(-1+Math.sqrt(1+8*targetFrom))/2 一元二次方程求根公式
* </pre>
*/
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);
// mSpeed=v2;
isShouldEnd=false;
}

luckyStart

最新文章

  1. 推荐 10 个超棒的 CSS3 代码生成工具
  2. HTML5 自定义属性 data-* 和 jQuery.data 详解
  3. 金融自助设备WOSA/XFS规范介绍
  4. 如何对Linux的grub进行加密
  5. java理论基础学习三
  6. [css]兼容性
  7. Qt入门-字符串类QString
  8. Centos6.5搭建分布式压力测试工具Tsung的环境搭建
  9. NOIP 2017 Day 0. 游记
  10. php做的一个简易爬虫
  11. Lucene 的索引文件锁原理
  12. 利用BeEF REST API自动化控制僵尸主机
  13. scrapy基本使用
  14. 使用 dep 配置 golang 开发环境
  15. mysql配置修改项
  16. SQL 必知必会&#183;笔记&lt;18&gt;管理事务处理
  17. Java并发编程:ThreadLocal的使用以及实现原理解析
  18. 内核futex的BUG导致程序hang死问题排查
  19. Python字符串符号:双引号/单引号用法注解。
  20. linux下order by 报出ORDER BY clause is not in SELECT list

热门文章

  1. 凯尔卡C68全球版汽车电脑诊断仪
  2. HDU 5597 GTW likes function 打表
  3. [转]O(n)回文子串算法 Manacher算法
  4. DirectSound的应用
  5. 大礼包!ANDROID内存优化(大汇总)
  6. iOS开发——UI篇Swift篇&amp;UIAlertView/UIActionSheet
  7. 0c-33-@class,循环retain
  8. 使用mysqladmin ext 了解MySQL运行状态 转
  9. error C2440:“类型转换&quot;:无法从“void (__thiscall Play1::* )(int *)”转换为“cocos2d::SEL_CallFucN
  10. 使用NuGet加载包,发现加载的dll都是最新版,原来少加了参数[-Version]