




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025版房地产项目场地租赁合同补充协议范本
- ct个人实习总结
- 二零二五年度电影院地毯采购合同
- 二零二五年三人共同开设美发店服务合同范本
- 二零二五年度铲车租赁及租赁期限调整协议
- 二零二五年度住宅小区屋顶绿化与设备安装合同
- 二零二五年度农产品采购合同及销售合同
- 二零二五年度彩钢车库门安装服务合同
- 二零二五年度专业食堂承包管理合作协议
- 二零二五年度智能安防设备维护保养服务合同
- GB/T 9576-2013橡胶和塑料软管及软管组合件选择、贮存、使用和维护指南
- GA/T 1323-2016基于荧光聚合物传感技术的痕量炸药探测仪通用技术要求
- 2023年苏州国发创业投资控股有限公司招聘笔试题库及答案解析
- 高中历史《第一次工业革命》说课课件
- 学生集体外出活动备案表
- SH3904-2022年石油化工建设工程项目竣工验收规定
- 叉车检验检测报告
- DNF装备代码大全
- 基于Qt的俄罗斯方块的设计(共25页)
- 古建筑木构件油漆彩绘地仗施工技术分析
- 食堂投诉处理方案
评论
0/150
提交评论