安卓 转盘功能添加


zhuanpanView.java

/*
 * 说明:
 * 该类自定义了转盘类,可通过给定转盘中各个块的概率,控制指针的指向
 * 创建转盘时,需提供转盘背景图像panpic 和 指针图像panhandpic,二者为宽度相同的正方行
 * 转盘的块数由概率数组p[]限定
 * 
 * 调用:
 * final zhuanpanView zhuanpan = new zhuanpanView(this) ; //创建转盘
 * int p[] = {20, 0, 20, 0, 30, 30};					  //p为转盘所有块的概率数组
 * zhuanpan.startRotate(p);                               //转盘指向对应块,返回值为块位置(从0顺时针计数) 
 * - 若转盘处于旋转状态再次调用,则返回-1.
 */

import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
 
//自定义的转盘View  
public class zhuanpanView extends View implements Runnable
{  
    //界面需要的图片  
    private Bitmap panpic;  
    private Bitmap panhandpic;  
    
    public int width, height;						//转盘的宽度和高度
    
    //旋转矩阵
    private Matrix panRotate=new Matrix();			//可控制盘面的旋转
    private Matrix panhandTrans=new Matrix();  		//可控制指针的旋转
      
    private int degree=0;  							//旋转角度
    private float degreeSpeed=0;					//旋转角度变化增量,控制转盘转速由快到慢
    private int destdegree=360*6+60;				//最终停止角度位置
    private int offDegree = 0;						//角度偏移量,记录转盘指针前一次的位置
      
    public boolean flagRotate=false;				//标志转盘指针当前是否处于旋转状态
    private int centerX, centerY;					//旋转中心位置
    
    public static Random random = new Random();		//随机数对象
    
    
    //创建转盘控件-代码创建时,可调用该函数
    public zhuanpanView(Context context) 
    {
        super(context);
        zhuanpanViewInit(context);  
    }  
    
    //创建转盘控件-XML布局创建控件时,会调用该函数
    public zhuanpanView(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
        zhuanpanViewInit(context);
    } 
    
    //转盘控件自身的初始化
    private void zhuanpanViewInit(Context context)
    {
    	Resources r=context.getResources();
        
        //生成图片  
        panpic=BitmapFactory.decodeStream(r.openRawResource(R.drawable.table));  
        panhandpic=BitmapFactory.decodeStream(r.openRawResource(R.drawable.pointer)); 
        
        //转盘大小自适应屏幕,已480屏幕宽度为基准
        float magnify = getMagnifyParams((Activity)context);
        panpic=resize(panpic, magnify);
        panhandpic=resize(panhandpic, magnify);
        
        width = panhandpic.getWidth();				//设置转盘的宽度
        height = panhandpic.getHeight();
        
        centerX = width/2;							//获取指针旋转的中心位置
        centerY = height/2;
          
        //用线程来刷新界面  
        Thread thread=new Thread(this);
        thread.start();  
    }
    
	//获取与屏幕适配的放大倍数
	private float getMagnifyParams(Activity activity)
	{
		float magnify = 1f;
		
		//获取屏幕的宽度和高度
	    WindowManager wm = activity.getWindowManager();
	    int screenWidth = wm.getDefaultDisplay().getWidth();
	    int screenHeight = wm.getDefaultDisplay().getHeight();

	    int min = screenWidth < screenHeight ? screenWidth : screenHeight;	//取宽高较小的
	    magnify = min/480f;
	    
	    Log.e("转盘自适应:", " ");
	    Log.e("屏幕分辨率", screenWidth+"," + screenHeight);
	    Log.e("转盘放大倍数", magnify+" " );
	    return magnify;
	}
	    
	//将Bitmap放大size倍
	private static Bitmap resize(Bitmap bitmap, float size) 
	{
		Matrix matrix = new Matrix(); 
		matrix.postScale(size, size); //长和宽放大缩小的比例
		
		Bitmap resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
		return resizeBmp;
	 }
      
    //重写View类的onDraw()函数  
    @Override  
    protected void onDraw(Canvas canvas) 
    {  
        canvas.drawBitmap(panpic, panRotate, null); 		//绘制出转盘
          
        panhandTrans.setRotate(degree+offDegree, centerX, centerY);	//转盘指针绕其中心旋转角度degree
        canvas.drawBitmap(panhandpic, panhandTrans, null);	//绘制指针
        
        //控制位置的平移
        //panhandTrans.setTranslate(centerX-panhandpic.getWidth()/2, centerY-panhandpic.getHeight()/5*3);  
    }  
  
    //重写的run函数,用来控制转盘指针的转动,改变旋转的角度
    public void run() 
    {  
        try 
        {
            while(true)
            {  
                if(flagRotate && degree < destdegree)	//控制转盘中的指针旋转到指定角度
                {
                        this.degree += (int)degreeSpeed;  	//当前旋转到的角度
                        
                        //这个函数强制UI线程刷新界面  
                        this.postInvalidate();  
                      
                        Thread.sleep(30); 					//每秒40次绘制
                        
                        degreeAccelerate();					//执行加减速处理
                        
                        if(degree >= destdegree) flagRotate = false;
                }
            }  
              
        } 
        catch (InterruptedException e) 
        {  
            e.printStackTrace();  
        }  
    }  
    
    //控制转盘中指针的旋转加减速
    private void degreeAccelerate()
    {
    	if(degreeSpeed == 0) degreeSpeed = 1;
    	
    	if(degree<230)							//执行加速,大概130度范围加速到最大
    	{
    		if(degreeSpeed <= 20) 
    			degreeSpeed *= 1.19f;
    		else if(degreeSpeed >= 21)
    			degreeSpeed = 20.57f;
    	}
    	else if(destdegree - degree < 720) 		//执行减速
    	{
    		if(degreeSpeed > 1)
    			degreeSpeed *= 0.9752f;
    		else 
    			degreeSpeed = 1;
    	}
    }
    
    //转盘数据重置
    public void reset()
    {
    	offDegree = 0;
    	degree=0;
    	degreeSpeed=0;
    }
    
    //重置当前角度和转速,保存指针角度位置
    private void reset2()
    {
    	offDegree = (degree+offDegree) % 360;		//先保存上次的角度偏移值
    	
    	degree=0;
    	degreeSpeed=0;
    }
    
    //根据概率数组p控制转盘的旋转
    public int startRotate(int p[])
    {  
    	if(flagRotate)							//如果转盘正处于旋转状态
    	{
    		Log.e("转盘选中位置", "-1");
    		return -1;							//-1表示转盘当前不可用
    	}
    	
    	reset2();								//获取转盘指针上次的角度偏移值,重置当前角度
    	
    	int select = set_destdegree(p);			//根据各块的给定概率设置旋转的最终角度和选中块位置
    	Log.e("转盘选中位置", select+"");
    	
        this.flagRotate=true;  					//开始旋转
        return select;							
    }  
    
    /**
     * 按默认概率,控制转盘旋转,
     * 转盘块数 = 概率数组p.length
     * startRotate(p)控制转盘旋转,返回值为转盘指针指向的块号
     */
    public void startRotate1()
    {
    	int p[] = {0, 20, 20, 20, 20, 20, 20, 20};
    	startRotate(p);
    }
    
    //停止指针旋转,可不调用待其自动停止
    public void stopRotate()
    {  
        this.flagRotate=false;  
    }  
    
    //根据各部分的比例值,设置旋转最终停止位置
    public int set_destdegree(int p[])
    {
    	int len = p.length;						//转盘中的总块数
    	random.setSeed(random.nextLong());		//随机设置其随机种子,进一步随机化
    	
    	int countp = 0;							//统计所有块的总概率
    	for(int j= 0; j < len; j++)countp += p[j];
    		
    	int num = random.nextInt(countp) + 1;	//生成1到countp之间的随机数
    	
    	//根据各块的比例值,将num转换为对应的块位置 i
    	int tmp = 0;	//累计前面各块的概率和
    	int i=0;
    	for(; i<len && tmp < num; i++)
    	{
    		tmp += p[i];						//累计概率
    		if(num <= tmp)break;				//num在块p[i]的概率范围内
    	}
    	
    	int partDegree = (int)(360/len);					//计算各块所占的角度大小
    	int partRnddegree = random.nextInt(partDegree-3)+2; //块内角度随机偏移, -3)+2避免指向两块的交界处
    	
    	//块位置转化为块的对应角度
    	destdegree = partDegree * i + 360*6 + partRnddegree;//指向选定块,多转6圈,块内角度随机
    	destdegree -= offDegree;				//目标角度减少初始偏移
    	
    	return i;								//返回指针所指的块位置
    }
}  


添加转盘操作

添加:
=》1.
zhuanpanView.java、
pointer.png、table.png 
到项目



=》2.
NewActivity.java中(待添加转盘的Activity)

添加全局变量:
public zhuanpanView zhuanpan;			//添加转盘
public Handler handler;				//处理转盘的显示与隐藏



NewActivity.onCreate(){}中添加:	——可调整 params.topMargin = 50; 的值修改转盘的垂直位置

handler = new Handler() 
{
    @SuppressLint("HandlerLeak")
	@Override
    public void handleMessage(Message msg) 
    {
        switch (msg.what) 
        {
            case 1:	//显示转盘
            	if(zhuanpan==null)									//没有创建转盘,则创建
            	{
            		zhuanpan = new zhuanpanView(NewActivity.this);	//创建转盘
            		
            		//转盘的布局参数
            		FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(zhuanpan.width, zhuanpan.height);
            	    params.topMargin = 50;							
            		params.gravity = Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL/*Gravity.TOP*/;
            		
            		addContentView(zhuanpan, params);				//添加转盘到Activity
            	}
            	else zhuanpan.setVisibility(View.VISIBLE);			//已有,则显示
            	
            	break;
            case 2:	//隐藏转盘
            	if(zhuanpan!=null)									//转盘存在
            	{
            		zhuanpan.setVisibility(View.INVISIBLE);			//隐藏
            		zhuanpan.reset();								//转盘重置,回到初始状态
            	}
            	
//		        		if(zhuanpan!=null && zhuanpan.getParent()!=null) ((ViewGroup)zhuanpan.getParent()).removeView(zhuanpan);
            	break;
            case 3:	//启动转盘
            	zhuanpan.startRotate1();
            	break;
        }
    }
};



=》3.
抽奖控制处添加:(调用函数进行控制)

/**
 * 向父线程发送消息
 * what = 1, 显示转盘
 * what = 2, 隐藏转盘
 */
private void zhuanpanControl(int what)
{
	Handler handler = NewActivity.instance.handler;	//用于子线程向父线程发送消息
	
	Message msg = new Message();
    msg.what = what;								
    handler.sendMessage(msg);						//通知handler处理事件
};

/**
 * 启动转盘
 * @param p 各转盘块的概率 p = {10, 10, 10, 10, 15, 15, 15, 15}
 * @return  指针所指向的转盘块位置(从0顺时针计数)
 */
private int zhuanpanStart(int[] p)
{
	return NewActivity.instance.zhuanpan.startRotate(p);
}


转盘图片:table.jpg、pointer.ppng
 


下载:

http://download.csdn.net/detail/scimence/8016379




附录:(2015_08_17)

1、 zhuanpanView2.java

package com.linkstudio.popstar.script;

/*
 * 说明:
 * 该类自定义了转盘类,可通过给定转盘中各个块的概率,控制指针的指向
 * 创建转盘时,需提供转盘背景图像panpic 和 指针图像panhandpic,二者为宽度相同的正方行
 * 转盘的块数由概率数组p[]长度限定
 * 
 * 默认设置:初始时,转盘指针指向0度位置,指向第一个块的中心位置(左边缘,设置pointerCenter = false;)
 * 
 * 调用:
 * final zhuanpanView zhuanpan = new zhuanpanView2() ; //创建转盘
 * int p[] = {20, 0, 20, 0, 30, 30};					  //p为转盘所有块的概率数组
 * zhuanpan.startRotate(p);                               //转盘指向对应块,返回值为块位置(从0顺时针计数) 
 * - 若转盘处于旋转状态再次调用,则返回-1.
 */

import java.util.Random;

import android.util.Log;

import com.hlge.lib.base.Component;


// 自定义的转盘View
public class zhuanpanView2 implements Runnable
{
	Component panhand;
	
	private int degree = 0;  						// 旋转角度
	private float degreeSpeed = 0;					// 旋转角度变化增量,控制转盘转速由快到慢
	private int destdegree = 0;						// 最终停止角度位置
	private int offDegree = 0;						// 角度偏移量,记录转盘指针前一次的位置
	
	private float drawOffDegree = 0;				// 绘制偏移角度,指针指向距0度位置的度数,顺时针为正
	
	public boolean flagRotate = false;				// 标志转盘指针当前是否处于旋转状态
	private float centerX, centerY;					// 旋转中心位置
	private int blockNums = 1;						// 转盘中的总块数
	protected float blockDegree = 360;				// 一个转盘块占用的角度
	
	public static Random random = new Random();		// 随机数对象
	public boolean pointerCenter = true;			// 转盘指针是否指向第一块的中心位置,false:指向第一块的起始边缘
	
	// 转盘指针角度的调整
	public void degreeAdjust(float drawOffDegree)
	{
		this.drawOffDegree = drawOffDegree - 0.3f;
		panhand.setRotate(centerX, centerY, -(degree + offDegree + drawOffDegree));
	}
	
	// 设置转盘指针的中心位置
	public void setCenter(float centerX, float centerY)
	{
		this.centerX = centerX;
		this.centerY = centerY;
		panhand.setRotate(centerX, centerY, -(degree + offDegree + drawOffDegree));
	}
	
	// 创建转盘控件-代码创建时,可调用该函数,X/Y为位置调整
	public zhuanpanView2(Component panhand, float X, float Y)
	{
		this.panhand = panhand;
		panhand.setXY((short) (panhand.x + X), (short) (panhand.y + Y));	// 重新调整位置
		
		this.centerX = panhand.width / 2;
		this.centerY = panhand.height / 2;
	}
	
	public boolean isRun = false;
	
	public void start()
	{
		Thread thread = new Thread(this);
		thread.start();
		isRun = true;
	}
	
	public void interrupt()
	{
		isRun = false;
	}
	
	// 重写的run函数,用来控制转盘指针的转动,改变旋转的角度
	public void run()
	{
		try
		{
			// while(isRun && (ScriptLib.luckyform != null || ScriptLib.sevenDayReward_Lucky != null))
			while (isRun)
			{
				if (flagRotate && degree < destdegree)	// 控制转盘中的指针旋转到指定角度
				{
					this.degree += (int) degreeSpeed;  	// 当前旋转到的角度
					update();							// 转盘旋转时,角度变动执行相应逻辑
					
					panhand.setRotate(centerX, centerY, -(degree + offDegree + drawOffDegree));	// 转盘指针绕其中心旋转角度degree
					// panhand.setRotate(-(degree+offDegree+drawOffDegree));
					
					Thread.sleep(25); 					// 每秒25毫秒操作一次
					
					degreeAccelerate();					// 执行加减速处理
					
					if (degree >= destdegree)
					{
						flagRotate = false;
						
						rotateStopDoing();				// 转盘停止转动时,执行逻辑
						interrupt();
					}
				}
			}
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}
	
	/** 更新操作,供子类重写 */
	public void update()
	{}
	
	/** 转盘停止转动时调用,供子类重写 */
	public void rotateStopDoing()
	{}
	
	// 控制转盘中指针的旋转加减速
	private void degreeAccelerate()
	{
		if (degreeSpeed == 0) degreeSpeed = 1;
		
		if (degree < 230)							// 执行加速,大概130度范围加速到最大
		{
			if (degreeSpeed <= 20)
				degreeSpeed *= 1.19f;
			else if (degreeSpeed >= 21) degreeSpeed = 20.57f;
		}
		else if (destdegree - degree < 720) 		// 执行减速
		{
			if (degreeSpeed > 1)
				degreeSpeed *= 0.9752f;
			else
				degreeSpeed = 1;
		}
	}
	
	// 转盘数据重置
	public void reset()
	{
		offDegree = 0;
		degree = 0;
		degreeSpeed = 0;
	}
	
	// 重置当前角度和转速,保存指针角度位置
	private void reset2()
	{
		offDegree = (degree + offDegree) % 360;		// 先保存上次的角度偏移值
		
		degree = 0;
		degreeSpeed = 0;
	}
	
	// 根据概率数组p控制转盘的旋转
	public int startRotate(int p[])
	{
		if (flagRotate)							// 如果转盘正处于旋转状态
		{
			Log.e("转盘选中位置", "-1");
			return -1;							// -1表示转盘当前不可用
		}
		
		reset2();								// 获取转盘指针上次的角度偏移值,重置当前角度
		
		int select = set_destdegree(p);			// 根据各块的给定概率设置旋转的最终角度和选中块位置
		Log.e("转盘选中位置", select + "");
		
		this.flagRotate = true;  				// 开始旋转
		start();
		return select;
	}
	
	/** 按默认概率,控制转盘旋转, 转盘块数 = 概率数组p.length startRotate(p)控制转盘旋转,返回值为转盘指针指向的块号 */
	public void startRotate1()
	{
		int p[] = { 0, 20, 20, 20, 20, 20, 20, 20 };
		startRotate(p);
	}
	
	// 停止指针旋转,可不调用待其自动停止
	public void stopRotate()
	{
		this.flagRotate = false;
	}
	
	/**
	 * 获取转盘指针实时角度值,相对于第0块起始边角度位置
	 */
	public int curDegree()
	{
		float half = (pointerCenter ? (int)(blockDegree / 2) : 0);
		return (int)(degree + half + offDegree);
	}
	
	/**
	 * 指针角度为degree时,所指的块位置
	 */
	public int blockIndex(float degree)
	{
		return (int) (degree % 360 / blockDegree);
	}
	
	/**
	 * 指针角度为degree时,所指的块位置(限定块角度大小partDegree)
	 */
	public int blockIndex(float degree, float partDegree)
	{
		return (int) (degree % 360 / partDegree);
	}
	
	// 根据各部分的比例值,设置旋转最终停止位置
	public int set_destdegree(int p[])
	{
		blockNums = p.length;								// 转盘中的总块数
		random.setSeed(random.nextLong());					// 随机设置其随机种子,进一步随机化
		
		int countp = 0;										// 统计所有块的总概率
		for (int j = 0; j < blockNums; j++)
			countp += p[j];
		
		int num = random.nextInt(countp) + 1;				// 生成1到countp之间的随机数
		
		// 根据各块的比例值,将num转换为对应的块位置 i
		int tmp = 0;	// 累计前面各块的概率和
		int i = 0;
		for (; i < blockNums && tmp < num; i++)
		{
			tmp += p[i];						// 累计概率
			if (num <= tmp) break;				// num在块p[i]的概率范围内
		}
		
		blockDegree = 360 / blockNums;			// 计算各块所占的角度大小
		int partRnddegree = random.nextInt((int)blockDegree - 9) + 5; 	// 块内角度随机偏移, -9)+5避免指向两块的交界处
		
		// 块位置转化为块的对应角度
		destdegree = (int)(blockDegree * i) + 360 * 6 + partRnddegree;	// 指向选定块,多转6圈,块内角度随机
		if (pointerCenter) destdegree -= (int)(blockDegree / 2);		// 相对于转盘背景少转动半个块内角
			
		destdegree -= offDegree;				// 目标角度减少初始偏移
		
		return i;								// 返回指针所指的块位置
	}
}


2、zhuanpanView.java

/**
 * 2015-8-11上午10:18:58
 * wangzhongyuan
 */
package com.linkstudio.popstar.script;

import android.util.Log;

import com.hlge.lib.base.Component;
import com.hlge.lib.tool.SoundManager;

/**
 * zhuanpanView 继承自转盘基础类zhuanpanView2,新增转盘指示灯、即时音效
 * -----
 * 2015-8-11 上午10:18:58 
 * wangzhongyuan
 */
public class zhuanpanView extends zhuanpanView2
{
	private float nextDegree = 0;				// 下一处更新操作,角度位置
	zhuanpanLights16 tex;
	private boolean thisFormDebug = true;
	
	public zhuanpanView(Component panhand, float X, float Y, zhuanpanLights16 tex)
	{
		super(panhand, X, Y);
		this.tex = tex;
	}
	
	/** 转盘指针指向各个块时,的更新操作 */
	public void update()
	{
		int degree = curDegree();
		if (degree > nextDegree)
		{
			int index = blockIndex(degree, blockDegree / 2);	// (blockDegree/2)块大小的块索引
			
			if (index % 2 == 1) SoundManager.playSound("zhuandong.mp3", false);
			updateProcess(index);					// 显示指针所指块索引对应内容
			
			nextDegree += blockDegree / 2;			// 间隔一定角度值,执行更新操作
		}
	}
	
	String info = "";
	
	// 更新转盘显示信息
	private void updateProcess(int curBlock)
	{
		if (thisFormDebug) info += curBlock + ", " + nextDegree + "; ";
		tex.index = curBlock;
	}
	
	/** 转盘停止转动时调用 */
	public void rotateStopDoing()
	{
		selectMessage();									//转盘停止转动调用逻辑
		SoundManager.playSound("zhuandong_js.mp3", false);	//播放转盘停止转动音效
		tex.index = -1;										//转盘重置,不绘制灯
		
		if (thisFormDebug)
		{
			Log.e("转盘指针所指块变动:", info);
			info = "";
		}
		
		nextDegree %= 360;
	}
	
	/**
	 * 转盘停止转动时调用,选中块处理逻辑,供子类调用
	 */
	public void selectMessage() {}
}

3、zhuanpanLights16.java

/**
 * 2015-8-11上午10:19:17
 * wangzhongyuan
 */
package com.linkstudio.popstar.script;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.hlge.lib.base.HlgeTexture;
import com.hlge.lib.base.SpineTexture;

/**
 * Lights16 转盘指示灯
 * -----
 * 2015-8-11 上午10:19:17  
 * wangzhongyuan
 */
public class zhuanpanLights16  extends HlgeTexture
{
	SpineTexture[] lights;
	public int index = -1, preIndex = -1;
	
	/** 创建Texture */
	public zhuanpanLights16()
	{
		super();
		
		lights = new SpineTexture[16];
		for (int i = 0; i < 16; i++)
			lights[i] = new SpineTexture("7", (14 + i) + "", true);
	}
	
	/** SpineTexture的绘制 */
	public void paint(SpriteBatch g)
	{
		paint(g, x, -y);
	}
	
	/** SpineTexture的绘制 */
	public void paint(SpriteBatch g, float x, float y)
	{
		if (index >= lights.length) index = 0;
		if (index >= 0 && lights[index] != null)
		{
			g.setColor(color.toIntBits());		// 设置透明度
			
			if (parent != null)
			{
				x += parent.width / 2;
				y += parent.height / 2;
			}
			
//			if (index != preIndex)
//			{
//				preIndex = index;
//				if (lights[index].isPlayOver()) lights[index].rePlay(); // lights[index].spine.setAction(spine.actionId, false); //
//			}
			
			lights[index].paint(g, x, y);
		}
	}
	
	@Override
	public void dispose()
	{
		for (int i = 0; i < lights.length; i++)
			if (lights[i] != null) lights[i].dispose();
		lights = null;
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值