• 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 }

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

  • 相关阅读:
    cull/clip distance example
    Sutherland-Hodgeman多边形裁剪
    OpenCV 脸部跟踪(3)
    人脸识别中的Procruster analysis应用
    卡尔曼滤波的原理说明
    偏导数
    泊松分布E(X^2)
    抽奖概率
    卡尔曼滤波的原理说明
    卡尔曼滤波3
  • 原文地址:https://www.cnblogs.com/hankzhouAndroid/p/8998854.html
Copyright © 2020-2023  润新知