Android实现自定义的卫星式菜单(弧形菜单)详解

Android实现自定义的卫星式菜单(弧形菜单)详解,第1张

概述一、前言Android实现卫星式菜单也叫弧形菜单,主要要做的工作如下:1.动画的处理

一、前言

AndroID 实现卫星式菜单也叫弧形菜单,主要要做的工作如下:

1.动画的处理

2.自定义viewGroup来实现卫星式菜单VIEw

(1)自定义属性

       a. 在attrs.xml中定义属性

       b. 在布局中使用自定义属性

       c. 在自定义VIEw中读取布局文件中的自定义属性

(2)onMeasure 测量 child 即测量主按钮以及菜单项

(3)onLayout 布局 child 即布局主按钮以及菜单项

(4)设置主按钮的选择动画

       a.为菜单项menuItem添加平移动画和旋转动画

       b.实现菜单项menuItem的点击动画

卫星式菜单效果截图:

    

二、实现

上面介绍了原理和效果图,下面来看看卫星菜单类的实现:

1.布局文件的实现

<relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:tools="http://schemas.androID.com/tools" xmlns:xcskin="http://schemas.androID.com/apk/res/com.xc.xcskin" androID:ID="@+ID/container" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" >  <com.xc.xcskin.vIEw.XCArcmenuVIEw  androID:ID="@+ID/arcmenu"  androID:layout_wIDth="150dp"  androID:layout_height="150dp"  androID:layout_alignParentBottom="true"  androID:layout_alignParentleft="true"  xcskin:position="left_bottom"  xcskin:radius="120dp" >  <relativeLayout   androID:layout_wIDth="wrap_content"   androID:layout_height="wrap_content"   androID:background="@drawable/composer_button" >   <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:layout_centerInParent="true"    androID:src="@drawable/composer_icn_plus" />  </relativeLayout>  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_camera"    androID:tag="camera" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_music"    androID:tag="music" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_place"    androID:tag="place" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_sleep"    androID:tag="sleep" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_thought"    androID:tag="thought" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_with"    androID:tag="with" /> </com.xc.xcskin.vIEw.XCArcmenuVIEw>  <com.xc.xcskin.vIEw.XCArcmenuVIEw  androID:ID="@+ID/arcmenu2"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:layout_alignParentBottom="true"  androID:layout_alignParentRight="true"  xcskin:position="right_bottom"  xcskin:radius="150dp" >  <relativeLayout   androID:layout_wIDth="wrap_content"   androID:layout_height="wrap_content"   androID:background="@drawable/composer_button" >   <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:layout_centerInParent="true"    androID:src="@drawable/composer_icn_plus" />  </relativeLayout>  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_camera"    androID:tag="camera" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_music"    androID:tag="music" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_place"    androID:tag="place" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_sleep"    androID:tag="sleep" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_thought"    androID:tag="thought" />  <ImageVIEw    androID:ID="@+ID/ID_button"    androID:layout_wIDth="wrap_content"    androID:layout_height="wrap_content"    androID:src="@drawable/composer_with"    androID:tag="with" /> </com.xc.xcskin.vIEw.XCArcmenuVIEw>  </relativeLayout>

2.卫星菜单类的实现

package com.xc.xcskin.vIEw;import com.xc.xcskin.R;import androID.content.Context;import androID.content.res.TypedArray;import androID.util.AttributeSet;import androID.util.Log;import androID.util.TypedValue;import androID.vIEw.VIEw;import androID.vIEw.VIEw.OnClickListener;import androID.vIEw.VIEwGroup;import androID.vIEw.animation.AlphaAnimation;import androID.vIEw.animation.Animation;import androID.vIEw.animation.Animation.AnimationListener;import androID.vIEw.animation.AnimationSet;import androID.vIEw.animation.RotateAnimation;import androID.vIEw.animation.ScaleAnimation;import androID.vIEw.animation.TranslateAnimation;/** * 卫星式菜单VIEw * @author caizhiming * */public class XCArcmenuVIEw extends VIEwGroup implements OnClickListener{ private static final int POS_left_top = 0; private static final int POS_left_BottOM = 1; private static final int POS_RIGHT_top = 2; private static final int POS_RIGHT_BottOM = 3;  private position mposition = position.RIGHT_BottOM; private int mRadius; private Status mStatus = Status.CLOSE; //主菜的单按钮 private VIEw mCbutton; private OnMenuItemClickListener mOnMenuItemClickListener; /**  * 菜单的状态枚举类  * @author caizhiming  *  */ public enum Status{  OPEN,CLOSE } /**  * 菜单的位置枚举类  * @author caizhiming  *  */ public enum position{  left_top,left_BottOM,RIGHT_top,RIGHT_BottOM } /**  * 点击子菜单项的回调接口  * @author caizhiming  *  */ public interface OnMenuItemClickListener {  voID onClick(VIEw vIEw,int pos); } public voID setonMenuItemClickListener(   OnMenuItemClickListener onMenuItemClickListener) {  this.mOnMenuItemClickListener = onMenuItemClickListener; }  public XCArcmenuVIEw(Context context) {  this(context,null);  // Todo auto-generated constructor stub } public XCArcmenuVIEw(Context context,AttributeSet attrs) {  this(context,attrs,0);  // Todo auto-generated constructor stub } public XCArcmenuVIEw(Context context,AttributeSet attrs,int defStyle) {  super(context,defStyle);  // Todo auto-generated constructor stub  //获取自定义属性  TypedArray a = context.gettheme().obtainStyledAttributes(attrs,R.styleable.XCArcmenuVIEw,defStyle,0);  int pos = a.getInt(R.styleable.XCArcmenuVIEw_position,POS_RIGHT_BottOM);  switch (pos) {   case POS_left_top:    mposition = position.left_top;    break;   case POS_left_BottOM:    mposition = position.left_BottOM;    break;   case POS_RIGHT_top:    mposition = position.RIGHT_top;    break;   case POS_RIGHT_BottOM:    mposition = position.RIGHT_BottOM;    break;  }  mRadius = (int) a.getDimension(R.styleable.XCArcmenuVIEw_radius,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,150,getResources().getdisplayMetrics()));  Log.v("czm","mposition = " + mposition + ",mRadius = "+mRadius);  a.recycle(); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {  // Todo auto-generated method stub  int count = getChildCount();  for(int i = 0; i < count; i ++){   measureChild(getChildAt(i),wIDthMeasureSpec,heightmeasureSpec);  }  super.onMeasure(wIDthMeasureSpec,heightmeasureSpec); } @OverrIDe protected voID onLayout(boolean changed,int l,int t,int r,int b) {  // Todo auto-generated method stub  if(changed){   layoutCbutton();   layoutMenuItems();  } }  /**  * 布局主菜单项  */ private voID layoutCbutton() {  // Todo auto-generated method stub  mCbutton = getChildAt(0);  mCbutton.setonClickListener(this);  int l = 0;  int t = 0;  int wIDth = mCbutton.getMeasureDWIDth();  int height = mCbutton.getMeasuredHeight();  switch (mposition) {   case left_top:    l = 0;    t = 0;    break;    case left_BottOM:    l = 0;    t = getMeasuredHeight() - height;    break;   case RIGHT_top:    l = getMeasureDWIDth() - wIDth;    t = 0;    break;   case RIGHT_BottOM:    l = getMeasureDWIDth() - wIDth;    t = getMeasuredHeight() - height;    break;   default:    break;  }  mCbutton.layout(l,t,l + wIDth,t + height); } /**  * 布局菜单项  */ private voID layoutMenuItems() {  // Todo auto-generated method stub  int count = getChildCount();  for (int i = 0; i < count - 1; i++) {   VIEw child = getChildAt(i + 1);   int l = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));   int t = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));   int wIDth = child.getMeasureDWIDth();   int height = child.getMeasuredHeight();   // 如果菜单位置在底部 左下,右下   if (mposition == position.left_BottOM || mposition == position.RIGHT_BottOM) {    t = getMeasuredHeight() - height - t;   }   // 右上,右下   if (mposition == position.RIGHT_top || mposition == position.RIGHT_BottOM) {    l = getMeasureDWIDth() - wIDth - l;   }   child.layout(l,t + height);   child.setVisibility(VIEw.GONE);  } } @OverrIDe public voID onClick(VIEw v) {  // Todo auto-generated method stub  mCbutton = findVIEwByID(R.ID.ID_button);  rotateCbutton(v,360,300);  toggleMenu(300); } /**  * 切换菜单  */ public voID toggleMenu(int duration) {  // Todo auto-generated method stub  // 为menuItem添加平移动画和旋转动画  int count = getChildCount();  for (int i = 0; i < count - 1; i++)  {   final VIEw childVIEw = getChildAt(i + 1);   childVIEw.setVisibility(VIEw.VISIBLE);   // end 0,0   // start   int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));   int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));   int xflag = 1;   int yflag = 1;   if (mposition == position.left_top     || mposition == position.left_BottOM)   {    xflag = -1;   }   if (mposition == position.left_top     || mposition == position.RIGHT_top)   {    yflag = -1;   }   AnimationSet animset = new AnimationSet(true);   Animation tranAnim = null;   // to open   if (mStatus == Status.CLOSE)   {    tranAnim = new TranslateAnimation(xflag * cl,yflag * ct,0);    childVIEw.setClickable(true);    childVIEw.setFocusable(true);   } else   // to close   {    tranAnim = new TranslateAnimation(0,xflag * cl,yflag * ct);    childVIEw.setClickable(false);    childVIEw.setFocusable(false);   }   tranAnim.setFillAfter(true);   tranAnim.setDuration(duration);   tranAnim.setStartOffset((i * 100) / count);   tranAnim.setAnimationListener(new AnimationListener()   {    @OverrIDe    public voID onAnimationStart(Animation animation)    {    }    @OverrIDe    public voID onAnimationRepeat(Animation animation)    {    }    @OverrIDe    public voID onAnimationEnd(Animation animation)    {     if (mStatus == Status.CLOSE)     {      childVIEw.setVisibility(VIEw.GONE);     }    }   });   // 旋转动画   RotateAnimation rotateAnim = new RotateAnimation(0,720,Animation.relative_TO_SELF,0.5f,0.5f);   rotateAnim.setDuration(duration);   rotateAnim.setFillAfter(true);   animset.addAnimation(rotateAnim);   animset.addAnimation(tranAnim);   childVIEw.startAnimation(animset);   final int pos = i + 1;   childVIEw.setonClickListener(new OnClickListener()   {    @OverrIDe    public voID onClick(VIEw v)    {     if (mOnMenuItemClickListener != null)      mOnMenuItemClickListener.onClick(childVIEw,pos);     menuItemAnim(pos - 1);     changeStatus();    }   });  }  // 切换菜单状态  changeStatus();   } /**  * 选择主菜单按钮  *   */ private voID rotateCbutton(VIEw v,float start,float end,int duration) {  // Todo auto-generated method stub  RotateAnimation anim = new RotateAnimation(start,end,0.5f);  anim.setDuration(duration);  anim.setFillAfter(true);  v.startAnimation(anim); } /**  * 添加menuItem的点击动画  *   */ private voID menuItemAnim(int pos) {  for (int i = 0; i < getChildCount() - 1; i++)  {   VIEw childVIEw = getChildAt(i + 1);   if (i == pos)   {    childVIEw.startAnimation(scaleBigAnim(300));   } else   {    childVIEw.startAnimation(scaleSmallAnim(300));   }   childVIEw.setClickable(false);   childVIEw.setFocusable(false);  } } /**  * 为当前点击的Item设置变小和透明度增大的动画  * @param duration  * @return  */ private Animation scaleSmallAnim(int duration) {  AnimationSet animationSet = new AnimationSet(true);  ScaleAnimation scaleAnim = new ScaleAnimation(1.0f,0.0f,1.0f,0.5f);  AlphaAnimation AlphaAnim = new AlphaAnimation(1f,0.0f);  animationSet.addAnimation(scaleAnim);  animationSet.addAnimation(AlphaAnim);  animationSet.setDuration(duration);  animationSet.setFillAfter(true);  return animationSet; } /**  * 为当前点击的Item设置变大和透明度降低的动画  */ private Animation scaleBigAnim(int duration) {  AnimationSet animationSet = new AnimationSet(true);  ScaleAnimation scaleAnim = new ScaleAnimation(1.0f,4.0f,0.0f);  animationSet.addAnimation(scaleAnim);  animationSet.addAnimation(AlphaAnim);  animationSet.setDuration(duration);  animationSet.setFillAfter(true);  return animationSet; } /**  * 切换菜单状态  */ private voID changeStatus() {  mStatus = (mStatus == Status.CLOSE ? Status.OPEN    : Status.CLOSE); } /**  * 是否处于展开状态  * @return  */ public boolean isopen() {  return mStatus == Status.OPEN; }  }

3.使用卫星式菜单类

package com.xc.xcskin;import androID.app.Activity;import androID.os.Bundle;import androID.vIEw.VIEw;import androID.Widget.Toast;import com.xc.xcskin.vIEw.XCArcmenuVIEw;import com.xc.xcskin.vIEw.XCArcmenuVIEw.OnMenuItemClickListener;import com.xc.xcskin.vIEw.XCGuaguakaVIEw;import com.xc.xcskin.vIEw.XCGuaguakaVIEw.OnCompleteListener;/** * 使用并测试自定义卫星式菜单VIEw * @author caizhiming * */public class XCArcmenuVIEwDemo extends Activity{ @OverrIDe protected voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.xc_arcmenu_vIEw_demo);  XCArcmenuVIEw vIEw = (XCArcmenuVIEw) findVIEwByID(R.ID.arcmenu);  vIEw.setonMenuItemClickListener(new OnMenuItemClickListener() {      @OverrIDe   public voID onClick(VIEw vIEw,int pos) {    // Todo auto-generated method stub    String tag = (String) vIEw.getTag();    Toast.makeText(XCArcmenuVIEwDemo.this,tag,Toast.LENGTH_SHORT).show();   }  }); }}

三、总结

AndroID实现自定义的卫星式菜单(弧形菜单)的内容到这就基本结束了,感兴趣的朋友们可以动手 *** 作起来,只有自己实践了才能更深的理解,希望本文对大家能有所帮助。

总结

以上是内存溢出为你收集整理的Android实现自定义的卫星式菜单(弧形菜单)详解全部内容,希望文章能够帮你解决Android实现自定义的卫星式菜单(弧形菜单)详解所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1148561.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存