Android仿QQ5.0侧滑菜单ResideMenu源码分析

简介:

转自:http://blog.csdn.net/cym492224103/article/details/39177275

AndroidResideMenu

github:https://github.com/SpecialCyCi/AndroidResideMenu  csdn:http://download.csdn.net/detail/cym492224103/7887801

先看看如何使用:

把项目源码下载下来导入工程,可以看到


ResideMenu为引用工程,再看看如何使用这个引用工程来构建出ResideMenu,

1.先new一个ResideMenu对象

[java]  view plain copy print ?
  1. resideMenu = new ResideMenu(this);  
2.设置它的背景图片

[java]  view plain copy print ?
  1. resideMenu.setBackground(R.drawable.menu_background);  
3.绑定当前Activity

[java]  view plain copy print ?
  1. resideMenu.attachToActivity(this);  
4.设置监听

[java]  view plain copy print ?
  1. resideMenu.setMenuListener(menuListener);  
可以监听菜单打开和关闭状态

[java]  view plain copy print ?
  1. private ResideMenu.OnMenuListener menuListener = new ResideMenu.OnMenuListener() {  
  2.     @Override  
  3.     public void openMenu() {  
  4.         Toast.makeText(mContext, "Menu is opened!", Toast.LENGTH_SHORT).show();  
  5.     }  
  6.   
  7.     @Override  
  8.     public void closeMenu() {  
  9.         Toast.makeText(mContext, "Menu is closed!", Toast.LENGTH_SHORT).show();  
  10.     }  
  11. };  
5.设置内容缩放比例(0.1~1f)

[java]  view plain copy print ?
  1. //valid scale factor is between 0.0f and 1.0f. leftmenu'width is 150dip.   
  2.         resideMenu.setScaleValue(0.6f);  
6.创建子菜单

[java]  view plain copy print ?
  1. // create menu items;  
  2.        itemHome     = new ResideMenuItem(this, R.drawable.icon_home,     "Home");  
  3.        itemProfile  = new ResideMenuItem(this, R.drawable.icon_profile,  "Profile");  
  4.        itemCalendar = new ResideMenuItem(this, R.drawable.icon_calendar, "Calendar");  
  5.        itemSettings = new ResideMenuItem(this, R.drawable.icon_settings, "Settings");  
7.设置点击事件及将刚创建的子菜单添加到侧换菜单中(可以看到它是通过常量来控制子菜单的添加位置)

[java]  view plain copy print ?
  1. itemHome.setOnClickListener(this);  
  2.         itemProfile.setOnClickListener(this);  
  3.         itemCalendar.setOnClickListener(this);  
  4.         itemSettings.setOnClickListener(this);  
  5.   
  6.         resideMenu.addMenuItem(itemHome, ResideMenu.DIRECTION_LEFT);  
  7.         resideMenu.addMenuItem(itemProfile, ResideMenu.DIRECTION_LEFT);  
  8.         resideMenu.addMenuItem(itemCalendar, ResideMenu.DIRECTION_RIGHT);  
  9.         resideMenu.addMenuItem(itemSettings, ResideMenu.DIRECTION_RIGHT);  
8.设置title按钮的点击事件,设置左右菜单的开关

[java]  view plain copy print ?
  1. // You can disable a direction by setting ->  
  2.         // resideMenu.setSwipeDirectionDisable(ResideMenu.DIRECTION_RIGHT);  
  3.   
  4.         findViewById(R.id.title_bar_left_menu).setOnClickListener(new View.OnClickListener() {  
  5.             @Override  
  6.             public void onClick(View view) {  
  7.                 resideMenu.openMenu(ResideMenu.DIRECTION_LEFT);  
  8.             }  
  9.         });  
  10.         findViewById(R.id.title_bar_right_menu).setOnClickListener(new View.OnClickListener() {  
  11.             @Override  
  12.             public void onClick(View view) {  
  13.                 resideMenu.openMenu(ResideMenu.DIRECTION_RIGHT);  
  14.             }  
  15.         });  
9.还重写了dispatchTouchEvent

[java]  view plain copy print ?
  1. @Override  
  2.     public boolean dispatchTouchEvent(MotionEvent ev) {  
  3.         return resideMenu.dispatchTouchEvent(ev);  
  4.     }  
10.菜单关闭方法

[java]  view plain copy print ?
  1. resideMenu.closeMenu();  

11.屏蔽菜单方法

[java]  view plain copy print ?
  1. // You can disable a direction by setting ->  
  2.         // resideMenu.setSwipeDirectionDisable(ResideMenu.DIRECTION_RIGHT);  

使用方法已经说完了,接下来,看看它的源码,先看看源码的项目结构。



很多人初学者都曾纠结,看源码,如何从何看起,我个人建议从上面使用的顺序看起,并且在看的时候要带个问题去看去思考,这样更容易理解。

上面的第一步是,创建ResideMenu对象,我们就看看ResideMenu的构造。

[java]  view plain copy print ?
  1. public ResideMenu(Context context) {  
  2.         super(context);  
  3.         initViews(context);  
  4.     }  
从上面代码,看到构造里面就一个初始化view,思考问题:如何初始化view及初始化了什么view。

[java]  view plain copy print ?
  1. private void initViews(Context context){  
  2.         LayoutInflater inflater = (LayoutInflater)  
  3.                 context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  4.         inflater.inflate(R.layout.residemenu, this);  
  5.         scrollViewLeftMenu = (ScrollView) findViewById(R.id.sv_left_menu);  
  6.         scrollViewRightMenu = (ScrollView) findViewById(R.id.sv_right_menu);  
  7.         imageViewShadow = (ImageView) findViewById(R.id.iv_shadow);  
  8.         layoutLeftMenu = (LinearLayout) findViewById(R.id.layout_left_menu);  
  9.         layoutRightMenu = (LinearLayout) findViewById(R.id.layout_right_menu);  
  10.         imageViewBackground = (ImageView) findViewById(R.id.iv_background);  
  11.     }  
原理分析:从上面的代码可以看到,加载了一个residemenu的布局,先看布局

[java]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  4.               android:layout_width="match_parent"  
  5.               android:layout_height="match_parent">  
  6.     <ImageView  
  7.             android:id="@+id/iv_background"  
  8.             android:adjustViewBounds="true"  
  9.             android:scaleType="centerCrop"  
  10.             android:layout_width="match_parent"  
  11.             android:layout_height="match_parent"/>  
  12.   
  13.     <ImageView  
  14.             android:id="@+id/iv_shadow"  
  15.             android:background="@drawable/shadow"  
  16.             android:layout_width="fill_parent"  
  17.             android:layout_height="fill_parent"  
  18.             android:scaleType="fitXY"/>  
  19.   
  20.     <ScrollView  
  21.             android:id="@+id/sv_left_menu"  
  22.             android:scrollbars="none"  
  23.             android:paddingLeft="30dp"  
  24.             android:layout_width="150dp"  
  25.             android:layout_height="fill_parent">  
  26.         <LinearLayout  
  27.                 android:id="@+id/layout_left_menu"  
  28.                 android:orientation="vertical"  
  29.                 android:layout_gravity="center_vertical"  
  30.                 android:layout_width="wrap_content"  
  31.                 android:layout_height="wrap_content">  
  32.   
  33.         </LinearLayout>  
  34.     </ScrollView>  
  35.   
  36.     <ScrollView  
  37.             android:id="@+id/sv_right_menu"  
  38.             android:scrollbars="none"  
  39.             android:paddingRight="30dp"  
  40.             android:layout_width="150dp"  
  41.             android:layout_height="fill_parent"  
  42.             android:layout_gravity="right">  
  43.         <LinearLayout  
  44.                 android:id="@+id/layout_right_menu"  
  45.                 android:orientation="vertical"  
  46.                 android:layout_gravity="center_vertical"  
  47.                 android:layout_width="wrap_content"  
  48.                 android:layout_height="wrap_content"  
  49.                 android:gravity="right">  
  50.   
  51.         </LinearLayout>  
  52.     </ScrollView>  
  53.   
  54. </FrameLayout>  
布局显示效果


从布局文件,以及显示效果我们可以看到,它是一个帧布局,第一个ImageView是背景,第二个ImageView是.9的阴影效果的图片(看下面的图),

两个(ScrollView包裹着一个LinerLayout),可以从上面图看到结构分别是左菜单和右菜单

[java]  view plain copy print ?
  1. <img src="http://img.blog.csdn.net/20140910100807704?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3ltNDkyMjI0MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" style="font-family: Arial; background-color: rgb(255, 255, 255);" alt="" />  

1.初始化布局以及布局文件分析完毕,2.接下来是设置背景图,初始化view的时候就已经拿到了背景控件,所以设置背景图也是非常好实现的事情了。

[java]  view plain copy print ?
  1. public void setBackground(int imageResrouce){  
  2.        imageViewBackground.setImageResource(imageResrouce);  
  3.    }  
3.绑定activity,思考问题:它做了什么?

[java]  view plain copy print ?
  1. /** 
  2.   * use the method to set up the activity which residemenu need to show; 
  3.   * 
  4.   * @param activity 
  5.   */  
  6.  public void attachToActivity(Activity activity){  
  7.      initValue(activity);  
  8.      setShadowAdjustScaleXByOrientation();  
  9.      viewDecor.addView(this0);  
  10.      setViewPadding();  
  11.  }  
原理分析:绑定activity做了4件事情,分别是:

1.初始化参数:

[java]  view plain copy print ?
  1. private void initValue(Activity activity){  
  2.     this.activity   = activity;  
  3.     leftMenuItems   = new ArrayList<ResideMenuItem>();  
  4.     rightMenuItems  = new ArrayList<ResideMenuItem>();  
  5.     ignoredViews    = new ArrayList<View>();  
  6.     viewDecor = (ViewGroup) activity.getWindow().getDecorView();  
  7.     viewActivity = new TouchDisableView(this.activity);  
  8.   
  9.     View mContent   = viewDecor.getChildAt(0);  
  10.     viewDecor.removeViewAt(0);  
  11.     viewActivity.setContent(mContent);  
  12.     addView(viewActivity);  
  13.   
  14.     ViewGroup parent = (ViewGroup) scrollViewLeftMenu.getParent();  
  15.     parent.removeView(scrollViewLeftMenu);  
  16.     parent.removeView(scrollViewRightMenu);  
  17. }  

2.正对横竖屏缩放比例进行调整

[java]  view plain copy print ?
  1. private void setShadowAdjustScaleXByOrientation(){  
  2.       int orientation = getResources().getConfiguration().orientation;  
  3.       if (orientation == Configuration.ORIENTATION_LANDSCAPE) {  
  4.           shadowAdjustScaleX = 0.034f;  
  5.           shadowAdjustScaleY = 0.12f;  
  6.       } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {  
  7.           shadowAdjustScaleX = 0.06f;  
  8.           shadowAdjustScaleY = 0.07f;  
  9.       }  
  10.   }  

3.添加当前view

[java]  view plain copy print ?
  1. viewDecor.addView(this0);  

4.设置view边距

[java]  view plain copy print ?
  1. /** 
  2.      * we need the call the method before the menu show, because the 
  3.      * padding of activity can't get at the moment of onCreateView(); 
  4.      */  
  5.     private void setViewPadding(){  
  6.         this.setPadding(viewActivity.getPaddingLeft(),  
  7.                 viewActivity.getPaddingTop(),  
  8.                 viewActivity.getPaddingRight(),  
  9.                 viewActivity.getPaddingBottom());  
  10.     }  
4.设置监听,思考问题:它什么时候调用监听,原理分析:动画监听开始执行动画掉哦那个openMenu动画结束调用closeMenu,从此我们可以想到,但它调用openMenu( int  direction)和closeMenu()都会设置这个监听。

[java]  view plain copy print ?
  1. private Animator.AnimatorListener animationListener = new Animator.AnimatorListener() {  
  2.         @Override  
  3.         public void onAnimationStart(Animator animation) {  
  4.             if (isOpened()){  
  5.                 showScrollViewMenu();  
  6.                 if (menuListener != null)  
  7.                     menuListener.openMenu();  
  8.             }  
  9.         }  
  10.   
  11.         @Override  
  12.         public void onAnimationEnd(Animator animation) {  
  13.             // reset the view;  
  14.             if(isOpened()){  
  15.                 viewActivity.setTouchDisable(true);  
  16.                 viewActivity.setOnClickListener(viewActivityOnClickListener);  
  17.             }else{  
  18.                 viewActivity.setTouchDisable(false);  
  19.                 viewActivity.setOnClickListener(null);  
  20.                 hideScrollViewMenu();  
  21.                 if (menuListener != null)  
  22.                     menuListener.closeMenu();  
  23.             }  
  24.         }  
  25.   
  26.         @Override  
  27.         public void onAnimationCancel(Animator animation) {  
  28.   
  29.         }  
  30.   
  31.         @Override  
  32.         public void onAnimationRepeat(Animator animation) {  
  33.   
  34.         }  
  35.     };  
5. 设置内容缩放比例(0.1~1f),细心的同学会发现在当缩完成后还可以在往里面拉到更小,有种弹性的感觉,挺有趣的。但是有些人的需求不想要有这种弹性效果,我们可以通过修改源码修改这个弹性效果,找到getTargetScale这个方法,修改下面0.5这个数值。使用时设置了0.6的缩放比例,默认下面的弹性参数是0.5所以我们当缩完成后还可以在往里面拉0.1的比例。

[java]  view plain copy print ?
  1. private float getTargetScale(float currentRawX){  
  2.     float scaleFloatX = ((currentRawX - lastRawX) / getScreenWidth()) * 0.75f;  
  3.     scaleFloatX = scaleDirection == DIRECTION_RIGHT ? - scaleFloatX : scaleFloatX;  
  4.   
  5.     float targetScale = ViewHelper.getScaleX(viewActivity) - scaleFloatX;  
  6.     targetScale = targetScale > 1.0f ? 1.0f : targetScale;  
  7.     targetScale = targetScale < 0.5f ? 0.5f : targetScale;  
  8.     return targetScale;  
  9. }  

默认缩放比例:

[java]  view plain copy print ?
  1. //valid scale factor is between 0.0f and 1.0f.  
  2.    private float mScaleValue = 0.5f;  
[java]  view plain copy print ?
  1. AnimatorSet scaleDown_activity = buildScaleDownAnimation(viewActivity, mScaleValue, mScaleValue);  
[java]  view plain copy print ?
  1. /** 
  2.      * a helper method to build scale down animation; 
  3.      * 
  4.      * @param target 
  5.      * @param targetScaleX 
  6.      * @param targetScaleY 
  7.      * @return 
  8.      */  
  9.     private AnimatorSet buildScaleDownAnimation(View target,float targetScaleX,float targetScaleY){  
  10.   
  11.         AnimatorSet scaleDown = new AnimatorSet();  
  12.         scaleDown.playTogether(  
  13.                 ObjectAnimator.ofFloat(target, "scaleX", targetScaleX),  
  14.                 ObjectAnimator.ofFloat(target, "scaleY", targetScaleY)  
  15.         );  
  16.   
  17.         scaleDown.setInterpolator(AnimationUtils.loadInterpolator(activity,  
  18.                 android.R.anim.decelerate_interpolator));  
  19.         scaleDown.setDuration(250);  
  20.         return scaleDown;  
  21.     }  
6.创建子菜单,看下子菜单的构造,我们通过上面的学习,原理分析:我们可以猜测到,无非就是加载布局设置内容

[java]  view plain copy print ?
  1. public ResideMenuItem(Context context, int icon, String title) {  
  2.         super(context);  
  3.         initViews(context);  
  4.         iv_icon.setImageResource(icon);  
  5.         tv_title.setText(title);  
  6.     }  
  7.   
  8.     private void initViews(Context context){  
  9.         LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  10.         inflater.inflate(R.layout.residemenu_item, this);  
  11.         iv_icon = (ImageView) findViewById(R.id.iv_icon);  
  12.         tv_title = (TextView) findViewById(R.id.tv_title);  
  13.     }  
布局文件:

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  4.               android:orientation="horizontal"  
  5.               android:layout_width="match_parent"  
  6.               android:layout_height="wrap_content"  
  7.               android:gravity="center_vertical"  
  8.               android:paddingTop="30dp">  
  9.   
  10.     <ImageView  
  11.             android:layout_width="30dp"  
  12.             android:layout_height="30dp"  
  13.             android:scaleType="centerCrop"  
  14.             android:id="@+id/iv_icon"/>  
  15.   
  16.     <TextView  
  17.             android:layout_width="match_parent"  
  18.             android:layout_height="wrap_content"  
  19.             android:textColor="@android:color/white"  
  20.             android:textSize="18sp"  
  21.             android:layout_marginLeft="10dp"  
  22.             android:id="@+id/tv_title"/>  
  23.   
  24. </LinearLayout>  

显示效果图:


7.子菜单添加到侧换菜单中(可以看到它是通过常量来控制子菜单的添加位置)原理分析:根据不同的常量来区分添加不同菜单的子菜单

[java]  view plain copy print ?
  1. /** 
  2.     * add a single items; 
  3.     * 
  4.     * @param menuItem 
  5.     * @param direction 
  6.     */  
  7.    public void addMenuItem(ResideMenuItem menuItem, int direction){  
  8.        if (direction == DIRECTION_LEFT){  
  9.            this.leftMenuItems.add(menuItem);  
  10.            layoutLeftMenu.addView(menuItem);  
  11.        }else{  
  12.            this.rightMenuItems.add(menuItem);  
  13.            layoutRightMenu.addView(menuItem);  
  14.        }  
  15.    }  
8.设置title按钮的点击事件,设置左右菜单的开关,原理分析:先设置了缩放方向然后在设置动画,正如我们上面想的一样还设置了动画监听。

[java]  view plain copy print ?
  1. /** 
  2.  * show the reside menu; 
  3.  */  
  4. public void openMenu(int direction){  
  5.   
  6.     setScaleDirection(direction);  
  7.   
  8.     isOpened = true;  
  9.     AnimatorSet scaleDown_activity = buildScaleDownAnimation(viewActivity, mScaleValue, mScaleValue);  
  10.     AnimatorSet scaleDown_shadow = buildScaleDownAnimation(imageViewShadow,  
  11.             mScaleValue + shadowAdjustScaleX, mScaleValue + shadowAdjustScaleY);  
  12.     AnimatorSet alpha_menu = buildMenuAnimation(scrollViewMenu, 1.0f);  
  13.     scaleDown_shadow.addListener(animationListener);  
  14.     scaleDown_activity.playTogether(scaleDown_shadow);  
  15.     scaleDown_activity.playTogether(alpha_menu);  
  16.     scaleDown_activity.start();  
  17. }  
设置缩放方向及计算x,y轴位置。

[java]  view plain copy print ?
  1. private void setScaleDirection(int direction){  
  2.   
  3.     int screenWidth = getScreenWidth();  
  4.     float pivotX;  
  5.     float pivotY = getScreenHeight() * 0.5f;  
  6.   
  7.     if (direction == DIRECTION_LEFT){  
  8.         scrollViewMenu = scrollViewLeftMenu;  
  9.         pivotX  = screenWidth * 1.5f;  
  10.     }else{  
  11.         scrollViewMenu = scrollViewRightMenu;  
  12.         pivotX  = screenWidth * -0.5f;  
  13.     }  
  14.   
  15.     ViewHelper.setPivotX(viewActivity, pivotX);  
  16.     ViewHelper.setPivotY(viewActivity, pivotY);  
  17.     ViewHelper.setPivotX(imageViewShadow, pivotX);  
  18.     ViewHelper.setPivotY(imageViewShadow, pivotY);  
  19.     scaleDirection = direction;  
  20. }  
9.重写 dispatchTouchEvent,问题思考:如何到根据手指滑动自动缩放

如果还不了解,dispatchTouchEvent这个函数如何调用?什么时候调用?请先看看http://blog.csdn.net/cym492224103/article/details/39179311

[java]  view plain copy print ?
  1. @Override  
  2. public boolean dispatchTouchEvent(MotionEvent ev) {  
  3.     float currentActivityScaleX = ViewHelper.getScaleX(viewActivity);  
  4.     if (currentActivityScaleX == 1.0f)  
  5.         setScaleDirectionByRawX(ev.getRawX());  
  6.   
  7.     switch (ev.getAction()){  
  8.         case MotionEvent.ACTION_DOWN:  
  9.             lastActionDownX = ev.getX();  
  10.             lastActionDownY = ev.getY();  
  11.             isInIgnoredView = isInIgnoredView(ev) && !isOpened();  
  12.             pressedState    = PRESSED_DOWN;  
  13.             break;  
  14.   
  15.         case MotionEvent.ACTION_MOVE:  
  16.             if (isInIgnoredView || isInDisableDirection(scaleDirection))  
  17.                 break;  
  18.   
  19.             if(pressedState != PRESSED_DOWN &&  
  20.                     pressedState != PRESSED_MOVE_HORIZANTAL)  
  21.                 break;  
  22.   
  23.             int xOffset = (int) (ev.getX() - lastActionDownX);  
  24.             int yOffset = (int) (ev.getY() - lastActionDownY);  
  25.   
  26.             if(pressedState == PRESSED_DOWN) {  
  27.                 if(yOffset > 25 || yOffset < -25) {  
  28.                     pressedState = PRESSED_MOVE_VERTICAL;  
  29.                     break;  
  30.                 }  
  31.                 if(xOffset < -50 || xOffset > 50) {  
  32.                     pressedState = PRESSED_MOVE_HORIZANTAL;  
  33.                     ev.setAction(MotionEvent.ACTION_CANCEL);  
  34.                 }  
  35.             } else if(pressedState == PRESSED_MOVE_HORIZANTAL) {  
  36.                 if (currentActivityScaleX < 0.95)  
  37.                     showScrollViewMenu();  
  38.   
  39.                 float targetScale = getTargetScale(ev.getRawX());  
  40.                 ViewHelper.setScaleX(viewActivity, targetScale);  
  41.                 ViewHelper.setScaleY(viewActivity, targetScale);  
  42.                 ViewHelper.setScaleX(imageViewShadow, targetScale + shadowAdjustScaleX);  
  43.                 ViewHelper.setScaleY(imageViewShadow, targetScale + shadowAdjustScaleY);  
  44.                 ViewHelper.setAlpha(scrollViewMenu, (1 - targetScale) * 2.0f);  
  45.   
  46.                 lastRawX = ev.getRawX();  
  47.                 return true;  
  48.             }  
  49.   
  50.             break;  
  51.   
  52.         case MotionEvent.ACTION_UP:  
  53.   
  54.             if (isInIgnoredView) break;  
  55.             if (pressedState != PRESSED_MOVE_HORIZANTAL) break;  
  56.   
  57.             pressedState = PRESSED_DONE;  
  58.             if (isOpened()){  
  59.                 if (currentActivityScaleX > 0.56f)  
  60.                     closeMenu();  
  61.                 else  
  62.                     openMenu(scaleDirection);  
  63.             }else{  
  64.                 if (currentActivityScaleX < 0.94f){  
  65.                     openMenu(scaleDirection);  
  66.                 }else{  
  67.                     closeMenu();  
  68.                 }  
  69.             }  
  70.   
  71.             break;  
  72.   
  73.     }  
  74.     lastRawX = ev.getRawX();  
  75.     return super.dispatchTouchEvent(ev);  
  76. }  
上面代码量有点多,看上去有点晕,接下来我们来分别从按下、移动、放开、来原理分析:

MotionEvent.ACTION_DOWN:

记录了X,Y轴的坐标点,判断是否打开,设置了按下的状态为PRESSED_DOWN

MotionEvent.ACTION_MOVE:

拿到当前X,Y减去DOWN下记录下来的X,Y,这样得到了移动的X,Y,

然后判断如果如果移动的X,Y大于25或者小于-25就改变按下状态为PRESSED_MOVE_VERTICAL

如果移动的X,Y大于50或者小于-50就改变状态为PRESSED_MOVE_HORIZANTAL

状态为PRESSED_MOVE_HORIZANTAL就改变菜单主视图内容以及阴影图片大小,在改变的同时还设置了当前菜单的透明度。

MotionEvent.ACTION_UP:

判断是否菜单是否打开状态,在获取当前缩放的X比例,

判断比例小于0.56f,则关闭菜单,反正开启菜单。

看完后,我们在回去看看代码,就会发现其实也不过如此~!

10.菜单关闭方法,同样也设置了动画监听之前的想法也是成立的。

[java]  view plain copy print ?
  1. /** 
  2.     * close the reslide menu; 
  3.     */  
  4.    public void closeMenu(){  
  5.   
  6.        isOpened = false;  
  7.        AnimatorSet scaleUp_activity = buildScaleUpAnimation(viewActivity, 1.0f, 1.0f);  
  8.        AnimatorSet scaleUp_shadow = buildScaleUpAnimation(imageViewShadow, 1.0f, 1.0f);  
  9.        AnimatorSet alpha_menu = buildMenuAnimation(scrollViewMenu, 0.0f);  
  10.        scaleUp_activity.addListener(animationListener);  
  11.        scaleUp_activity.playTogether(scaleUp_shadow);  
  12.        scaleUp_activity.playTogether(alpha_menu);  
  13.        scaleUp_activity.start();  
  14.    }  
11.屏蔽菜单方法

[java]  view plain copy print ?
  1. public void setSwipeDirectionDisable(int direction){  
  2.         disabledSwipeDirection.add(direction);  
  3.     }  
[java]  view plain copy print ?
  1. private boolean isInDisableDirection(int direction){  
  2.         return disabledSwipeDirection.contains(direction);  
  3.     }  
原理分析:在重写 dispatchTouchEvent的时候,细心的同学应该会看到, ACTION_MOVE下面有个判断

[java]  view plain copy print ?
  1. if (isInIgnoredView || isInDisableDirection(scaleDirection))  
如果这个方向的菜单被屏蔽了,就滑不出来了。

最后我们会发现我们一直都没说到TouchDisableView,其实initValue的时候就初始化了,它就是viewActivity,是我们的内容视图。


我们来看看它做了什么?

[java]  view plain copy print ?
  1. @Override  
  2.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.   
  4.         int width = getDefaultSize(0, widthMeasureSpec);  
  5.         int height = getDefaultSize(0, heightMeasureSpec);  
  6.         setMeasuredDimension(width, height);  
  7.   
  8.         final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);  
  9.         final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);  
  10.         mContent.measure(contentWidth, contentHeight);  
  11.     }  
  12.   
  13.     @Override  
  14.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  15.         final int width = r - l;  
  16.         final int height = b - t;  
  17.         mContent.layout(00, width, height);  
  18.     }  
  19.   
  20.     @Override  
  21.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  22.         return mTouchDisabled;  
  23.     }  
  24.   
  25.     void setTouchDisable(boolean disableTouch) {  
  26.         mTouchDisabled = disableTouch;  
  27.     }  
  28.   
  29.     boolean isTouchDisabled() {  
  30.         return mTouchDisabled;  
  31.     }  
动态设置宽高,设置事件是否传递下去的flag。
相关文章
|
存储 监控 Android开发
Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)
Android卡顿优化 | ANR分析与实战(附ANR-WatchDog源码分析及实战、与AndroidPerformanceMonitor的区别)
|
8月前
|
Android开发
Android PackageManagerService源码分析和APK安装原理详解
Android PackageManagerService源码分析和APK安装原理详解
203 1
|
XML Java Android开发
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(下)
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(下)
167 0
|
XML 数据库 网络虚拟化
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(上)
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新
214 0
|
XML Java Linux
Android8.1 MTK平台 SystemUI源码分析之 电池时钟刷新
Android8.1 MTK平台 SystemUI源码分析之 电池时钟刷新
262 0
|
Android开发
Android仿QQ侧滑菜单
Android仿QQ侧滑菜单
|
XML 存储 搜索推荐
|
Java 调度 Android开发
android体系课-系统启动流程-之zygote进程启动过程源码分析
笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己
|
Java 调度 Android开发
android体系课-系统启动流程-之SystemServer启动过程源码分析
笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己
|
设计模式 XML 缓存
Android体系课学习 之 网络请求库Retrofit源码分析-看这一篇就够了
- 网络请求在我们开发中起的很大比重,有一个好的网络框架可以节省我们的开发工作量,也可以避免一些在开发中不该出现的bug - *Retrofit*是一个轻量级框架,基于*OkHttp*的一个*Restful*框架