android 显示在底部的ArcMenu菜单

结合各位大佬的文章整理的

自定义菜单

package com.yjcul.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;

import com.yjcul.barcounter.R;

/**
 * Created by yadianna02 on 2018/7/23.
 */

public class ArcMenu extends RelativeLayout implements View.OnClickListener {
    private static String TAG = "tag";
    private int position = 1;// 标识菜单的位置 0:上 1:下(当前代码未使用,仅开发了下方的菜单)
    private int radius = dip2px(getContext(), 100);// 菜单的半径
    private int mHeight;
    private int mWidth;
    private int centerChildHeight;
    private int centerChildWidth;
    private View mMenu;
    private boolean mStatus = false;// true表示打开,false表示关闭
    private OnItemClicklistener mOnItemClickListener;
    private int childCount;
    private AnimationSet mItemAnimationSet;//菜单项被点击的动画集合

    public ArcMenu(Context context) {
        this(context, null);
    }

    public ArcMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ArcMenu(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0);
        int count = array.getIndexCount();
        for (int i = 0; i < count; i++) {
            int index = array.getIndex(i);
            switch (index) {
                case R.styleable.ArcMenu_position:
                    position = array.getInteger(index, 1);
                    break;
                case R.styleable.ArcMenu_radius:
                    radius = (int) array.getDimension(index, dip2px(context, 100));
                default:
                    break;
            }
        }

        array.recycle();

        /**
         * 完成菜单项被点击的动画的初始化
         */
        mItemAnimationSet = new AnimationSet(false);//false标识动画集中的动画各自使用自己的动画插入器

        //创建一个形变动画,从相对于自身中心点由1倍体积扩大到3倍体积
        ScaleAnimation mScaleAnimation = new ScaleAnimation(1.0f, 3.0f, 1.0f, 3.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mScaleAnimation.setDuration(400);
        //创建一个透明度动画,透明度从不透明到完全透明
        AlphaAnimation mAlphaAnimation = new AlphaAnimation(1.0f, 0.0f);
        mAlphaAnimation.setDuration(400);
        mItemAnimationSet.addAnimation(mAlphaAnimation);
        mItemAnimationSet.addAnimation(mScaleAnimation);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed) {
            childCount = getChildCount();
            if (childCount <= 2) {//菜单项不能少于两个
                return;
            }
            for (int i = 0; i < childCount; i++) {
                View child = getChildAt(i);
                int childHeight = child.getMeasuredHeight();
                int childWidth = child.getMeasuredWidth();
                if (i == 0) {// 中心菜单
                    centerChildHeight = mHeight - child.getMeasuredHeight() / 2;// 中间view的中心坐标y
                    centerChildWidth = mWidth / 2;// 中间view的中心坐标y

                    child.layout((mWidth - childWidth) / 2, mHeight - childHeight, (mWidth + childWidth) / 2, mHeight);
                    child.setOnClickListener(this);
                } else {//根据弧度计算出每个子菜单的位置
                    child.setVisibility(View.GONE);
                    double temA = Math.PI / (childCount - 2) * (i - 1);
                    int left = 0;
                    int top = 0;
                    int right = 0;
                    int bottom = 0;
                    left = (int) (centerChildWidth + radius * Math.cos(temA) - childWidth / 2);
                    top = (int) (centerChildHeight - radius * Math.sin(temA) - childHeight / 2);
                    right = (int) (centerChildWidth + radius * Math.cos(temA) + childWidth / 2);
                    bottom = (int) (centerChildHeight - radius * Math.sin(temA) + childHeight / 2);
                    child.layout(left, top, right, bottom);
                }
            }
        }
    }

    @Override
    public void onClick(View v) {
        startCenterMenuAnimation();
        startItemMenuAnimation();
        changeStatus();
    }

    /**
     * 设置子菜单展开和收回的动画
     */
    private void startItemMenuAnimation() {
        final int childCount = getChildCount();
        TranslateAnimation animation = null;
        for (int i = 1; i < childCount; i++) {
            final int position = i;
            double temA = Math.PI / (childCount - 2) * (i - 1);
            final View child = getChildAt(i);
            if (mStatus) {
                animation = new TranslateAnimation(0, -(float) (radius * Math.cos(temA)), 0, (float) (radius * Math.sin(temA)));
                child.setVisibility(View.GONE);
                animation.setDuration(300);
            } else {

                animation = new TranslateAnimation(-(float) (radius * Math.cos(temA)), 0, (float) (radius * Math.sin(temA)), 0);
                animation.setInterpolator(new OvershootInterpolator(3f));
                child.setVisibility(View.VISIBLE);
                animation.setDuration(500);
            }
            child.startAnimation(animation);
            child.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    startItemClickAnimation(position);
                    changeStatus(false);
                    if (mOnItemClickListener != null) {
                        mOnItemClickListener.onClick(child, position);
                    }
                }
            });
        }
    }

    /**
     * 中间主菜单项的动画效果
     */
    private void startCenterMenuAnimation() {
        mMenu = getChildAt(0);
        RotateAnimation animation = new RotateAnimation(0f, 360F, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation.setFillAfter(true);
        animation.setDuration(500);
        mMenu.startAnimation(animation);
    }

    /**
     * 改变菜单的状态
     */
    private void changeStatus() {
        if (mStatus) {
            mStatus = false;
        } else {
            mStatus = true;
        }
    }

    /**
     * 改变菜单的状态
     */
    private void changeStatus(boolean b) {
        mStatus = b;
    }

    /**
     * 设置菜单项被点击的动画
     */
    private void startItemClickAnimation(int positon) {
        for (int i = 1; i < childCount; i++) {
            View child = getChildAt(i);
            if (i == positon) {
                child.startAnimation(mItemAnimationSet);
            }
            child.setVisibility(View.GONE);
        }
    }


    /**
     * 菜单项的监听
     */
    public interface OnItemClicklistener {
        void onClick(View v, int position);
    }

    public OnItemClicklistener getOnItemClickListener() {
        return mOnItemClickListener;
    }

    public void setOnItemClickListener(OnItemClicklistener mOnItemClickListener) {
        this.mOnItemClickListener = mOnItemClickListener;
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
}

在values下创建attrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="position">
        <enum name="left_top" value="0" />
        <enum name="right_top" value="1" />
        <enum name="right_bottom" value="2" />
        <enum name="left_bottom" value="3" />
    </attr>
    <attr name="radius" format="dimension"></attr>

    <declare-styleable name="ArcMenu">
        <attr name="position" />
        <attr name="radius" />
    </declare-styleable>
</resources>

使用方法:

布局文件中

<com.yjcul.view.ArcMenu
        android:id="@+id/activity_main_arcmenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/composer_button_normal">

            <ImageView
                android:id="@+id/id_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/composer_button_normal" />
        </RelativeLayout>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/composer_camera"
            android:tag="Camera" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/composer_music"
            android:tag="Sun" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/composer_place"
            android:tag="Place" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/composer_sleep"
            android:tag="Sleep" />

    </com.yjcul.view.ArcMenu>

注:ArcMenu层的宽高需要设置为match_parent,不然会显示错误

第一个ImageView为中间按钮,下面的ImageView为点击后显示的菜单按钮

在activity中使用

ArcMenu arcMenu = findViewById(R.id.activity_main_arcmenu);

        arcMenu.setOnItemClickListener(new ArcMenu.OnItemClicklistener() {
            @Override
            public void onClick(View v, int position) {
                Log.e("tag", "点击了" + position + "----->" + v.getId());
            }
        });

还可以在代码中动态添加菜单按钮

ArcMenu arcMenu = findViewById(R.id.activity_main_arcmenu);

        ImageView imageView = new ImageView(this);
        imageView.setImageResource(R.drawable.composer_with);
        arcMenu.addView(imageView);

        arcMenu.setOnItemClickListener(new ArcMenu.OnItemClicklistener() {
            @Override
            public void onClick(View v, int position) {
                Log.e("tag", "点击了" + position + "----->" + v.getId());
            }
        });

猜你喜欢

转载自blog.csdn.net/pxcz110112/article/details/81165026