自定义菜单栏---卫星菜单栏

在android开发中卫星菜单栏比较常用,而且不失为一个比较炫的而且简单实现的自定义控件

1.

下面开始实现功能,ok~首先先来看要实现的功能:
1.点击主菜单按钮 按钮旋转360 子菜单按钮菜单展开
2.在展开状态下点击主菜单,然后子菜单合拢
3.子菜单按钮会有旋转,平移,渐变动画
4.在展开状态下,点击子菜单按钮,被点击按钮放大消,其他没有被点击的子菜单消失
5.在demo中添加listView,如果菜单为展开状态,滑动listViewh会自动合拢
6.主菜单和子菜单布局在代码中做了判单,在左上,左下,右上,右下都不会影响效果,有需求 可以检测

2.

    下面来看效果图:

自定义菜单栏---卫星菜单栏_第1张图片

3.

功能和效果介绍完之后开始详细解析代码:
3.1布局的设置以及自定义属性的实现

在res->value 下设置自定义属性,然后自定义菜单继承属性:


<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中实现自定义属性(即位置和半径)


<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 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(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 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(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~ 就到这里了 期待共同进步;

你可能感兴趣的:(android,custom,widget)