自定义菜单栏---卫星菜单栏
来源:互联网 发布:网络赚钱的门路和技巧 编辑:程序博客网 时间:2024/05/31 19:35
在android开发中卫星菜单栏比较常用,而且不失为一个比较炫的而且简单实现的自定义控件
1.
下面开始实现功能,ok~首先先来看要实现的功能:
1.点击主菜单按钮 按钮旋转360 子菜单按钮菜单展开
2.在展开状态下点击主菜单,然后子菜单合拢
3.子菜单按钮会有旋转,平移,渐变动画
4.在展开状态下,点击子菜单按钮,被点击按钮放大消,其他没有被点击的子菜单消失
5.在demo中添加listView,如果菜单为展开状态,滑动listViewh会自动合拢
6.主菜单和子菜单布局在代码中做了判单,在左上,左下,右上,右下都不会影响效果,有需求 可以检测
2.
下面来看效果图:
3.
功能和效果介绍完之后开始详细解析代码:
3.1布局的设置以及自定义属性的实现
在res->value 下设置自定义属性,然后自定义菜单继承属性:
<?xml version="1.0" encoding="utf-8"?><resources> <attr name="position"> <enum name="left_top" value="0"/> <enum name="left_bottom" value="1"/> <enum name="right_top" value="2"/> <enum name="right_bottom" value="3"/> </attr> <attr name="radius" format="dimension"/> <declare-styleable name="ArcMenu"> <attr name="position"/> <attr name="radius"/> </declare-styleable></resources>
由以上代码可以看到 设置了一个Position 就是主菜单按钮的位置设定,(有四个值,可以自己定制);然后设置了半径(不是严格意义上的半径),就是自菜单和主菜单的直线长度;然后自定义空间ArcMenu 继承 然后再MainActivity中加入ArcMenu并且在xml中实现自定义属性(即位置和半径)
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:myattr = "http://schemas.android.com/apk/res/com.example.custonmenu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp"> <!--至少有一个主按钮 若干个菜单按钮--> <com.example.custonmenu.custom.ArcMenu android:id="@+id/arc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" myattr:position = "right_bottom" myattr:radius = "100dp" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/bg_btn"> <ImageView android:layout_centerInParent="true" android:id="@+id/button" android:layout_width="30dp" android:layout_height="30dp" android:src="@drawable/icon_close"/> </RelativeLayout> <ImageView android:id="@+id/btn_eat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon_eat" android:tag="eat"/> <ImageView android:id="@+id/btn_movie" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon_moive" android:tag="movie"/> <ImageView android:id="@+id/btn_play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon_play" android:tag="play"/> <ImageView android:id="@+id/btn_sleep" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon_sleep" android:tag="sleep"/> </com.example.custonmenu.custom.ArcMenu></FrameLayout>
在根布局中生命自定义属性 这里定义为myattr,以便后面使用该自定义属性,仔细看xml代码 这里没有sm好说的
3.2核心自定义代码类ArcMenu的实现
自定义一个菜单的自定义空间ArcMenu,实现其半径的获取和初始position的设置
public class ArcMenu extends ViewGroup implements View.OnClickListener { /**自定义属性 半径*/ private int mRadius; /**设置value 用于匹配attrs*/ private final int LEFT_TOP = 0; private final int LEFT_BOTTOM = 1; private final int RIGHT_TOP = 2; private final int RIGHT_BOTTOM = 3; /**设置初始的位置和按钮状态*/ private Position mPosition = Position.RIGHT_BOTTOM; private State mState = State.CLOSE; private View mainMenu; /**两个自定义的属性 position radius * @param * * */ private enum Position{ LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM } /**菜单的打开和关闭状态的枚举类型*/ private enum State{ OPEN,CLOSE } public ArcMenu(Context context) { this(context,null); } public ArcMenu(Context context, AttributeSet attrs) { this(context, attrs,0); } public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /**给半径设置属性 dp*/// mRadius = TypedValue.applyDimension(// TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics()); //获取自定义属性 //获取position的value TypedArray type = context.getTheme(). obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0); int POS = type.getInt(R.styleable.ArcMenu_position, RIGHT_BOTTOM); switch (POS){ case LEFT_TOP: mPosition = Position.LEFT_TOP; break; case LEFT_BOTTOM: mPosition = Position.LEFT_BOTTOM; break; case RIGHT_TOP: mPosition = Position.RIGHT_TOP; break; case RIGHT_BOTTOM: mPosition = Position.RIGHT_BOTTOM; break; } //设置半径 mRadius = (int) type.getDimension(R.styleable.ArcMenu_radius, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 150, getResources(). getDisplayMetrics())); //Log.i("mRadius = COMPLEX_UNIT_DIP",mPosition + "===" + mRadius); type.recycle(); }
初始化成员变量,Position和State(开关状态)这里用枚举来记录多种类型,在构造方法中从xml根据自定义属性attr来去除半径设置到mRadius,根据xml中属性position判断来给mPosition赋值,在这里基本初始化完毕;
然后开始设置其measure方法实现ArcMenu中对其字孩子的测量,对每一个子孩子的宽高进行测量:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量子孩子 int count = getChildCount(); for (int i = 0; i < count; i++) { View view = getChildAt(i); measureChild(view,widthMeasureSpec,heightMeasureSpec); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
接下来 开始在onLayout最后对空间进行重新布局:
@Override protected void onLayout(boolean change, int l, int t, int r, int b) { if (change){ //设置主menu layoutMainMenu(); //设置item layoutItemMenu(); } }
接着看主menu的布局设置:
private void layoutMainMenu() { mainMenu = getChildAt(0); mainMenu.setOnClickListener(this); int l = 0; int t = 0; int mWidth = mainMenu.getMeasuredWidth(); int mHeight = mainMenu.getMeasuredHeight(); switch (mPosition){ case LEFT_TOP: l = 0; t = 0; break; case LEFT_BOTTOM: l = 0; t = getMeasuredHeight() - mHeight; break; case RIGHT_TOP: l = getMeasuredWidth() - mWidth; t = 0; break; case RIGHT_BOTTOM: l = getMeasuredWidth() - mWidth; t = getMeasuredHeight() - mHeight; break; } mainMenu.layout(l,t,l+mWidth,t+mHeight); }
分别对LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM的位置进行left,top,right,bottom的设置,这样主菜单放在哪里都可以分布;
接着看子菜单的布局:
private void layoutItemMenu() { int count = getChildCount(); for (int i = 0; i < count - 1; i++) { //第一个字孩子市主菜单 不在这里布局 View itemMenu = getChildAt(i + 1); //设置item点击 initItemClick(itemMenu,i + 1); itemMenu.setVisibility(GONE); int mItemHeight = itemMenu.getMeasuredHeight(); int mItemWidth = itemMenu.getMeasuredWidth(); int il = (int) (mRadius * Math.sin(Math.PI/2/(count-2) * i)); int it = (int) (mRadius * Math.cos(Math.PI/2/(count - 2) * i)); if (mPosition == Position.RIGHT_BOTTOM || mPosition == Position.RIGHT_TOP){ //高是不变的 l要改变 il = getMeasuredWidth() - il - mItemWidth; } if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM){ it = getMeasuredHeight() - it - mItemHeight; } itemMenu.layout(il,it,il + mItemWidth,it + mItemHeight); } }
这里用到一点三角函数的知识建议画图做了解,首先以LEFT_TOP为基准设置il和it,il = mRadius * sin(PI/2/3*i),it = mRadius * cos(PI/2/3*i);根据不同位置进行变化 最后统一调用layout进行布局:
int il = (int) (mRadius * Math.sin(Math.PI/2/(count-2) * i)); int it = (int) (mRadius * Math.cos(Math.PI/2/(count - 2) * i)); if (mPosition == Position.RIGHT_BOTTOM || mPosition == Position.RIGHT_TOP){ //高是不变的 l要改变 il = getMeasuredWidth() - il - mItemWidth; } if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM){ it = getMeasuredHeight() - it - mItemHeight; } itemMenu.layout(il,it,il + mItemWidth,it + mItemHeight);
当然需要注意的事 一开始默认菜单为关闭 所以需要把子菜单设置为不可见;接着就需要看主菜单和子菜单的点击事件了 这里需要加入动画;
首先看主菜单的点击事件:
@Override public void onClick(View view) { //设置按钮的旋转 setRotaAnim(view); //切换菜单 setChangeMenu(); }
首先来看主菜单的自身的旋转动画:
private void setRotaAnim(View view) { RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setFillAfter(true); rotateAnimation.setDuration(500); view.startAnimation(rotateAnimation); }
很简单 就是一个旋转动画,那么接下来看点击主菜单,子菜单按钮的飞入飞出动画,这里包含3中动画,平移+旋转+渐变:
public void setChangeMenu() { int end = 0; int start = 0; TranslateAnimation translateAnimation; int count = getChildCount(); for (int i = 0; i < count - 1; i++) { final View itemView = getChildAt(i + 1); itemView.setVisibility(VISIBLE); int il = (int) (mRadius * Math.sin(Math.PI/2/(count-2) * i)); int it = (int) (mRadius * Math.cos(Math.PI/2/(count - 2) * i)); //对每一个item添加动画 AnimationSet animationSet = new AnimationSet(true); //添加平移动画 //判断位移的距离 int xFlat = 1; int yFlat = 1; //开始判断 if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM){ xFlat = -1; } if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP){ yFlat = -1; } if (mState == State.CLOSE){ translateAnimation = new TranslateAnimation(xFlat * il, 0, yFlat * it, 0); itemView.setClickable(true); itemView.setFocusable(true); }else { translateAnimation = new TranslateAnimation(0,xFlat * il, 0, yFlat * it); itemView.setClickable(false); itemView.setFocusable(false); } translateAnimation.setFillAfter(true); translateAnimation.setDuration(500); translateAnimation.setStartOffset((i * 100) / count); translateAnimation.setAnimationListener(new //设置旋转动画 RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setFillAfter(true); rotateAnimation.setDuration(500); AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0f); alphaAnimation.setDuration(500); alphaAnimation.setFillAfter(true); AlphaAnimation alphaAnimation1 = new AlphaAnimation(0f, 1.0f); alphaAnimation1.setDuration(500); alphaAnimation1.setFillAfter(true); animationSet.addAnimation(rotateAnimation); animationSet.addAnimation(translateAnimation); if (mState == State.OPEN){ animationSet.addAnimation(alphaAnimation); }else { animationSet.addAnimation(alphaAnimation1); } animationSet.setFillAfter(true); animationSet.setDuration(500); itemView.startAnimation(animationSet); } changeState(); }
首先大体来看,是AnimSet的组合动画,重点要看子菜单按钮的平移动画的位移变化,这里是比较绕的:
int xFlat = 1; int yFlat = 1; //开始判断 if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM){ xFlat = -1; } if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP){ yFlat = -1; } if (mState == State.CLOSE){ translateAnimation = new TranslateAnimation(xFlat * il, 0, yFlat * it, 0); itemView.setClickable(true); itemView.setFocusable(true); }else { translateAnimation = new TranslateAnimation(0,xFlat * il, 0, yFlat * it); itemView.setClickable(false); itemView.setFocusable(false); }
首先是以子菜单按钮自身来说,x = 0 ,y = 0,他们的位移均为上面代码il和it,就是前面用三角函数获取的偏移量,当左上和左下时候,x方向收缩时候,子菜单x坐标市减少的,在左上和右上,y方向同样坐标是减少的,所以要通过xFlag和yFlag的正负来控制减少和增加,建议画图自己研究一下,很简单;
最后不要忘了在点击菜单完毕后要重新设置menu的state:
private void changeState() { mState = (mState == State.CLOSE?State.OPEN:State.CLOSE); }
最后设置字按钮的点击事件: 首先复制部分代码 说明一下:
for (int i = 0; i < count - 1; i++) { //第一个字孩子市主菜单 不在这里布局 View itemMenu = getChildAt(i + 1); //设置item点击 initItemClick(itemMenu,i + 1);
这是遍历子孩子,因为是设置子孩子的点击,需要排除主按钮,而恰好主按钮也是子孩子,所以需要在遍历时候条件,设定为0~count-2,然后传入position时候,传入postion+1;
ok,看子菜单按钮的点击事件:
private void initItemClick(View itemMenu, final int pos) { itemMenu.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { int count = getChildCount(); for (int i = 0; i < count - 1 ; i++) { View itemView = getChildAt(i + 1); if (i + 1 == pos){ if (mListener != null) mListener.onClick(view,pos); //放大动画+ 透明 AnimationSet animationSet = new AnimationSet(true); //放大动画 ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 4.0f, 1.0f, 4.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); //透明动画 AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0f); animationSet.setDuration(500); animationSet.setFillAfter(true); animationSet.addAnimation(scaleAnimation); animationSet.addAnimation(alphaAnimation); itemView.startAnimation(animationSet); mState = State.CLOSE; }else{ //透明动画 AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0f); alphaAnimation.setDuration(500); alphaAnimation.setFillAfter(true); itemView.startAnimation(alphaAnimation); } } } }); }
大体思路就是点击时候遍历所有按钮,被点击的放大伴随消失,没有点击的直接消失;当然要严格控制开/闭的状态;
最后需要在ArcMenu中定义一个对调的接口:
/**设置接口的对象*/ private OnItemClickListener mListener; /**设置会调接口的方法*/ public void setOnItemClickListener(OnItemClickListener listener) { this.mListener = listener; } /**设置会调接口*/ public interface OnItemClickListener{ void onClick(View view ,int pos); }
对调接口中抽象方法放在子菜单的点击事件中:(这里仅粘贴部分代码)
rivate void initItemClick(View itemMenu, final int pos) { itemMenu.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { int count = getChildCount(); for (int i = 0; i < count - 1 ; i++) { View itemView = getChildAt(i + 1); if (i + 1 == pos){ if (mListener != null) mListener.onClick(view,pos); //放大动画+ 透明 AnimationSet animationSet = new AnimationSet(true);
在Arc中设置一个记录状态的方法:
public boolean isOpen(){ if (mState == State.CLOSE){ return false; }else { return true; } }
接下来就是在MainActivity中调用了,比较简单直接粘贴MainActivity中代码:
public class MainActivity extends AppCompatActivity implements ArcMenu.OnItemClickListener { private ArcMenu mArc; private ListView mListView; private ArrayList<String> mData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); initListener(); } private void initListener() { mListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView absListView, int i) { } @Override public void onScroll(AbsListView absListView, int i, int i1, int i2) { if (mArc.isOpen()){ mArc.setChangeMenu(); } } }); } private void initView() { mArc = (ArcMenu) findViewById(R.id.arc); mListView = (ListView) findViewById(R.id.listView); } private void initData() { mArc.setOnItemClickListener(this); setData(); mListView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mData)); } private void setData() { mData = new ArrayList<>(); for (int i = 'A'; i < 'Z'; i++) { mData.add(String.valueOf((char)i)); } } @Override public void onClick(View view, int pos) { Toast.makeText(this,view.getTag()+ "",Toast.LENGTH_SHORT).show(); }}
就是设置一个简单的listView,然后监听listView的滑动,当滑动过程中,通过Arcmenu的isOpen()返回值判断,当为打开状态时候,滑动自动合闭;调用ArcMenu中setChangeMenu
这样一个卫星样式的可打开,可定制实现功能的菜单栏就实现了
下面看完整代码:
//ArcMenu:
package com.example.custonmenu.custom;import android.content.BroadcastReceiver;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.ViewGroup;import android.view.animation.AlphaAnimation;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.RotateAnimation;import android.view.animation.ScaleAnimation;import android.view.animation.TranslateAnimation;import android.widget.Switch;import com.example.custonmenu.MainActivity;import com.example.custonmenu.R;/** * Created by houruixiang on 2017/8/7. * 自定义菜单栏 */public class ArcMenu extends ViewGroup implements View.OnClickListener { /**自定义属性 半径*/ private int mRadius; /**设置value 用于匹配attrs*/ private final int LEFT_TOP = 0; private final int LEFT_BOTTOM = 1; private final int RIGHT_TOP = 2; private final int RIGHT_BOTTOM = 3; /**设置初始的位置和按钮状态*/ private Position mPosition = Position.RIGHT_BOTTOM; private State mState = State.CLOSE; private View mainMenu; /**两个自定义的属性 position radius * @param * * */ private enum Position{ LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM } /**菜单的打开和关闭状态的枚举类型*/ private enum State{ OPEN,CLOSE } /**设置接口的对象*/ private OnItemClickListener mListener; /**设置会调接口的方法*/ public void setOnItemClickListener(OnItemClickListener listener) { this.mListener = listener; } /**设置会调接口*/ public interface OnItemClickListener{ void onClick(View view ,int pos); } public ArcMenu(Context context) { this(context,null); } public ArcMenu(Context context, AttributeSet attrs) { this(context, attrs,0); } public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /**给半径设置属性 dp*/// mRadius = TypedValue.applyDimension(// TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics()); //获取自定义属性 //获取position的value TypedArray type = context.getTheme(). obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0); int POS = type.getInt(R.styleable.ArcMenu_position, RIGHT_BOTTOM); switch (POS){ case LEFT_TOP: mPosition = Position.LEFT_TOP; break; case LEFT_BOTTOM: mPosition = Position.LEFT_BOTTOM; break; case RIGHT_TOP: mPosition = Position.RIGHT_TOP; break; case RIGHT_BOTTOM: mPosition = Position.RIGHT_BOTTOM; break; } //设置半径 mRadius = (int) type.getDimension(R.styleable.ArcMenu_radius, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 150, getResources(). getDisplayMetrics())); //Log.i("mRadius = COMPLEX_UNIT_DIP",mPosition + "===" + mRadius); type.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量子孩子 int count = getChildCount(); for (int i = 0; i < count; i++) { View view = getChildAt(i); measureChild(view,widthMeasureSpec,heightMeasureSpec); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean change, int l, int t, int r, int b) { if (change){ //设置主menu layoutMainMenu(); //设置item layoutItemMenu(); } } private void layoutItemMenu() { int count = getChildCount(); for (int i = 0; i < count - 1; i++) { //第一个字孩子市主菜单 不在这里布局 View itemMenu = getChildAt(i + 1); //设置item点击 initItemClick(itemMenu,i + 1); itemMenu.setVisibility(GONE); int mItemHeight = itemMenu.getMeasuredHeight(); int mItemWidth = itemMenu.getMeasuredWidth(); int il = (int) (mRadius * Math.sin(Math.PI/2/(count-2) * i)); int it = (int) (mRadius * Math.cos(Math.PI/2/(count - 2) * i)); if (mPosition == Position.RIGHT_BOTTOM || mPosition == Position.RIGHT_TOP){ //高是不变的 l要改变 il = getMeasuredWidth() - il - mItemWidth; } if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM){ it = getMeasuredHeight() - it - mItemHeight; } itemMenu.layout(il,it,il + mItemWidth,it + mItemHeight); } } private void initItemClick(View itemMenu, final int pos) { itemMenu.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { int count = getChildCount(); for (int i = 0; i < count - 1 ; i++) { View itemView = getChildAt(i + 1); if (i + 1 == pos){ if (mListener != null) mListener.onClick(view,pos); //放大动画+ 透明 AnimationSet animationSet = new AnimationSet(true); //放大动画 ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 4.0f, 1.0f, 4.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); //透明动画 AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0f); animationSet.setDuration(500); animationSet.setFillAfter(true); animationSet.addAnimation(scaleAnimation); animationSet.addAnimation(alphaAnimation); itemView.startAnimation(animationSet); mState = State.CLOSE; }else{ //透明动画 AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0f); alphaAnimation.setDuration(500); alphaAnimation.setFillAfter(true); itemView.startAnimation(alphaAnimation); } } } }); } private void layoutMainMenu() { mainMenu = getChildAt(0); mainMenu.setOnClickListener(this); int l = 0; int t = 0; int mWidth = mainMenu.getMeasuredWidth(); int mHeight = mainMenu.getMeasuredHeight(); switch (mPosition){ case LEFT_TOP: l = 0; t = 0; break; case LEFT_BOTTOM: l = 0; t = getMeasuredHeight() - mHeight; break; case RIGHT_TOP: l = getMeasuredWidth() - mWidth; t = 0; break; case RIGHT_BOTTOM: l = getMeasuredWidth() - mWidth; t = getMeasuredHeight() - mHeight; break; } mainMenu.layout(l,t,l+mWidth,t+mHeight); } @Override public void onClick(View view) { //设置按钮的旋转 setRotaAnim(view); //切换菜单 setChangeMenu(); } public void setChangeMenu() { int end = 0; int start = 0; TranslateAnimation translateAnimation; int count = getChildCount(); for (int i = 0; i < count - 1; i++) { final View itemView = getChildAt(i + 1); itemView.setVisibility(VISIBLE); int il = (int) (mRadius * Math.sin(Math.PI/2/(count-2) * i)); int it = (int) (mRadius * Math.cos(Math.PI/2/(count - 2) * i)); //对每一个item添加动画 AnimationSet animationSet = new AnimationSet(true); //添加平移动画 //判断位移的距离 int xFlat = 1; int yFlat = 1; //开始判断 if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM){ xFlat = -1; } if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP){ yFlat = -1; } if (mState == State.CLOSE){ translateAnimation = new TranslateAnimation(xFlat * il, 0, yFlat * it, 0); itemView.setClickable(true); itemView.setFocusable(true); }else { translateAnimation = new TranslateAnimation(0,xFlat * il, 0, yFlat * it); itemView.setClickable(false); itemView.setFocusable(false); } translateAnimation.setFillAfter(true); translateAnimation.setDuration(500); translateAnimation.setStartOffset((i * 100) / count); translateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (mState == State.CLOSE){ itemView.setVisibility(GONE); } //Log.i("onAnimationEnd","nihao i m u"); //itemView.setVisibility(GONE); } @Override public void onAnimationRepeat(Animation animation) { } }); //设置旋转动画 RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setFillAfter(true); rotateAnimation.setDuration(500); AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0f); alphaAnimation.setDuration(500); alphaAnimation.setFillAfter(true); AlphaAnimation alphaAnimation1 = new AlphaAnimation(0f, 1.0f); alphaAnimation1.setDuration(500); alphaAnimation1.setFillAfter(true); animationSet.addAnimation(rotateAnimation); animationSet.addAnimation(translateAnimation); if (mState == State.OPEN){ animationSet.addAnimation(alphaAnimation); }else { animationSet.addAnimation(alphaAnimation1); } animationSet.setFillAfter(true); animationSet.setDuration(500); itemView.startAnimation(animationSet); } changeState(); } private void changeState() { mState = (mState == State.CLOSE?State.OPEN:State.CLOSE); } private void setRotaAnim(View view) { RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setFillAfter(true); rotateAnimation.setDuration(500); view.startAnimation(rotateAnimation); } public boolean isOpen(){ if (mState == State.CLOSE){ return false; }else { return true; } }}
//MainActivity:
package com.example.custonmenu;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.AbsListView;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.Toast;import com.example.custonmenu.custom.ArcMenu;import java.util.ArrayList;public class MainActivity extends AppCompatActivity implements ArcMenu.OnItemClickListener { private ArcMenu mArc; private ListView mListView; private ArrayList<String> mData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); initListener(); } private void initListener() { mListView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView absListView, int i) { } @Override public void onScroll(AbsListView absListView, int i, int i1, int i2) { if (mArc.isOpen()){ mArc.setChangeMenu(); } } }); } private void initView() { mArc = (ArcMenu) findViewById(R.id.arc); mListView = (ListView) findViewById(R.id.listView); } private void initData() { mArc.setOnItemClickListener(this); setData(); mListView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mData)); } private void setData() { mData = new ArrayList<>(); for (int i = 'A'; i < 'Z'; i++) { mData.add(String.valueOf((char)i)); } } @Override public void onClick(View view, int pos) { Toast.makeText(this,view.getTag()+ "",Toast.LENGTH_SHORT).show(); }}
ok~ 就到这里了 期待共同进步;
- 自定义菜单栏---卫星菜单栏
- 菜单栏
- 菜单栏
- 菜单栏
- 菜单栏
- 菜单栏
- 菜单栏
- Qt 菜单栏自定义
- Android自定义菜单栏
- Unity 自定义菜单栏
- Access2003中自定义菜单栏
- Unity自定义菜单栏
- UIWebView自定义菜单栏
- 自定义jqgrid 菜单栏
- Qt自定义菜单栏
- VBA自定义菜单和菜单栏
- VBA自定义菜单和菜单栏
- 自定义左下角弧形旋转菜单栏
- 通俗易懂java设计模式——策略模式(Strategy)
- 决策树相关知识小结
- 顺序表应用4:元素位置互换之逆置算法
- 蓝牙音响升压芯片 内置MOS 可升9V FP6298
- jar包执行后程序资源无法读取的解决方案
- 自定义菜单栏---卫星菜单栏
- 数组中求俩个数,三个数,K个数和为给定sum
- leetcode--Implement Stack using Queues
- gradle 学习记录1--mac
- 动态规划入门-最大子段
- 网站要上线了,问问自己这15个问题再做决定
- GitHub开源推荐系统项目Surprise的安装和使用
- /usr/bin/ld: cannot find -l* 错误的解决方法
- 前端程序员必知的30个Chrome扩展