一、前言
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实现自定义的卫星式菜单(弧形菜单)详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)