zoukankan      html  css  js  c++  java
  • 浮动菜单

    效果图: 

                     

    1、菜单栏类

      1 /**
      2  * 1.该控件必须包含3个及以上子控件
      3  * 2.第一个子控件表示浮动菜单的母菜单,剩余的作为浮动控件的子菜单
      4  * 3.子菜单和母菜单之间的距离可以修改 RADIUS 的值
      5  */
      6 public class FloatingMenu extends ViewGroup {
      7     // 子菜单和母菜单图标距离
      8     private final static int RADIUS = 400;
      9     // 当前菜单状态
     10     private MenuStatu currentStatu = MenuStatu.STATU_CLOSE;
     11 
     12     // 菜单状态枚举
     13     public enum MenuStatu {
     14         STATU_OPEN, STATU_CLOSE
     15     }
     16 
     17     /**
     18      * 子菜单被点击回调接口
     19      */
     20     public interface OnItemMenuClickListener {
     21         void onItemMenuClick(View view, int position);
     22     }
     23     // 子菜单被点击回调接口
     24     private OnItemMenuClickListener onItemMenuClickListener;
     25     public void setOnItemMenuClickListener(OnItemMenuClickListener onItemMenuClickListener) {
     26         this.onItemMenuClickListener = onItemMenuClickListener;
     27     }
     28     public FloatingMenu(Context context) {
     29         super(context);
     30     }
     31     public FloatingMenu(Context context, AttributeSet attrs) {
     32         super(context, attrs);
     33     }
     34     public FloatingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
     35         super(context, attrs, defStyleAttr);
     36     }
     37 
     38     @Override
     39     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     40         int childCount = getChildCount();
     41 
     42         if (childCount < 3)
     43             throw new IllegalStateException("当前控件的孩子控件至少需要3个");
     44 
     45         measureChildren(widthMeasureSpec, heightMeasureSpec);
     46         int tempWidth = getChildAt(1).getMeasuredWidth();
     47         int tempHeight = getChildAt(childCount - 1).getMeasuredHeight();
     48         setMeasuredDimension(RADIUS + tempWidth, RADIUS + tempHeight);
     49     }
     50 
     51     @Override
     52     protected void onLayout(boolean changed, int l, int t, int r, int b) {
     53         if (changed) {
     54             int measuredWidth = getMeasuredWidth();
     55             int measuredHeight = getMeasuredHeight();
     56             int childCount = getChildCount();
     57             // 计算每2个子菜单之间的角度值
     58             float averageAngle = 90 / (childCount - 1 - 1);
     59 
     60             for (int i = 0; i < childCount; i++) {
     61                 final View childAt = getChildAt(i);
     62                 int childWidth = childAt.getMeasuredWidth();
     63                 int childHeight = childAt.getMeasuredHeight();
     64 
     65                 // 第一个子控件是母菜单
     66                 if (i == 0) {
     67                     int left = measuredWidth - childWidth;
     68                     int top = measuredHeight - childHeight;
     69                     childAt.layout(left, top, measuredWidth, measuredHeight);
     70 
     71                     childAt.setOnClickListener(new OnClickListener() {
     72                         @Override
     73                         public void onClick(View v) {
     74                             changeStatuAnim(300);
     75                         }
     76                     });
     77                 } else { // 其余的为子菜单
     78                     final int temp = i;
     79                     // 计算每一个子菜单的位置
     80                     float calAngle = (i - 1) * averageAngle;
     81                     double centerX = RADIUS * Math.cos(Math.PI / 180 * calAngle);
     82                     double centerY = RADIUS * Math.sin(Math.PI / 180 * calAngle);
     83                     int left = (int) (measuredWidth - centerX - childWidth);
     84                     int top = (int) (measuredHeight - centerY - childHeight);
     85                     int right = (int) (measuredWidth - centerX);
     86                     int bottom = (int) (measuredHeight - centerY);
     87                     childAt.layout(left, top, right, bottom);
     88 
     89                     childAt.setVisibility(View.GONE);
     90 
     91                     childAt.setOnClickListener(new OnClickListener() {
     92                         @Override
     93                         public void onClick(View v) {
     94                             if (onItemMenuClickListener != null) {
     95                                 onItemMenuClickListener.onItemMenuClick(childAt, temp);
     96                             }
     97                             clickItemAnim(temp);
     98                         }
     99                     });
    100                 }
    101             }
    102         }
    103     }
    104 
    105     /**
    106      * 点击子菜单时的动画效果
    107      *
    108      * @param position
    109      */
    110     private void clickItemAnim(int position) {
    111         for (int i = 1; i < getChildCount(); i++) {
    112             View childAt = getChildAt(i);
    113             if (i == position) {
    114                 childAt.startAnimation(toBig());
    115             } else {
    116                 childAt.startAnimation(toSmall());
    117             }
    118             childAt.setVisibility(GONE);
    119         }
    120         changeStatu();
    121     }
    122 
    123     /**
    124      * 变小,变透明
    125      */
    126     private Animation toSmall() {
    127         AnimationSet animationSet = new AnimationSet(true);
    128         AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
    129         ScaleAnimation scaleAnimation = new ScaleAnimation(1, 0, 1, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    130         animationSet.setDuration(200);
    131         animationSet.addAnimation(alphaAnimation);
    132         animationSet.addAnimation(scaleAnimation);
    133         return animationSet;
    134     }
    135 
    136     /**
    137      * 变大,变透明
    138      *
    139      * @return
    140      */
    141     private Animation toBig() {
    142         AnimationSet animationSet = new AnimationSet(true);
    143         AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
    144         ScaleAnimation scaleAnimation = new ScaleAnimation(1, 3, 1, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    145         animationSet.setDuration(200);
    146         animationSet.addAnimation(alphaAnimation);
    147         animationSet.addAnimation(scaleAnimation);
    148         return animationSet;
    149     }
    150 
    151     /**
    152      * 子菜单状态改变动画效果
    153      *
    154      * @param durationMillis 动画执行时间
    155      */
    156     private void changeStatuAnim(int durationMillis) {
    157         int childCount = getChildCount();
    158         for (int i = 1; i < childCount; i++) {
    159             final View view = getChildAt(i);
    160 
    161             float jiao = 90 / (childCount - 1 - 1);
    162             float jiJiao = (i - 1) * jiao;
    163             float toX = (float) (RADIUS * Math.cos(Math.PI / 180 * jiJiao));
    164             float toY = (float) (RADIUS * Math.sin(Math.PI / 180 * jiJiao));
    165 
    166             AnimationSet animationSet = new AnimationSet(true);
    167             RotateAnimation rotateAnim = new RotateAnimation(
    168                     0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    169             TranslateAnimation translateAnimation;
    170             AlphaAnimation alphaAnimation;
    171             // 根据子菜单状态实现不同的动画效果
    172             if (!isOpen()) {
    173                 translateAnimation = new TranslateAnimation(toX, 0, toY, 0);
    174                 alphaAnimation = new AlphaAnimation(0, 1);
    175             } else {
    176                 translateAnimation = new TranslateAnimation(0, toX, 0, toY);
    177                 alphaAnimation = new AlphaAnimation(1, 0);
    178             }
    179 
    180             // 注意先添加旋转动画,再添加平移动画
    181             animationSet.addAnimation(rotateAnim);
    182             animationSet.addAnimation(translateAnimation);
    183             animationSet.addAnimation(alphaAnimation);
    184             animationSet.setDuration(durationMillis);
    185             animationSet.setAnimationListener(new Animation.AnimationListener() {
    186                 @Override
    187                 public void onAnimationStart(Animation animation) {
    188 
    189                 }
    190 
    191                 @Override
    192                 public void onAnimationEnd(Animation animation) {
    193                     if (currentStatu == MenuStatu.STATU_OPEN) {
    194                         view.setVisibility(View.VISIBLE);
    195                     } else {
    196                         view.setVisibility(View.GONE);
    197                     }
    198                 }
    199 
    200                 @Override
    201                 public void onAnimationRepeat(Animation animation) {
    202 
    203                 }
    204             });
    205             view.startAnimation(animationSet);
    206         }
    207         changeStatu();
    208     }
    209 
    210     /**
    211      * 改变状态
    212      */
    213     private void changeStatu() {
    214         currentStatu = (currentStatu == MenuStatu.STATU_OPEN) ? MenuStatu.STATU_CLOSE : MenuStatu.STATU_OPEN;
    215     }
    216 
    217     /**
    218      * 对外暴露的方法,关闭子菜单
    219      */
    220     public void closeMenu() {
    221         changeStatuAnim(300);
    222     }
    223 
    224     /**
    225      * 判断是否打开子菜单
    226      *
    227      * @return
    228      */
    229     public boolean isOpen() {
    230         return currentStatu == MenuStatu.STATU_OPEN;
    231     }
    232 }

     2、布局文件

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent">
     5 
     6     <com.example.dell.floatmenudemo.weight.FloatingMenu
     7         android:id="@+id/floating"
     8         android:layout_width="wrap_content"
     9         android:layout_height="wrap_content"
    10         android:layout_alignParentBottom="true"
    11         android:layout_alignParentRight="true"
    12         android:layout_marginBottom="50dp"
    13         android:layout_marginRight="50dp">
    14 
    15         <!--第一个子控件表示母菜单-->
    16         <ImageView
    17             android:id="@+id/imageViewSwitch"
    18             android:layout_width="wrap_content"
    19             android:layout_height="wrap_content"
    20             android:layout_alignParentLeft="true"
    21             android:layout_alignParentStart="true"
    22             android:layout_alignParentTop="true"
    23             android:src="@mipmap/ic_launcher" />
    24 
    25         <!--其余的控件表示子菜单-->
    26         <ImageView
    27             android:layout_width="wrap_content"
    28             android:layout_height="wrap_content"
    29             android:src="@mipmap/ic_launcher_round" />
    30 
    31         <ImageView
    32             android:layout_width="wrap_content"
    33             android:layout_height="wrap_content"
    34             android:src="@mipmap/ic_launcher_round" />
    35 
    36         <ImageView
    37             android:layout_width="wrap_content"
    38             android:layout_height="wrap_content"
    39             android:src="@mipmap/ic_launcher_round" />
    40 
    41         <ImageView
    42             android:layout_width="wrap_content"
    43             android:layout_height="wrap_content"
    44             android:src="@mipmap/ic_launcher_round" />
    45 
    46         <ImageView
    47             android:layout_width="wrap_content"
    48             android:layout_height="wrap_content"
    49             android:src="@mipmap/ic_launcher_round" />
    50 
    51         <ImageView
    52             android:layout_width="wrap_content"
    53             android:layout_height="wrap_content"
    54             android:src="@mipmap/ic_launcher_round" />
    55     </com.example.dell.floatmenudemo.weight.FloatingMenu>
    56 
    57 </RelativeLayout>

     3、 activity

     1 package com.example.dell.floatmenudemo;
     2 
     3 import android.os.Bundle;
     4 import android.support.v7.app.AppCompatActivity;
     5 import android.view.View;
     6 import android.widget.Toast;
     7 
     8 import com.example.dell.floatmenudemo.weight.FloatingMenu;
     9 public class MainActivity extends AppCompatActivity {
    10     private FloatingMenu floating;
    11     @Override
    12     protected void onCreate(Bundle savedInstanceState) {
    13         super.onCreate(savedInstanceState);
    14         setContentView(R.layout.activity_main);
    15         floating = (FloatingMenu) findViewById(R.id.floating);
    16         initFloatingMenu();
    17     }
    18     /**
    19      * 初始化浮动菜单控件
    20      */
    21     private void initFloatingMenu() {
    22         floating.setOnItemMenuClickListener(new FloatingMenu.OnItemMenuClickListener() {
    23             @Override
    24             public void onItemMenuClick(View view, int position) {
    25                 Toast.makeText(MainActivity.this, "子菜单 - " + position, Toast.LENGTH_SHORT).show();
    26             }
    27         });
    28     }
    29 }

     4、 还可以编写 横竖的菜单栏 ,效果如下:

                                                

    代码如下:

      1 package com.example.dell.floatmenudemo.weight;
      2 
      3 import android.content.Context;
      4 import android.graphics.Camera;
      5 import android.util.AttributeSet;
      6 import android.util.Log;
      7 import android.view.View;
      8 import android.view.ViewGroup;
      9 import android.view.animation.AlphaAnimation;
     10 import android.view.animation.Animation;
     11 import android.view.animation.AnimationSet;
     12 import android.view.animation.RotateAnimation;
     13 import android.view.animation.ScaleAnimation;
     14 import android.view.animation.TranslateAnimation;
     15 
     16 public  class  FloatingActionsMenu extends ViewGroup{
     17     private static final String TAG = "FloatingActionsMenu";
     18  //  子控件之间的距离
     19 public   final  static  int DISTANCE = 20;
     20  // 枚举 菜单栏的状态
     21 public  enum  MenuStatus{STATUS_OPEN,STATUS_CLOSE}
     22 // 当前状态
     23 private  MenuStatus currentStatus = MenuStatus.STATUS_CLOSE;
     24 // 子菜单点击回调接口
     25     public interface  OnItemMenuClickListener{
     26         void  onItemMenuClick(View view,int position);// 此方法内对点击作出响应,需实例化
     27 }
     28 //  调用接口封装到方法
     29     private  OnItemMenuClickListener onItemMenuClickListener;
     30     public void setOnItemMenuClickListener(OnItemMenuClickListener onItemMenuClickListener){
     31         this.onItemMenuClickListener = onItemMenuClickListener;
     32     }
     33     public FloatingActionsMenu(Context context) {
     34         super(context);
     35     }
     36     public FloatingActionsMenu(Context context, AttributeSet attrs) {
     37         super(context, attrs);
     38     }
     39 
     40         //计算 menu 大小
     41     @Override
     42     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     43             int childCount = getChildCount();
     44             if (childCount<3)throw  new IllegalStateException("当前控件至少需要三个子控件");
     45             measureChildren(widthMeasureSpec,heightMeasureSpec);
     46             int tempWidth = getChildAt(0).getMeasuredWidth();
     47             int tempHeight = getChildAt(0).getMeasuredHeight();
     48 
     49             setMeasuredDimension(tempWidth,(tempHeight+DISTANCE)*childCount);
     50     }
     51     // 计算控件位置
     52     //     changed   是否可以改变
     53     @Override
     54     protected void onLayout(boolean changed, int l, int t, int r, int b) {
     55         if(changed){
     56             int measureWidth  = getMeasuredWidth();
     57             int measureHeidth  = getMeasuredHeight();
     58             int childCount = getChildCount();
     59             for(int i = 0 ;i<childCount;i++){
     60                 final  View childAt = getChildAt(i);
     61                 int childWidth = childAt.getMeasuredWidth();
     62                 int childHeight = childAt.getMeasuredHeight();
     63                 // 第一个子控件是菜单栏开关
     64                 if (i==0){
     65                     int left = 0;
     66                     int top = (childCount-1-i)*(DISTANCE+childHeight);
     67                     int right = left+childWidth;
     68                     int bottom = top+childHeight;
     69                 childAt.layout(left,top,right,bottom);
     70                 childAt.setOnClickListener(new OnClickListener() {
     71                     @Override
     72                     public void onClick(View view) {
     73                         changeStatuAnim(300);
     74                     }
     75                 });
     76                 }else {
     77                     // 其余的为 子控件按钮
     78                     final  int temp = i;
     79                     int left = 0;
     80                     int top = (childCount-1-i)*(DISTANCE+childHeight);
     81                     int right = left+childWidth;
     82                     int bottom = top+childHeight;
     83                     childAt.layout(left,top,right,bottom);
     84                     childAt.setVisibility(View.GONE);
     85                     childAt.setOnClickListener(new OnClickListener() {
     86                         @Override
     87                         public void onClick(View view) {
     88                             if (onItemMenuClickListener!=null){
     89                                 onItemMenuClickListener.onItemMenuClick(childAt,temp);
     90                             }
     91                             clickItemAnim(temp);
     92                         }
     93                     });
     94                 }
     95             }
     96         }
     97     }
     98 
     99     /**
    100      *    点击子菜单时的动画效果
    101      */
    102     private void clickItemAnim(int position){
    103         for (int i=1;i<getChildCount();i++){
    104             View childAt = getChildAt(i);
    105             if (i==position){
    106 //                childAt.startAnimation(toBig());
    107                 childAt.startAnimation(rotateAroundY());// Y轴旋转
    108             }
    109             childAt.setVisibility(GONE);
    110         }
    111         changeStatu();
    112     }
    113 
    114     /**
    115      *   变小,变透明
    116      * @return
    117      */
    118     private Animation toSmall(){
    119         AnimationSet animationSet = new AnimationSet(true);
    120         AlphaAnimation alphaAnimation = new AlphaAnimation(1,0);// 透明
    121         animationSet.setDuration(200);// 200 毫秒
    122         animationSet.addAnimation(alphaAnimation);
    123         return  animationSet;
    124     }
    125     /**
    126      *    变大,变透明
    127      */
    128     private  Animation toBig(){
    129         AnimationSet animationSet = new AnimationSet(true);
    130         AlphaAnimation alphaAnimation = new AlphaAnimation(1,0);// 透明
    131         animationSet.addAnimation(alphaAnimation);
    132         ScaleAnimation scaleAnimation = new ScaleAnimation(1,3,1,3,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);// 变大
    133         animationSet.setDuration(200);// 200 毫秒
    134         return  animationSet;
    135     }
    136     /**
    137      *  绕Y 轴旋转
    138      */
    139     private  Animation rotateAroundY(){
    140           RotateToYAnimation rotateToYAnimation = new RotateToYAnimation();
    141           rotateToYAnimation.setRepeatCount(1);
    142           return  rotateToYAnimation;
    143     }
    144     /**
    145      *
    146      *    子菜单状态改变动画效果
    147      */
    148     private  void changeStatuAnim(int durationMillis){
    149         int childCount = getChildCount();
    150         for (int i = 0;i<childCount;i++){
    151             final View view = getChildAt(i);
    152             int toX = 0;
    153             int toY = (i-1)*view.getHeight()+DISTANCE*i;
    154             if (i==0){
    155                 //  do something
    156             }else {
    157 
    158                 AnimationSet animationSet = new AnimationSet(true);
    159                 animationSet.setDuration(300);
    160                 RotateAnimation rotateAnimation = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
    161                 TranslateAnimation translateAnimation;
    162                 AlphaAnimation alphaAnimation;
    163                 // 根据不同的子菜单状态实现不同的效果
    164                 if (!isopen()){
    165                     translateAnimation = new TranslateAnimation(toX,0,toY,0);
    166                     alphaAnimation = new AlphaAnimation(0,1);
    167 //                    currentStatus = MenuStatus.STATUS_OPEN;
    168                 }else {
    169                     translateAnimation = new TranslateAnimation(0,toX,0,toY);
    170                     alphaAnimation = new AlphaAnimation(1,0);
    171 //                    currentStatus = MenuStatus.STATUS_CLOSE;
    172 
    173                 }
    174                 //  先添加旋转 在添加 平移
    175                 animationSet.addAnimation(rotateAnimation);
    176                 animationSet.addAnimation(translateAnimation);
    177                 animationSet.addAnimation(alphaAnimation);
    178                 animationSet.setAnimationListener(new Animation.AnimationListener() {
    179                     @Override
    180                     public void onAnimationStart(Animation animation) {
    181 
    182                     }
    183 
    184                     @Override
    185                     public void onAnimationEnd(Animation animation) {
    186                         if (currentStatus == MenuStatus.STATUS_OPEN){
    187                             view.setVisibility(VISIBLE);
    188                         }else {
    189 
    190                             view.setVisibility(View.GONE);
    191                         }
    192                     }
    193                     @Override
    194                     public void onAnimationRepeat(Animation animation) {
    195 
    196                     }
    197                 });
    198                 view.startAnimation(animationSet);
    199             }
    200         }
    201         changeStatu();
    202     }
    203 /**
    204  *   改变状态
    205  */
    206     private  void  changeStatu(){
    207         currentStatus = (currentStatus== MenuStatus.STATUS_OPEN)?MenuStatus.STATUS_CLOSE:MenuStatus.STATUS_OPEN;
    208     }
    209 
    210     /**
    211      *   对外暴露的方法  关闭子菜单
    212      */
    213 
    214     public  void  closeMenu(){changeStatuAnim(300);}
    215     /**
    216      * 判断是否打开  子菜单
    217      */
    218     public  boolean isopen(){return  currentStatus==MenuStatus.STATUS_OPEN;}
     }

    其中用到 沿Y轴为轴旋转的动画,代码如下:

        

     1 package com.example.dell.floatmenudemo.weight;
     2 
     3 import android.graphics.Camera;
     4 import android.graphics.Matrix;
     5 import android.view.animation.Animation;
     6 import android.view.animation.DecelerateInterpolator;
     7 import android.view.animation.Transformation;
     8 
     9 /**
    10 
    11  调用代码
    12  RotateToYAnimation  rotateToYAnimation = new RotateToYAnimation();
    13  rotateToYAnimation.setRepeatCount(Animation.INFINITE); //翻转无数次
    14  view.startAnimation(rotateToYAnimation);
    15 
    16  */
    17 
    18 public class RotateToYAnimation extends Animation{
    19 private Camera camera = new Camera();
    20 private int centerX ;
    21 private int centerY;
    22 
    23     /**
    24      *   获取坐标  定义动画时间
    25      * @param width
    26      * @param height
    27      * @param parentWidth
    28      * @param parentHeight
    29      */
    30     @Override
    31     public void initialize(int width, int height, int parentWidth, int parentHeight) {
    32         super.initialize(width, height, parentWidth, parentHeight);
    33         // 获取中心点坐标
    34         centerX = width/2;
    35         centerY = width/2;
    36         //  动画执行时间
    37         setDuration(200);
    38         // 内插器
    39         setInterpolator(new DecelerateInterpolator());
    40     }
    41 
    42     /**
    43      *
    44      *    旋转角度
    45      * @param interpolatedTime
    46      * @param t
    47      */
    48     @Override
    49     protected void applyTransformation(float interpolatedTime, Transformation t) {
    50             final Matrix matrix = t.getMatrix();
    51             camera.save();
    52             //  旋转中心是Y轴  可自行设置
    53             camera.rotateY(360*interpolatedTime);
    54             //  把 摄像头  加在变换 矩阵上
    55         camera.getMatrix(matrix);
    56         //  设置翻转  中心点
    57         matrix.preTranslate(-centerX,centerY);
    58         matrix.postTranslate(centerX,centerY);
    59         camera.restore();
    60     }
    61 }
  • 相关阅读:
    51nod 1102 面积最大的矩形 (单调栈)
    Loj 6280 数列分块入门 4
    Loj 6279 数列分块入门 3
    python 自己写package 导入 attempted relative import beyond top-level package
    Python __pycache__ 含义
    Hive 中 null 和N 的处理
    【shell】 shell 敏捷开发
    RPC 讲解
    neo4j 应用
    【Linux】 查看CPU占用
  • 原文地址:https://www.cnblogs.com/the-wang/p/9061346.html
Copyright © 2011-2022 走看看