Android 美食大转盘详解流程_第1页
Android 美食大转盘详解流程_第2页
Android 美食大转盘详解流程_第3页
Android 美食大转盘详解流程_第4页
Android 美食大转盘详解流程_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第Android美食大转盘详解流程你还在为明天吃什么而烦恼嘛

美食大赏帮你解决选择困难症

帮你做出最佳的选择

做吃货,我们是认真的

美食大转盘

本示例使用SurfaceView绘制而成,接下来逐步分析,

文末会贴出全部代码``文末会贴出全部代码``文末会贴出全部代码

初始化SurfaceView

privatevoidinit(){

mSurfaceHolder=this.getHolder();

//管理SurfaceView的生命周期

mSurfaceHolder.addCallback(this);

this.setFocusable(true);

this.setFocusableInTouchMode(true);

this.setKeepScreenOn(true);

通过获取高、宽,然后减去mPadding的长度获取到控件中心点,然后存储测量的宽、高

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

intwidth=Math.min(getMeasuredWidth(),getMeasuredHeight());

mPadding=getPaddingLeft();

mRadius=width-mPadding*2;

//中心点

mCenter=width/2;

setMeasuredDimension(width,width);

绘制圆盘背景

设置背景图片

privateBitmapmBgBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.turntable_bgcolor);

绘制背景突出部分

privatevoiddrawBgColor(){

mCanvas.drawColor(0xFFFFFFFF);

mCanvas.drawBitmap(mBgBitmap,null,newRect(mPadding/2,mPadding/2,getMeasuredWidth()-mPadding/2,getMeasuredWidth()-mPadding/2),null);

privatevoiddrawArea(){

//起始角度

floattempAngle=mStartAngle;

//每个盘块绘制的角度

floatsweepAngele=360/mItemCount;

for(inti=0;imItemCount;i++){

mArcPaint.setColor(itemColors[i]);

//绘制盘块

mCanvas.drawArc(mRange,tempAngle,sweepAngele,true,mArcPaint);

//绘制文本

drawText(tempAngle,sweepAngele,itemCharString[i]);

//绘制图标

drawIcon(tempAngle,mBitmaps[i]);

tempAngle+=sweepAngele;

mStartAngle+=mSpeed;

//如果需要停止,让转速逐渐变小直到0

if(isShouldEnd){

mSpeed-=mDifferSpeed;

if(mSpeed=0){

mSpeed=0;

isShouldEnd=false;

绘制盘块内文字

privatevoiddrawText(floattempAngle,floatsweepAngele,StringitemTextStr){

Pathpath=newPath();

path.addArc(mRange,tempAngle,sweepAngele);

//利用水平偏移量让文字居中

floattextWidth=mTextPaint.measureText(itemTextStr);

inthOffset=(int)(mRadius*Math.PI/mItemCount/2-textWidth/2);

//利用垂直偏移量让文字向圆心靠拢

intvOffset=mRadius/2/6;

mCanvas.drawTextOnPath(itemTextStr,path,hOffset,vOffset,mTextPaint);

绘制盘块内图标

privatevoiddrawIcon(floattempAngle,Bitmapbitmap){

//约束图片的宽度,为直径的1/8,可以作为可变参数设置

intimgWidth=mRadius/8;

//获取弧度值

floatangle=(float)((tempAngle+360/mItemCount/2)*Math.PI/180);

//约定图片位置在直径1/4处

intx=(int)(mCenter+mRadius/4*Math.cos(angle));

inty=(int)(mCenter+mRadius/4*Math.sin(angle));

//确定图片位置

Rectrect=newRect(x-imgWidth/2,y-imgWidth/2,x+imgWidth/2,y+imgWidth/2);

mCanvas.drawBitmap(bitmap,null,rect,null);

开始旋转转盘

publicvoidStart(intindex){

if(isStart()){

return;

if(index0){

mSpeed=50*(1+Math.random()*(0.5));

isShouldEnd=false;

return;

停止旋转转盘

publicvoidStop(){

if(isShouldEnd()){

return;

//将初始角度重置

mStartAngle=0;

isShouldEnd=true;

自定义转盘等份

因为我们要根据需要制作不同等份的转盘,需要跟用户产生交互,所有需要暴露一个方法供用户选择

publicvoidInitNumber(intnumber){

if(number=0){

return;

*确保为偶数*/

if(number%2==0){

InitArea(number);

本示例以4,6,8等份为例

privatevoidInitArea(intnumber){

switch(number){

case4:

fourParts();

break;

case6:

sixParts();

break;

case8:

eightParts();

break;

default:

sixParts();

每一次选择转盘等份,都需要对View进行重绘,需要多次改变图片数量,所以我们将图片设置成一个公共的方法,避免内存浪费

privatevoidfourParts(){

mItemCount=4;

itemCharString=newString[]{粉条,面条,米饭,粥,};

itemImages=newint[]{R.drawable.fen,R.drawable.mian,R.drawable.rice,R.drawable.tang};

itemColors=newint[]{0xffffc300,0xfff17e01,0xffffc300,0xfff17e01};

InitImage(mItemCount,itemImages);

privatevoidInitImage(intcount,int[]item){

mBitmaps=newBitmap[mItemCount];

for(inti=0;icount;i++){

mBitmaps[i]=BitmapFactory.decodeResource(getResources(),item[i]);

布局引用

XML布局文件内引用如下,其中中间的指针为图片类型

com.franzliszt.foodturntable.Turntable

android:id=@+id/TurnTable

android:layout_width=match_parent

android:layout_height=match_parent

android:padding=20dp

android:layout_margin=10dp

android:layout_centerInParent=true/

ImageView

android:id=@+id/StartAndEnd

android:layout_width=100dp

android:layout_height=100dp

android:layout_centerInParent=true

android:src=@drawable/start

android:quot;Start/

Activity引用

默认设置8等份,如果自定义多种等份,默认必须为最大的等份,不然会出现区域空白

turntable.InitNumber(8);

图标切换

对开始与暂停图标进行切换,根据点击次数进行切换

publicvoidStart(Viewview){

count++;

/*暂停*/

if(count%2==0){

turntable.Stop();

StartIcon();

}else{

/*开始*/

turntable.Start(-1);

StopIcon();

更换转盘等份

首先提供三个RadioButton供用户选择,然后通过SharedPreferences进行存储数据,有关SharedPreferences封装的知识,请移步到另一篇博文AndroidSharedPreferences存取操作以及封装详解

privatevoidSelectNumber(){

RG.setOnCheckedChangeListener(newRadioGroup.OnCheckedChangeListener(){

@Override

publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){

switch(checkedId){

caseR.id.fourParts:

sp.PutData(context,num,4);

break;

caseR.id.sixParts:

sp.PutData(context,num,6);

break;

caseR.id.eightParts:

sp.PutData(context,num,8);

break;

});

然后取出数据,并回调等份数值即可

publicvoidConfirm(Viewview){

RevealAnim(view);

loadingView.setVisibility(View.VISIBLE);

startLoading();

startPercentMockThread();

intnum=(int)sp.GetData(context,num,0);

turntable.InitNumber(num);

沉浸式体验

沉浸式体验即标题栏与系统状态栏主题一致我们分为以下几个步骤完成以上效果

建立一个样式

首先我们需要建立一个标题栏为空的样式,我们有两种方式去实现

第一种,使用系统提供样式

stylename=NotActionBar_1parent=Theme.AppCompat.Light.NoActionBar

itemname=colorPrimary@color/colorPrimary/item

itemname=colorPrimaryDark@color/colorPrimaryDark/item

itemname=colorAccent@color/colorAccent/item

/style

第二种,直接使用标志进行设置

其实第一种的源码就是第二种,(废话文学)

stylename=NotActionBarparent=Theme.AppCompat.Light.DarkActionBar

!--Customizeyourthemehere.--

itemname=windowNoTitletrue/item

itemname=windowActionBarfalse/item

/style

引用空标题栏样式

我们需要在我们要隐藏标题栏的Activity中引用如下代码android:theme=@style/NotActionBar

配置图如下,地址:清单文件中进行配置

自定义标题栏

我们隐藏了标题栏之后,我们需要自定义一个自己喜欢的风格的标题栏

推荐使用ToolBar,本示例为了简单,就直接使用了TextView,代码如下

LinearLayout

android:layout_width=match_parent

android:layout_height=80dp

android:orientation=horizontal

android:background=#cc00cc

android:gravity=center

android:paddingTop=20dp

TextView

android:layout_width=wrap_content

android:layout_height=wrap_content

android:text=吃货大赏

android:textColor=#ffffff

android:textSize=17sp

android:padding=10dp

/LinearLayout

合二为一

终于到了最后一步,我们需要在设置Activity对系统栏进行设置

首先需要对版本进行一个判定,防止版本不兼容

其次获取DecorView实例

然后使用标志符对系统状态进行设置,其中以下两个系统标志符为全屏和隐藏系统状态栏

重中之重,以下代码必须在setContentView(R.layout.activity_main);之前执行

重中之重,以下代码必须在setContentView(R.layout.activity_main);之前执行

重中之重,以下代码必须在setContentView(R.layout.activity_main);之前执行

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和View.SYSTEM_UI_FLAG_LAYOUT_STABLE

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

if(Build.VERSION.SDK_INT=21){

ViewdecorView=getWindow().getDecorView();

decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

getWindow().setStatusBarColor(Color.TRANSPARENT);

setContentView(R.layout.activity_main);

InitView();

SelectNumber();

RevealAnimator

建立一个圆形样式

首先我们需要建立一个圆形样式,在res-drawable下建立一个oval.xml文件

代码如下:

shapexmlns:android=/apk/res/androidandroid:shape=oval

solidandroid:color=#cc00cc/

/shape

动画设置

在XML文件中配置我们建立的圆形样式

android:background=@drawable/oval

然后再Activity中进行动画设置,其中createCircularReveal()方法的五个参数分别为:控件,动画开始的中心的X,动画开始的中心的Y,动画开始的半径,动画结束的半径

privatevoidRevealAnim(Viewview){

Animatoranimator=ViewAnimationUtils.createCircularReveal(

view,view.getWidth()/2,view.getHeight()/2,view.getWidth(),0

animator.setInterpolator(newAccelerateDecelerateInterpolator());

animator.setDuration(2000);

animator.start();

自定义转盘代码

publicclassTurntableextendsSurfaceViewimplementsSurfaceHolder.Callback,Runnable{

privateSurfaceHoldermSurfaceHolder;

privateCanvasmCanvas;

*用于SurfaceView绘制的子线程

privateThreadmThread;

*控制子线程开关

privatebooleanisRunning;

*字样*/

privateString[]itemCharString;

*图片*/

privateint[]itemImages;

privateBitmap[]mBitmaps;

*背景

privateBitmapmBgBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.turntable_bgcolor);

*色块*/

privateint[]itemColors;

*默认等份*/

privateintmItemCount=8;

*整个盘块的范围

privateRectFmRange=newRectF();

*整个盘块的直径

privateintmRadius;

*绘制盘块的画笔

privatePaintmArcPaint;

*绘制文本的画笔

privatePaintmTextPaint;

*字体大小*/

privatefloatmTextSize=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,20,getResources().getDisplayMetrics());

*盘块滚动的速度

privatedoublemSpeed=0;

*转盘的中心位置

privateintmCenter;

*这里我们的padding直接取paddingLeft

privateintmPadding;

*volatile保证线程间的可见性

privatevolatilefloatmStartAngle=0;

*判断是否点击了停止按钮

privatebooleanisShouldEnd=false;

*设置单次绘制最低时间,如果在该时间内绘制完成,让子线程sleep到改时间结束

*这样防止了线程绘制频繁,先消耗性能的问题

privatelongmOneTimeMinMillionSeconds=50;

privateintmDifferSpeed=1;//调用停止后递减的速度差值要大于0

publicTurntable(Contextcontext){

super(context);

init();

publicTurntable(Contextcontext,AttributeSetattrs){

super(context,attrs);

init();

publicTurntable(Contextcontext,AttributeSetattrs,intdefStyleAttr){

super(context,attrs,defStyleAttr);

init();

publicvoidInitNumber(intnumber){

if(number=0){

return;

*确保为偶数*/

if(number%2==0){

InitArea(number);

privatevoidInitArea(intnumber){

switch(number){

case4:

fourParts();

break;

case6:

sixParts();

break;

case8:

eightParts();

break;

default:

sixParts();

privatevoidfourParts(){

mItemCount=4;

itemCharString=newString[]{粉条,面条,米饭,粥,};

itemImages=newint[]{R.drawable.fen,R.drawable.mian,R.drawable.rice,R.drawable.tang};

itemColors=newint[]{0xffffc300,0xfff17e01,0xffffc300,0xfff17e01};

InitImage(mItemCount,itemImages);

privatevoidsixParts(){

mItemCount=6;

itemCharString=newString[]{火锅,汉堡,巧克力,奶茶,蛋糕,炸鸡

itemImages=newint[]{R.drawable.huoguo,R.drawable.hanbao,R.drawable.qiaokeli,R.drawable.naicha,R.drawable.dangao,R.drawable.zhaji1};

itemColors=newint[]{0xffffc300,0xfff17e01,0xffffc300,0xfff17e01,0xffffc300,0xfff17e01};

InitImage(mItemCount,itemImages);

privatevoideightParts(){

mItemCount=8;

itemCharString=newString[]{苹果,香蕉,榴莲,西瓜,葡萄,火龙果,芒果,草莓

itemImages=newint[]{R.drawable.apple,R.drawable.xaingjiao,R.drawable.liulian,R.drawable.xigua,R.drawable.putao,R.drawable.huolongguo,R.drawable.mangguo,R.drawable.caomei};

itemColors=newint[]{0xffffc300,0xfff17e01,0xffffc300,0xfff17e01,0xffffc300,0xfff17e01,0xffffc300,0xfff17e01};

InitImage(mItemCount,itemImages);

privatevoidinit(){

mSurfaceHolder=this.getHolder();

//管理SurfaceView的生命周期

mSurfaceHolder.addCallback(this);

//能够获取焦点

this.setFocusable(true);

this.setFocusableInTouchMode(true);

//保持常亮

this.setKeepScreenOn(true);

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

intwidth=Math.min(getMeasuredWidth(),getMeasuredHeight());

mPadding=getPaddingLeft();

mRadius=width-mPadding*2;

//中心点

mCenter=width/2;

setMeasuredDimension(width,width);

privatevoidInitImage(intcount,int[]item){

mBitmaps=newBitmap[mItemCount];

for(inti=0;icount;i++){

mBitmaps[i]=BitmapFactory.decodeResource(getResources(),item[i]);

@Override

publicvoidsurfaceCreated(SurfaceHoldersurfaceHolder){

//初始化盘块画笔

mArcPaint=newPaint();

mArcPaint.setAntiAlias(true);

mArcPaint.setDither(true);

//初始化文字画笔

mTextPaint=newPaint();

mTextPaint.setColor(0xffffffff);

mTextPaint.setTextSize(mTextSize);

//初始化盘块绘制范围

mRange=newRectF(mPadding,mPadding,mPadding+mRadius,mPadding+mRadius);

//初始化图片

InitImage(mItemCount,itemImages);

isRunning=true;

mThread=newThread(this);

mThread.start();

@Override

publicvoidsurfaceChanged(SurfaceHoldersurfaceHolder,inti,inti1,inti2){

@Override

publicvoidsurfaceDestroyed(SurfaceHoldersurfaceHolder){

isRunning=false;

@Override

publicvoidrun(){

*不断的进行绘制

while(isRunning){

longpreMillions=System.currentTimeMillis();

draw();

longafterMillions=System.currentTimeMillis();

longdrawOnceTime=afterMillions-preMillions;

if(drawOnceTimemOneTimeMinMillionSeconds){

try{

Thread.sleep(mOneTimeMinMillionSeconds-drawOnceTime);

}catch(InterruptedExceptione){

e.printStackTrace();

privatevoiddraw(){

try{

mCanvas=mSurfaceHolder.lockCanvas();

if(mCanvas!=null){

/*绘制背景颜色*/

drawBgColor();

/*绘制区域*/

drawArea();

}catch(Exceptione){

e.printStackTrace();

}finally{

if(mCanvas!=null){

mSurfaceHolder.unlockCanvasAndPost(mCanvas);

*绘制盘块

privatevoiddrawArea(){

//起始角度

floattempAngle=mStartAngle;

//每个盘块绘制的角度

floatsweepAngele=360/mItemCount;

for(inti=0;imItemCount;i++){

mArcPaint.setColor(itemColors[i]);

//绘制盘块

mCanvas.drawArc(mRange,tempAngle,sweepAngele,true,mArcPaint);

//绘制文本

drawText(tempAngle,sweepAngele,itemCharString[i]);

//绘制图标

drawIcon(tempAngle,mBitmaps[i]);

tempAngle+=sweepAngele;

mStartAngle+=mSpeed;

//如果需要停止,让转速逐渐变小直到0

if(isShouldEnd){

mSpeed-=mDifferSpeed;

if(mSpeed=0){

mSpeed=0;

isShouldEnd=false;

*绘制每个盘块的图标

*@paramtempAngle

*@parambitmap

privatevoiddrawIcon(floattempAngle,Bitmapbitmap){

//约束图片的宽度,为直径的1/8,可以作为可变参数设置

intimgWidth=mRadius/8;

//获取弧度值

floatangle=(float)((tempAngle+360/mItemCount/2)*Math.PI/180);

//约定图片位置在直径1/4处

intx=(int)(mCenter+mRadius/4*Math.cos(angle));

inty=(int)(mCenter+mRadius/4*Math.sin(angle));

//确定图片位置

Rectrect=newRect(x-imgWidth/2,y-imgWidth/2,x+imgWidth/2,y+imgWidth/2);

mCanvas.drawBitmap(bitmap,null,rect,null);

*绘制每个盘块的文本

*@paramtempAngle

*@paramsweepAngele

*@paramitemTextStr

privatevoiddrawText(floattempAngle,floatsweepAngele,StringitemTextStr){

Pathpath=newPath();

path.addArc(mRange,tempAngle,sweepAngele);

//利用水平偏移量让文字居中

floattextWidth=mTextPaint.measureText(itemTextStr);

inthOffset=(int)(mRadius*Math.PI/mItemCount/2-textWidth/2);

//利用垂直偏移量让文字向圆心靠拢

intvOffset=mRadius/2/6;

mCanvas.drawTextOnPath(itemTextStr,path,hOffset,vOffset,mTextPaint);

*绘制背景

privatevoiddrawBgColor(){

mCanvas.drawColor(0xFFFFFFFF);

mCanvas.drawBitmap(mBgBitmap,null,newRect(mPadding/2,mPadding/2,getMeasuredWidth()-mPadding/2,getMeasuredWidth()-mPadding/2),null);

*启动转盘

*能够控制到具体某个index范围内停止

publicvoidStart(intindex){

if(isStart()){

return;

if(index0){

mSpeed=50*(1+Math.random()*(0.5));

isShouldEnd=false;

return;

*停止转盘

publicvoidStop(){

if(isShouldEnd()){

return;

//将初始角度重置

mStartAngle=0;

isShouldEnd=true;

*转盘是否在旋转

*@return

publicbooleanisStart(){

returnmSpeed!=0;

*是否停止状态(但可能处于旋转减速到停止)

*@return

publicbooleanisShouldEnd(){

returnisShouldEnd;

XML布局代码

RelativeLayout

xmlns:android=/apk/res/android

xmlns:app=/apk/res-auto

xmlns:tools=/tools

android:layout_width=match_parent

android:layout_height=match_parent

android:background=#ffffff

LinearLayout

android:layout_width=match_parent

android:layout_height=80dp

android:orientation=horizontal

android:background=#cc00cc

android:gravity=center

android:paddingTop=20dp

TextView

android:layout_width=wrap_content

android:layout_height=wrap_content

android:text=吃货大赏

android:textColor=#ffffff

android:textSize=17sp

android:padding=10dp

/LinearLayout

com.franzliszt.foodturntable.Turntable

android:id=@+id/TurnTable

android:layout_width=match_parent

android:layout_height=match_parent

android:padding=20dp

android:layout_margin=10dp

android:layout_centerInParent=true/

ImageView

android:id=@+id/StartAndEnd

android:layout_width=100dp

android:layout_height=100dp

android:layout_centerInParent=true

android:src=@drawable/start

android:quot;Start/

com.franzliszt.foodturntable.AnimatedCircleLoadingView

android:id=@+id/loadingView

android:layout_width=match_parent

android:layout_height=match_parent

android:background=#000000

android:alpha=0.9

android:layout_centerInParent=true

app:animCircleLoadingView_mainColor=#cc00cc

app:animCircleLoadingView_secondaryColor=#ff0000

app:animCircleLoadingView_textColor=@android:color/white

android:visibility=gone

LinearLayout

android:layout_width=match_parent

android:layout_height=wrap_content

android:layout_below=@+id/TurnTable

android:orientation=vertical

android:layout_marginTop=20dp

RadioGroup

android:id=@+id/RG

android:layout_width=match_parent

android:layout_height=wrap_content

android:orientation=horizontal

android:layout_gravity=center

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论