android-属性动画之 动态菜单按钮

废话不多说,先看效果:

这是菜单展开之前:

这是展开之后:

如果重复点击最左边的按钮,就会切换 "展开" 和 "收缩" 的状态。

===================================================

调用的代码如下(涉及到的图片资源,我就不上传了,这里只是说明这种效果的制作思路):

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.beautifulanimator.MyLinearLayout
        android:id="@+id/ml_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>
 1 package com.example.beautifulanimator;
 2 
 3 import android.os.Bundle;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.util.Log;
 6 import android.view.View;
 7 
 8 /**
 9  * 
10  */
11 public class MainActivity extends AppCompatActivity {
12 
13     private MyLinearLayout myLinearLayout;
14 
15     @Override
16     protected void onCreate(Bundle savedInstanceState) {
17         super.onCreate(savedInstanceState);
18         setContentView(R.layout.activity_main);
19 
20         myLinearLayout = findViewById(R.id.ml_menu);
21         myLinearLayout.preset(getResources().getDrawable(R.drawable.f6, null), lis01);// 预设3个按钮,指定它的图片和事件
22         myLinearLayout.preset(getResources().getDrawable(R.drawable.f3, null), lis02);
23         myLinearLayout.preset(getResources().getDrawable(R.drawable.f4, null), lis03);
24         myLinearLayout.initLayout(this, getResources().getDrawable(R.drawable.f1, null));
25     }
26 
27     View.OnClickListener lis01 = new View.OnClickListener() {
28         @Override
29         public void onClick(View v) {
30             Log.d("myLinearLayout", "click 01");
31         }
32     };
33 
34     View.OnClickListener lis02 = new View.OnClickListener() {
35         @Override
36         public void onClick(View v) {
37             Log.d("myLinearLayout", "click 01");
38         }
39     };
40 
41     View.OnClickListener lis03 = new View.OnClickListener() {
42         @Override
43         public void onClick(View v) {
44             Log.d("myLinearLayout", "click 01");
45         }
46     };
47 
48 }

------------------------------

然后展出自定义Layout的代码:

  1 package com.example.beautifulanimator;
  2 
  3 import android.animation.Animator;
  4 import android.animation.AnimatorListenerAdapter;
  5 import android.animation.AnimatorSet;
  6 import android.animation.ObjectAnimator;
  7 import android.content.Context;
  8 import android.graphics.drawable.Drawable;
  9 import android.support.annotation.Nullable;
 10 import android.util.AttributeSet;
 11 import android.util.Log;
 12 import android.view.View;
 13 import android.widget.ImageView;
 14 import android.widget.LinearLayout;
 15 
 16 import java.util.ArrayList;
 17 import java.util.List;
 18 
 19 public class MyLinearLayout extends LinearLayout {
 20 
 21     /****************************构造函数****************/
 22     public MyLinearLayout(Context context) {
 23         this(context, null);
 24     }
 25 
 26     public MyLinearLayout(Context context, @Nullable AttributeSet attrs) {
 27         this(context, attrs, 0);
 28     }
 29 
 30     public MyLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
 31         super(context, attrs, defStyleAttr);
 32         initLayoutParameters(context);
 33     }
 34 
 35     /****************************私有函数********************************/
 36     private void initLayoutParameters(Context context) {
 37         setOrientation(LinearLayout.HORIZONTAL);// 线性布局-横向
 38         setPadding(DensityUtil.dip2px(context, 10), DensityUtil.dip2px(context, 10),
 39                 DensityUtil.dip2px(context, 10), DensityUtil.dip2px(context, 10));
 40     }
 41 
 42     private ImageView iv_head;// 主按钮
 43     private float startDegree, endDegree;//开始旋转的角度以及结束的角度
 44     private List<View> childrenMenuIconList = new ArrayList<>();// 已经绘制好的子view
 45     private boolean ifMenuOpened = false;//菜单是否打开了
 46     private float startX, endX;
 47     private boolean ifAnimateOver = true;//动画是否执行完毕(未完毕期间不接受点击事件)
 48     private int animationDuration = 300;// 动画执行的时长
 49 
 50     /**
 51      * 旋转主按钮
 52      *
 53      * @param iv_01
 54      */
 55     private void rotateMenuIcon(ImageView iv_01) {
 56         if (ifMenuOpened) {
 57             startDegree = 90;
 58             endDegree = 0;
 59         } else {
 60             startDegree = 0;
 61             endDegree = 90;
 62         }
 63 
 64         ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv_01, "rotation", startDegree, endDegree);
 65         objectAnimator.setDuration(animationDuration);
 66         objectAnimator.start();
 67     }
 68 
 69     private void setIfAnimateOver(boolean temp) {
 70         ifAnimateOver = temp;
 71     }
 72 
 73     /**
 74      * 绘制子menu
 75      */
 76     private void drawChildMenuIcon(Context context, Drawable drawable, View.OnClickListener listener) {
 77         setIfAnimateOver(false);
 78         AnimatorSet animatorSet = new AnimatorSet();
 79         final ImageView iv_menu = new ImageView(context);
 80         iv_menu.setOnClickListener(listener);
 81         iv_menu.setImageDrawable(drawable);
 82         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
 83                 LinearLayout.LayoutParams.WRAP_CONTENT);//宽高自适应
 84         layoutParams.width = DensityUtil.dip2px(context, 60);
 85         layoutParams.height = DensityUtil.dip2px(context, 60);
 86         addView(iv_menu, layoutParams);
 87         childrenMenuIconList.add(iv_menu);
 88 
 89         //我需要的是横向的起始X和终点X
 90         startX = -layoutParams.width;
 91         endX = 0;
 92 
 93         //ObjectAnimator 的 value参数,它这里有个坑,如果你是想让它慢慢显示,必须写0,1,而不能只写1.
 94         //但是如果需要让它慢慢隐藏,可以只写0
 95         ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(iv_menu, "alpha", 0, 1);
 96         objectAnimator2.setDuration(animationDuration);
 97         ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv_menu, "translationX", startX, endX);
 98         objectAnimator.setDuration(animationDuration);
 99 
100         animatorSet.playTogether(objectAnimator2, objectAnimator);//同时执行
101         animatorSet.addListener(new AnimatorListenerAdapter() {
102             @Override
103             public void onAnimationEnd(Animator animation) {
104                 super.onAnimationEnd(animation);
105                 setIfAnimateOver(true);
106             }
107         });
108         animatorSet.start();
109         Log.d("iv_menu", "click lis end");
110     }
111 
112     private List<Animator> listAnimator = new ArrayList<>();
113 
114     private void hideChildMenu() {
115         listAnimator.clear();
116         setIfAnimateOver(false);
117         for (final View v : childrenMenuIconList) {
118             ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(v, "translationX", endX, startX);
119             objectAnimator.setDuration(animationDuration);
120             objectAnimator.addListener(new AnimatorListenerAdapter() {
121                 @Override
122                 public void onAnimationEnd(Animator animation) {
123                     super.onAnimationEnd(animation);
124                     Log.d("hideChildMenu", "" + v.getHeight() + "-" + v.getWidth());
125                     removeView(v);
126                 }
127             });
128             listAnimator.add(objectAnimator);
129 
130             objectAnimator = ObjectAnimator.ofFloat(v, "alpha", 0);
131             objectAnimator.setDuration(animationDuration);
132             listAnimator.add(objectAnimator);
133         }
134 
135         AnimatorSet animatorSet = new AnimatorSet();
136         animatorSet.playTogether(listAnimator);
137         animatorSet.addListener(new AnimatorListenerAdapter() {
138             @Override
139             public void onAnimationEnd(Animator animation) {
140                 super.onAnimationEnd(animation);
141                 setIfAnimateOver(true);
142             }
143         });
144         animatorSet.start();
145         childrenMenuIconList.clear();//最后将childrenList清空
146     }
147 
148     /*******************************辅助内部类***************************************/
149     private List<DrawLis> drawLisList = new ArrayList<>();//即将绘制的view的相关参数
150 
151     class DrawLis {
152         Drawable drawable;
153         View.OnClickListener listener;
154 
155         DrawLis(Drawable drawableT, View.OnClickListener listenerT) {
156             drawable = drawableT;
157             listener = listenerT;
158         }
159     }
160     /****************************公开接口********************************/
161     /**
162      * 新增一个按钮以及一个监听
163      *
164      * @param drawable
165      * @param listener
166      */
167     public void preset(Drawable drawable, View.OnClickListener listener) {
168         drawLisList.add(new DrawLis(drawable, listener));
169     }
170 
171     public void initLayout(final Context context, Drawable drawable) {
172         iv_head = new ImageView(context);
173         iv_head.setScaleType(ImageView.ScaleType.CENTER_INSIDE);//设置等比例缩放,不会改变原图的纵横比
174         iv_head.setImageDrawable(drawable);
175         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
176         params.width = DensityUtil.dip2px(context, 60);//设置为60dp宽
177         params.height = DensityUtil.dip2px(context, 60);//设置为60dp高
178         addView(iv_head, params);//将主按钮加入布局
179 
180         iv_head.setOnClickListener(new OnClickListener() {
181             @Override
182             public void onClick(View v) {
183                 // 它的点击事件,点击之后,展开其他3个按钮
184                 if (ifAnimateOver)//如果动画执行完毕了,那就可以进行下面的操作
185                 {
186                     rotateMenuIcon(iv_head);// 让主按钮产生旋转效果
187                     if (!ifMenuOpened) {
188                         for (DrawLis lis : drawLisList) {
189                             drawChildMenuIcon(context, lis.drawable, lis.listener);//逐一添加child
190                         }
191                         ifMenuOpened = true;
192                     } else {
193                         hideChildMenu();
194                         ifMenuOpened = false;
195                     }
196                 }
197             }
198         });
199     }
200 
201 }

还有一个辅助类,用户转化dp和px:

 1 package com.example.beautifulanimator;
 2 
 3 import android.content.Context;
 4 
 5 public class DensityUtil {
 6 
 7     /**
 8      * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
 9      *
10      * @param context
11      * @param dpValue
12      * @return
13      * @date   2015年10月28日
14      */
15     public static int dip2px(Context context, float dpValue) {
16         final float scale = context.getResources().getDisplayMetrics().density;
17         return (int) (dpValue * scale + 0.5f);
18     }
19 
20     /**
21      * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
22      *
23      * @param context
24      * @param pxValue
25      * @return
26      * @date   2015年10月28日
27      */
28     public static int px2dip(Context context, float pxValue) {
29         final float scale = context.getResources().getDisplayMetrics().density;
30         return (int) (pxValue / scale + 0.5f);
31     }
32 }

关键代码已经加了注释。欢迎各位大佬留言讨论。

posted @ 2018-05-06 17:19  波澜不惊x  阅读(1174)  评论(0编辑  收藏  举报