在android开发中卫星菜单栏比较常用,而且不失为一个比较炫的而且简单实现的自定义控件
下面开始实现功能,ok~首先先来看要实现的功能:
1.点击主菜单按钮 按钮旋转360 子菜单按钮菜单展开
2.在展开状态下点击主菜单,然后子菜单合拢
3.子菜单按钮会有旋转,平移,渐变动画
4.在展开状态下,点击子菜单按钮,被点击按钮放大消,其他没有被点击的子菜单消失
5.在demo中添加listView,如果菜单为展开状态,滑动listViewh会自动合拢
6.主菜单和子菜单布局在代码中做了判单,在左上,左下,右上,右下都不会影响效果,有需求 可以检测
下面来看效果图:
功能和效果介绍完之后开始详细解析代码:
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~ 就到这里了 期待共同进步;