结合各位大佬的文章整理的
自定义菜单
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());
}
});