代码分析Android实现侧滑菜单

作者:mrr 时间:2022-04-02 16:38:45 

Android 侧滑菜单的实现,参考网上的代码,实现侧滑菜单。最重要的是这个动画类UgcAnimations,如何使用动画类来侧滑的封装FlipperLayout。

1、实现效果

代码分析Android实现侧滑菜单

2、动画类UgcAnimations


package com.mmsx.base;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;

/**
* Pat * 类
*
*/
public class UgcAnimations {
 private static int xOffset = 15;
 private static int yOffset = -13;

public static void initOffset(Context context) {
   xOffset = (int) (15 * context.getResources().getDisplayMetrics().density);
   yOffset = -(int) (13 * context.getResources().getDisplayMetrics().density);
 }

public static Animation getRotateAnimation(float fromDegrees,
     float toDegrees, long durationMillis) {
   RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,
       Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
       0.5f);
   rotate.setDuration(durationMillis);
   rotate.setFillAfter(true);
   return rotate;
 }

public static Animation getAlphaAnimation(float fromAlpha, float toAlpha,
     long durationMillis) {
   AlphaAnimation alpha = new AlphaAnimation(fromAlpha, toAlpha);
   alpha.setDuration(durationMillis);
   alpha.setFillAfter(true);
   return alpha;
 }

public static Animation getScaleAnimation(long durationMillis) {
   ScaleAnimation scale = new ScaleAnimation(1.0f, 1.5f, 1.0f, 1.5f,
       Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
       0.5f);
   scale.setDuration(durationMillis);
   return scale;
 }

public static Animation getTranslateAnimation(float fromXDelta,
     float toXDelta, float fromYDelta, float toYDelta,
     long durationMillis) {
   TranslateAnimation translate = new TranslateAnimation(fromXDelta,
       toXDelta, fromYDelta, toYDelta);
   translate.setDuration(durationMillis);
   translate.setFillAfter(true);
   return translate;
 }

public static void startOpenAnimation(RelativeLayout relativeLayout,
     ImageView background, ImageView menu, long durationMillis) {
   background.setVisibility(View.VISIBLE);
   relativeLayout.setVisibility(View.VISIBLE);
   background.startAnimation(getAlphaAnimation(0f, 1f, durationMillis));
   menu.startAnimation(getRotateAnimation(0, 90, durationMillis));
   for (int i = 0; i < relativeLayout.getChildCount(); i++) {
     ImageView imageView = (ImageView) relativeLayout.getChildAt(i);
     imageView.setVisibility(View.VISIBLE);
     MarginLayoutParams params = (MarginLayoutParams) imageView
         .getLayoutParams();
     AnimationSet set = new AnimationSet(true);
     set.addAnimation(getRotateAnimation(-270, 0, durationMillis));
     set.addAnimation(getAlphaAnimation(0.5f, 1.0f, durationMillis));
     set.addAnimation(getTranslateAnimation(
         -params.leftMargin + xOffset, 0f, params.bottomMargin
             + yOffset, 0f, durationMillis));
     set.setFillAfter(true);
     set.setDuration(durationMillis);
     set.setStartOffset((i * 100)
         / (-1 + relativeLayout.getChildCount()));
     set.setInterpolator(new OvershootInterpolator(1f));
     imageView.startAnimation(set);
   }
 }
 public static void startCloseAnimation(final RelativeLayout relativeLayout,
     final ImageView background, ImageView menu, long durationMillis) {
   background.startAnimation(getAlphaAnimation(1f, 0f, durationMillis));
   menu.startAnimation(getRotateAnimation(90, 0, durationMillis));
   for (int i = 0; i < relativeLayout.getChildCount(); i++) {
     final ImageView imageView = (ImageView) relativeLayout
         .getChildAt(i);
     MarginLayoutParams params = (MarginLayoutParams) imageView
         .getLayoutParams();
     AnimationSet set = new AnimationSet(true);
     set.addAnimation(getRotateAnimation(0, -270, durationMillis));
     set.addAnimation(getAlphaAnimation(1.0f, 0.5f, durationMillis));
     set.addAnimation(getTranslateAnimation(0f, -params.leftMargin
         + xOffset, 0f, params.bottomMargin + yOffset,
         durationMillis));
     set.setFillAfter(true);
     set.setDuration(durationMillis);
     set.setStartOffset(((relativeLayout.getChildCount() - i) * 100)
         / (-1 + relativeLayout.getChildCount()));
     set.setInterpolator(new AnticipateInterpolator(1f));
     set.setAnimationListener(new Animation.AnimationListener() {
       public void onAnimationStart(Animation arg0) {
       }
       public void onAnimationRepeat(Animation arg0) {
       }
       public void onAnimationEnd(Animation arg0) {
         relativeLayout.setVisibility(View.GONE);
         background.setVisibility(View.GONE);
       }
     });
     imageView.startAnimation(set);
   }
 }
 public static Animation clickAnimation(long durationMillis) {
   AnimationSet set = new AnimationSet(true);
   set.addAnimation(getAlphaAnimation(1.0f, 0.3f, durationMillis));
   set.addAnimation(getScaleAnimation(durationMillis));
   set.setDuration(durationMillis);
   return set;
 }
}

3、封装使用动画类FlipperLayout


package com.mmsx.base;
import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

/**
* 自己重写的ViewGroup,用与滑动切换界面使用,代码不详解,慢点看的话应该能看懂的...
*/
public class FlipperLayout extends ViewGroup {

private Scroller mScroller;
 private VelocityTracker mVelocityTracker;
 private int mWidth;

public static final int SCREEN_STATE_CLOSE = 0;
 public static final int SCREEN_STATE_OPEN = 1;
 public static final int TOUCH_STATE_RESTART = 0;
 public static final int TOUCH_STATE_SCROLLING = 1;
 public static final int SCROLL_STATE_NO_ALLOW = 0;
 public static final int SCROLL_STATE_ALLOW = 1;
 private int mScreenState = 0;
 private int mTouchState = 0;
 private int mScrollState = 0;
 private int mVelocityValue = 0;
 private boolean mOnClick = false;
 private onUgcDismissListener mOnUgcDismissListener;
 private onUgcShowListener mOnUgcShowListener;

public FlipperLayout(Context context) {
   super(context);
   mScroller = new Scroller(context);
   mWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
       54, getResources().getDisplayMetrics());

}

public FlipperLayout(Context context, AttributeSet attrs, int defStyle) {
   super(context, attrs, defStyle);
 }

public FlipperLayout(Context context, AttributeSet attrs) {
   super(context, attrs);
 }

protected void onLayout(boolean changed, int l, int t, int r, int b) {
   for (int i = 0; i < getChildCount(); i++) {
     View child = getChildAt(i);
     int height = child.getMeasuredHeight();
     int width = child.getMeasuredWidth();
     child.layout(0, 0, width, height);
   }
 }

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   int width = MeasureSpec.getSize(widthMeasureSpec);
   int height = MeasureSpec.getSize(heightMeasureSpec);
   setMeasuredDimension(width, height);
   for (int i = 0; i < getChildCount(); i++) {
     getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
   }
 }

public boolean dispatchTouchEvent(MotionEvent ev) {
   obtainVelocityTracker(ev);
   switch (ev.getAction()) {
   case MotionEvent.ACTION_DOWN:
     mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
         : TOUCH_STATE_SCROLLING;
     if (mTouchState == TOUCH_STATE_RESTART) {
       int x = (int) ev.getX();
       int screenWidth = getWidth();
       if (x <= mWidth && mScreenState == SCREEN_STATE_CLOSE
           && mTouchState == TOUCH_STATE_RESTART
           || x >= screenWidth - mWidth
           && mScreenState == SCREEN_STATE_OPEN
           && mTouchState == TOUCH_STATE_RESTART) {
         if (mScreenState == SCREEN_STATE_OPEN) {
           mOnClick = true;
         }
         mScrollState = SCROLL_STATE_ALLOW;
       } else {
         mOnClick = false;
         mScrollState = SCROLL_STATE_NO_ALLOW;
       }
     } else {
       return false;
     }
     break;
   case MotionEvent.ACTION_MOVE:
     mVelocityTracker.computeCurrentVelocity(1000,
         ViewConfiguration.getMaximumFlingVelocity());
     if (mScrollState == SCROLL_STATE_ALLOW
         && getWidth() - (int) ev.getX() < mWidth) {
       return true;
     }
     break;
   case MotionEvent.ACTION_UP:
     releaseVelocityTracker();
     if (mOnClick) {
       mOnClick = false;
       mScreenState = SCREEN_STATE_CLOSE;
       mScroller.startScroll(getChildAt(1).getScrollX(), 0,
           -getChildAt(1).getScrollX(), 0, 800);
       invalidate();
     }
     break;
   }
   return super.dispatchTouchEvent(ev);
 }

public boolean onInterceptTouchEvent(MotionEvent ev) {
   obtainVelocityTracker(ev);
   switch (ev.getAction()) {
   case MotionEvent.ACTION_DOWN:
     mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
         : TOUCH_STATE_SCROLLING;
     if (mTouchState == TOUCH_STATE_SCROLLING) {
       return false;
     }
     break;

case MotionEvent.ACTION_MOVE:
     mOnClick = false;
     mVelocityTracker.computeCurrentVelocity(1000,
         ViewConfiguration.getMaximumFlingVelocity());
     if (mScrollState == SCROLL_STATE_ALLOW
         && Math.abs(mVelocityTracker.getXVelocity()) > 200) {
       return true;
     }
     break;

case MotionEvent.ACTION_UP:
     releaseVelocityTracker();
     if (mScrollState == SCROLL_STATE_ALLOW
         && mScreenState == SCREEN_STATE_OPEN) {
       return true;
     }
     break;
   }
   return super.onInterceptTouchEvent(ev);
 }

public boolean onTouchEvent(MotionEvent event) {
   obtainVelocityTracker(event);
   switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
     mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
         : TOUCH_STATE_SCROLLING;
     if (mTouchState == TOUCH_STATE_SCROLLING) {
       return false;
     }
     break;

case MotionEvent.ACTION_MOVE:
     mVelocityTracker.computeCurrentVelocity(1000,
         ViewConfiguration.getMaximumFlingVelocity());
     mVelocityValue = (int) mVelocityTracker.getXVelocity();
     getChildAt(1).scrollTo(-(int) event.getX(), 0);
     break;

case MotionEvent.ACTION_UP:
     if (mScrollState == SCROLL_STATE_ALLOW) {
       if (mVelocityValue > 2000) {
         mScreenState = SCREEN_STATE_OPEN;
         mScroller
             .startScroll(
                 getChildAt(1).getScrollX(),
                 0,
                 -(getWidth()
                     - Math.abs(getChildAt(1)
                         .getScrollX()) -

mWidth), 0, 250);
         invalidate();

} else if (mVelocityValue < -2000) {
         mScreenState = SCREEN_STATE_CLOSE;
         mScroller.startScroll(getChildAt(1).getScrollX(), 0,
             -getChildAt(1).getScrollX(), 0, 250);
         invalidate();
       } else if (event.getX() < getWidth() / 2) {
         mScreenState = SCREEN_STATE_CLOSE;
         mScroller.startScroll(getChildAt(1).getScrollX(), 0,
             -getChildAt(1).getScrollX(), 0, 800);
         invalidate();
       } else {
         mScreenState = SCREEN_STATE_OPEN;
         mScroller
             .startScroll(
                 getChildAt(1).getScrollX(),
                 0,
                 -(getWidth()
                     - Math.abs(getChildAt(1)
                         .getScrollX()) -

mWidth), 0, 800);
         invalidate();
       }
     }
     break;
   }
   return super.onTouchEvent(event);
 }

public void open() {
   mTouchState = mScroller.isFinished() ? TOUCH_STATE_RESTART
       : TOUCH_STATE_SCROLLING;
   if (mTouchState == TOUCH_STATE_RESTART) {
     mScreenState = SCREEN_STATE_OPEN;
     mScroller.startScroll(getChildAt(1).getScrollX(), 0, -(getWidth()
         - Math.abs(getChildAt(1).getScrollX()) -

mWidth), 0, 800);
     invalidate();
   }
 }

//关闭当前的侧滑菜单,用view打开点击事件的页面
 public void close(View view) {
   mScreenState = SCREEN_STATE_CLOSE;
   mScroller.startScroll(getChildAt(1).getScrollX(), 0, -getChildAt(1)
       .getScrollX(), 0, 800);
   invalidate();
   setContentView(view);
 }

public void computeScroll() {
   super.computeScroll();
   if (mScroller.computeScrollOffset()) {
     getChildAt(1).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
     postInvalidate();
   } else {
     if (mScreenState == SCREEN_STATE_OPEN) {
       if (mOnUgcDismissListener != null) {
         mOnUgcDismissListener.dismiss();
       }
     } else if (mScreenState == SCREEN_STATE_CLOSE) {
       if (mOnUgcShowListener != null) {
         mOnUgcShowListener.show();
       }
     }
   }
 }
 private void obtainVelocityTracker(MotionEvent event) {
   if (mVelocityTracker == null) {
     mVelocityTracker = VelocityTracker.obtain();
   }
   mVelocityTracker.addMovement(event);
 }
 private void releaseVelocityTracker() {
   if (mVelocityTracker != null) {
     mVelocityTracker.recycle();
     mVelocityTracker = null;
   }
 }
 public int getScreenState() {
   return mScreenState;
 }
 public void setContentView(View view) {
   removeViewAt(1);
   addView(view, 1, getLayoutParams());
 }
 public interface OnOpenListener {
   public abstract void open();
 }
 public interface OnCloseListener {
   public abstract void close();
 }
 public interface onUgcDismissListener {
   public abstract void dismiss();
 }
 public interface onUgcShowListener {
   public abstract void show();
 }
 public void setOnUgcDismissListener(
     onUgcDismissListener onUgcDismissListener) {
   mOnUgcDismissListener = onUgcDismissListener;
 }
 public void setOnUgcShowListener(onUgcShowListener onUgcShowListener) {
   mOnUgcShowListener = onUgcShowListener;
 }
}

4、主界面MainActivity


package com.mmsx.activity;  
import com.mmsx.activity.SideslipMenu.onChangeViewListener;
import com.mmsx.activity.SideslipOther.onDataListener;
import com.mmsx.base.FlipperLayout;
import com.mmsx.base.FlipperLayout.OnOpenListener;
import com.mmsx.base.ViewUtil;
import android.os.Bundle;
import android.app.Activity;
import android.view.ViewGroup.LayoutParams;
import android.widget.Toast;

public class MainActivity extends Activity implements OnOpenListener{

//侧滑主要控制类,设置跟布局
 private FlipperLayout mRoot;
 //侧滑的默认界面,主界面
 private SideslipHome mHome;
 //侧滑的菜单,进行选择的
 private SideslipMenu mSideslipMenu;
 //其他菜单列表选择的效果
 private SideslipOther mOther;
 //退出时间间隔变量
 private long mExitTime;
 //时间间隔2s
 private static final int INTERVAL = 2000;
 //侧滑菜单选中的item
 private int mViewPosition;
 //侧滑传递的标题
 private String mstrTitle;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
    //创建容器,并设置全屏大小
   mRoot = new FlipperLayout(this);
   //布局的参数
   LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,
       LayoutParams.FILL_PARENT);
   mRoot.setLayoutParams(params);
   //创建菜单界面和内容首页界面,并添加到容器中,用于初始显示
   mHome = new SideslipHome(this, this);
   mSideslipMenu = new SideslipMenu(this);
   mRoot.addView(mSideslipMenu.getView(), params);
   mRoot.addView(mHome.getView(), params);
   //设置跟布局
   setContentView(mRoot);
   //设置监听
   setListener();
 }

//设置监听
 private void setListener() {
   mHome.setOnOpenListener(this);
    //监听菜单界面切换显示内容(onChangeViewListener接口在SideslipMenu中定义)
   mSideslipMenu.setOnChangeViewListener(new onChangeViewListener() {

public void onChangeView(int arg0) {
       mViewPosition = arg0;
       mOther = new SideslipOther(MainActivity.this);
       switch (arg0) {
       case ViewUtil.HOME:
         mRoot.close(mHome.getView());
         break;
       case ViewUtil.MESSAGE:
         mstrTitle = "消息";
         //设置数据接口监听
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       case ViewUtil.FRIENDS:
         mstrTitle = "好友";
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       case ViewUtil.PHOTO:
         mstrTitle = "照片";
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       case ViewUtil.VIEWED:
         mstrTitle = "转帖";
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       case ViewUtil.GIFTS:
         mstrTitle = "礼物";
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       case ViewUtil.RECOMMEND:
         mstrTitle = "游戏";
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       case ViewUtil.LBS:
         mstrTitle = "附近 ";
         mOther.setDataTitle(new DataTitle());
         mRoot.close(mOther.getView());
         break;
       default:
         break;
       }
     }
   });
 }

//传递数据到侧滑选中的页面
 private class DataTitle implements onDataListener{
   @Override
   public String getDataTitle() {
     return mstrTitle;
   }

}

@Override
 public void open() {
   if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_CLOSE) {
     mRoot.open();
   }
 }

/**
  * 返回键监听
  */
 public void onBackPressed() {
   /**
    * 如果界面的path菜单没有关闭时,先将path菜单关闭,否则则判断两次返回时间间隔,小于两秒则退出程序
    */
   if (mRoot.getScreenState() == FlipperLayout.SCREEN_STATE_OPEN) {
     if (mSideslipMenu.getUgcIsShowing()) {
       mSideslipMenu.closeUgc();
     } else {
       exit();
     }
   } else {
     switch (mViewPosition) {
     case ViewUtil.HOME:
       if (mHome.getUgcIsShowing()) {
         mHome.closeUgc();
       } else {
         exit();
       }
       break;
     default:
       exit();
       break;
     }

}

}  
 /**
  * 判断两次返回时间间隔,小于两秒则退出程序
  */
 private void exit() {
   if (System.currentTimeMillis() - mExitTime > INTERVAL) {
     Toast.makeText(this, "再按一次返回键,可直接退出程序", Toast.LENGTH_SHORT).show();
     mExitTime = System.currentTimeMillis();
   } else {
     finish();
     android.os.Process.killProcess(android.os.Process.myPid());
     System.exit(0);
   }
 }
}

5、SideslipHome


package com.mmsx.activity;
import com.mmsx.base.FlipperLayout.OnOpenListener;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class SideslipHome {
 private Context mContext;
 private Activity mActivity;
 private View mHomeView;
 private boolean mUgcIsShowing = false;  
 private OnOpenListener mOnOpenListener;
 public SideslipHome(Context context, Activity activity) {
   mContext = context;
   mActivity = activity;
   mHomeView = LayoutInflater.from(context).inflate(R.layout.sideslip_home, null);

initUI();
 }

private void initUI() {
   TextView ivTitleName = (TextView)mHomeView.findViewById(R.id.ivTitleName);  
   ivTitleName.setText("主页动态");

}

public void setOnOpenListener(OnOpenListener onOpenListener) {
   mOnOpenListener = onOpenListener;
 }

public View getView() {
   return mHomeView;
 }

/**
  * 获取Path菜单显示状态
  */
 public boolean getUgcIsShowing() {
   return mUgcIsShowing;
 }

/**
  * 关闭Path菜单
  */
 public void closeUgc() {
   mUgcIsShowing = false;
 }

}

好了,以上就是本文的全部叙述,希望大家喜欢。

标签:Android,侧滑菜单
0
投稿

猜你喜欢

  • Java如何使用HTTPclient访问url获得数据

    2023-11-12 04:16:21
  • C语言转义字符实例详解

    2021-08-23 02:12:20
  • zookeeper watch机制的理解

    2021-11-08 11:36:36
  • Java并发包之CopyOnWriteArrayList类的深入讲解

    2022-10-06 09:15:21
  • 详解Winform里面的缓存使用

    2022-07-22 21:16:32
  • 手把手教你SpringBoot快速集成Swagger的配置过程

    2023-10-30 01:16:22
  • idea乱码修改bin目录下的idea.exe.vmoptions无效问题

    2022-08-02 19:17:55
  • SpringBoot如何接收Post请求Body里面的参数

    2023-07-30 13:43:35
  • java发送http请求并获取状态码的简单实例

    2023-12-06 00:59:14
  • 有关微博content的封装实现详解

    2022-12-02 17:37:53
  • java实现文件压缩成zip的工具类

    2022-09-25 09:13:17
  • 通过spring注解开发,简单测试单例和多例区别

    2023-11-06 09:18:31
  • java map中相同的key保存多个value值方式

    2022-12-12 20:05:45
  • Java文件操作之IO流 File类的使用详解

    2023-07-26 00:49:41
  • SpringBoot如何在运行时动态添加数据源

    2023-11-13 21:36:40
  • OpenGL绘制贝塞尔曲线

    2022-02-28 11:51:57
  • JavaWeb入门教程之分页查询功能的简单实现

    2021-11-11 21:52:23
  • Python基础教程学习笔记 第一章 基础知识

    2023-12-28 17:45:56
  • C++实现哈夫曼树编码解码

    2022-02-13 15:48:09
  • Java Set集合的遍历及实现类的比较

    2023-11-05 16:08:10
  • asp之家 软件编程 m.aspxhome.com