Android 4.0 Launcher2源码分析——Workspace切换AllApps流程

本文来自http://blog.csdn.net/chenshaoyang0011 转载请申明文章出处!

文中如有纰漏之处,望不吝指教~~~欢迎讨论,共同学习~~~

进入All Apps界面是通过点击Hotseat中的allAppsButton触发事件,通过前面的分析,已经知道在setupViews()方法中,就为button设置好了onTouchListener:

  1. private void setupViews() {  
  2.         ......  
  3.         // Get the all apps button   
  4.         mAllAppsButton = findViewById(R.id.all_apps_button);  
  5.         if (mAllAppsButton != null) {  
  6.             mAllAppsButton.setOnTouchListener(new View.OnTouchListener() {  
  7.                 @Override  
  8.                 public boolean onTouch(View v, MotionEvent event) {  
  9.                     //(MotionEvent.ACTION_POINTER_1_DOWN & MotionEvent.ACTION_MASK)   
  10.                     //(MotionEvent.ACTION_POINTER_2_DOWN & MotionEvent.ACTION_MASK)   
  11.                     //(MotionEvent.ACTION_POINTER_3_DOWN & MotionEvent.ACTION_MASK)   
  12.                     // == MotionEvent.ACTION_DOWN   
  13.                     if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {  
  14.                         onTouchDownAllAppsButton(v);  
  15.                     }  
  16.                     return false;  
  17.                 }  
  18.             });  
  19.         }  
  20.         ......  
  21.     }  
private void setupViews() {
        ......
        // Get the all apps button
        mAllAppsButton = findViewById(R.id.all_apps_button);
        if (mAllAppsButton != null) {
            mAllAppsButton.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    //(MotionEvent.ACTION_POINTER_1_DOWN & MotionEvent.ACTION_MASK)
                    //(MotionEvent.ACTION_POINTER_2_DOWN & MotionEvent.ACTION_MASK)
                    //(MotionEvent.ACTION_POINTER_3_DOWN & MotionEvent.ACTION_MASK)
                    // == MotionEvent.ACTION_DOWN
                    if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
                        onTouchDownAllAppsButton(v);
                    }
                    return false;
                }
            });
        }
        ......
    }

这里简单说明下,为什么在判断事件的时候不直接使用event.getAction() == MotionEvent.ACTION_DOWN,而是采用(event.getAction() & MotionEvent.ACTION_MASK) ==MotionEvent.ACTION_DOWN呢?查看文档,我们可以发现ACTION_MASK的值为0x000000ff,二进制的值为11111111ACTION_DOWN的值为0x00000000,二进制为00000000。在真实的设备中通常支持多点触控,但根据直观的判断,多指按下和单指按下都属于按下AndroidACTION_MASK恰恰是为了解决这个问题而存在的因为(MotionEvent.ACTION_POINTER_1_DOWN & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN, (MotionEvent.ACTION_POINTER_2_DOWN   MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN,(MotionEvent.ACTION_POINTER_3_DOWN & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN。这就是为什么要先再判断的原因了。ACTION_DOWN被触发后,onTouchDownAllAppsButton()被调用。


  1. public void onTouchDownAllAppsButton(View v) {  
  2.         // Provide the same haptic feedback that the system offers for virtual keys.   
  3.         v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);  
  4.     }  
public void onTouchDownAllAppsButton(View v) {
        // Provide the same haptic feedback that the system offers for virtual keys.
        v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
    }
在onTouchDownAllAppsButton()中为ACTION_DOWN事件提供了触感反馈(振动反馈)。

接着,顺着启动的过程,进入到了Hotseat.resetLayout()方法中

  1. void resetLayout() {  
  2.         ......  
  3.         allAppsButton.setOnClickListener(new View.OnClickListener() {  
  4.             @Override  
  5.             public void onClick(android.view.View v) {  
  6.                 if (mLauncher != null) {  
  7.                     mLauncher.onClickAllAppsButton(v);  
  8.                 }  
  9.             }  
  10.         });  
  11.         ......  
  12.     }  
void resetLayout() {
        ......
        allAppsButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(android.view.View v) {
                if (mLauncher != null) {
                    mLauncher.onClickAllAppsButton(v);
                }
            }
        });
        ......
    }
这里为allAppsButton设置了OnClickListener,当allAppsButton被点击后,会调用Launcher.onClickAllAppsButton()方法。
  1. /** 
  2.  * Event handler for the "grid" button that appears on the home screen, which 
  3.  * enters all apps mode. 
  4.  * 
  5.  * @param v The view that was clicked. 
  6.  */  
  7. public void onClickAllAppsButton(View v) {  
  8.     showAllApps(true);  
  9. }  
    /**
     * Event handler for the "grid" button that appears on the home screen, which
     * enters all apps mode.
     *
     * @param v The view that was clicked.
     */
    public void onClickAllAppsButton(View v) {
        showAllApps(true);
    }
接着进入showAllApps()方法。
  1. void showAllApps(boolean animated) {  
  2.     if (mState != State.WORKSPACE) return;  
  3.   
  4.     //显示apps_customize也就是AllApps页面,切换时有缩放和渐显的动画    
  5.     cameraZoomOut(State.APPS_CUSTOMIZE, animated, false);  
  6.     mAppsCustomizeTabHost.requestFocus();  
  7.   
  8.     // Hide the search bar and hotseat   
  9.     //将searchBar隐藏起来   
  10.     mSearchDropTargetBar.hideSearchBar(animated);  
  11.   
  12.     // Change the state *after* we've called all the transition code   
  13.     //将状态mState从WORKSPACE切换到APPS_CUSTOMIZE   
  14.     mState = State.APPS_CUSTOMIZE;  
  15.   
  16.     // Pause the auto-advance of widgets until we are out of AllApps   
  17.     //停止对AppWidget的自动更新   
  18.     mUserPresent = false;  
  19.     updateRunning();  
  20.     //将桌面上打开的文件夹关闭   
  21.     closeFolder();  
  22.   
  23.     // Send an accessibility event to announce the context change   
  24.     getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);  
  25. }  
    void showAllApps(boolean animated) {
        if (mState != State.WORKSPACE) return;

        //显示apps_customize也就是AllApps页面,切换时有缩放和渐显的动画 
        cameraZoomOut(State.APPS_CUSTOMIZE, animated, false);
        mAppsCustomizeTabHost.requestFocus();

        // Hide the search bar and hotseat
        //将searchBar隐藏起来
        mSearchDropTargetBar.hideSearchBar(animated);

        // Change the state *after* we've called all the transition code
        //将状态mState从WORKSPACE切换到APPS_CUSTOMIZE
        mState = State.APPS_CUSTOMIZE;

        // Pause the auto-advance of widgets until we are out of AllApps
        //停止对AppWidget的自动更新
        mUserPresent = false;
        updateRunning();
        //将桌面上打开的文件夹关闭
        closeFolder();

        // Send an accessibility event to announce the context change
        getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
    }

进入方法后可以看到,最主要的功能是在cameraZoomOut()方法中,以动画的方式来显示AllApps页。接着隐藏了SearchDropTargetBarHotseat。为了节省资源,关闭了AppWidget的自动更新。下面进入cameraZoomOut()

  1. /** 
  2.  * Zoom the camera out from the workspace to reveal 'toView'. 
  3.  * Assumes that the view to show is anchored at either the very top or very bottom 
  4.  * of the screen. 
  5.  * @param toState The state to zoom out to. Must be APPS_CUSTOMIZE. 
  6.  */  
  7. private void cameraZoomOut(State toState, boolean animated, final boolean springLoaded) {  
  8.     ......  
  9.   
  10.     //设置缩放时的轴心   
  11.     setPivotsForZoom(toView, toState, scale);  
  12.   
  13.     // Shrink workspaces away if going to AppsCustomize from workspace   
  14.     //缩小workspaces然后让它消失。   
  15.     mWorkspace.changeState(Workspace.State.SMALL, animated);  
  16.   
  17.     if (animated) {  
  18.         //如果需要动画,就是用scaleAnim来实现缩放的动画效果   
  19.         final ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);  
  20.         scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator());  
  21.         scaleAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {  
  22.             public void onAnimationUpdate(float a, float b) {  
  23.                 ((View) toView.getParent()).invalidate();  
  24.                 toView.fastInvalidate();  
  25.                 toView.setFastScaleX(a * scale + b * 1f);  
  26.                 toView.setFastScaleY(a * scale + b * 1f);  
  27.             }  
  28.         });  
  29.   
  30.         toView.setVisibility(View.VISIBLE);  
  31.         toView.setFastAlpha(0f);  
  32.         //使用alphaAnim来实现渐显的动画效果   
  33.         ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(fadeDuration);  
  34.         alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));  
  35.         alphaAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {  
  36.             public void onAnimationUpdate(float a, float b) {  
  37.                 // don't need to invalidate because we do so above   
  38.                 toView.setFastAlpha(a * 0f + b * 1f);  
  39.             }  
  40.         });  
  41.         alphaAnim.setStartDelay(startDelay);  
  42.         alphaAnim.start();  
  43.   
  44.         if (toView instanceof LauncherTransitionable) {  
  45.             //切换开始时,调用AppsCustomizeTabHost.onLauncherTransitionStart()方法   
  46.             ((LauncherTransitionable) toView).onLauncherTransitionStart(instance, scaleAnim,  
  47.                     false);  
  48.         }  
  49.         scaleAnim.addListener(new AnimatorListenerAdapter() {  
  50.             boolean animationCancelled = false;  
  51.   
  52.             @Override  
  53.             public void onAnimationStart(Animator animation) {  
  54.                 updateWallpaperVisibility(true);  
  55.                 // Prepare the position   
  56.                 toView.setTranslationX(0.0f);  
  57.                 toView.setTranslationY(0.0f);  
  58.                 toView.setVisibility(View.VISIBLE);  
  59.                 toView.bringToFront();  
  60.             }  
  61.             @Override  
  62.             public void onAnimationEnd(Animator animation) {  
  63.                 // If we don't set the final scale values here, if this animation is cancelled   
  64.                 // it will have the wrong scale value and subsequent cameraPan animations will   
  65.                 // not fix that   
  66.                 toView.setScaleX(1.0f);  
  67.                 toView.setScaleY(1.0f);  
  68.                 if (toView instanceof LauncherTransitionable) {  
  69.                     //当切换过程完成时,调用AppsCustomizeTabHost.onLauncherTransitionEnd()方法   
  70.                     ((LauncherTransitionable) toView).onLauncherTransitionEnd(instance,  
  71.                             scaleAnim, false);  
  72.                 }  
  73.   
  74.                 ......  
  75.             }  
  76.   
  77.             @Override  
  78.             public void onAnimationCancel(Animator animation) {  
  79.                 animationCancelled = true;  
  80.             }  
  81.         });  
  82.   
  83.         // toView should appear right at the end of the workspace shrink animation   
  84.   
  85.         if (mStateAnimation != null) mStateAnimation.cancel();  
  86.         mStateAnimation = new AnimatorSet();  
  87.         mStateAnimation.play(scaleAnim).after(startDelay);  
  88.         mStateAnimation.start();  
  89.     } else {  
  90.         //不需要动画效果   
  91.         ......  
  92. }  
    /**
     * Zoom the camera out from the workspace to reveal 'toView'.
     * Assumes that the view to show is anchored at either the very top or very bottom
     * of the screen.
     * @param toState The state to zoom out to. Must be APPS_CUSTOMIZE.
     */
    private void cameraZoomOut(State toState, boolean animated, final boolean springLoaded) {
        ......

        //设置缩放时的轴心
        setPivotsForZoom(toView, toState, scale);

        // Shrink workspaces away if going to AppsCustomize from workspace
        //缩小workspaces然后让它消失。
        mWorkspace.changeState(Workspace.State.SMALL, animated);

        if (animated) {
            //如果需要动画,就是用scaleAnim来实现缩放的动画效果
            final ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
            scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator());
            scaleAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
                public void onAnimationUpdate(float a, float b) {
                    ((View) toView.getParent()).invalidate();
                    toView.fastInvalidate();
                    toView.setFastScaleX(a * scale + b * 1f);
                    toView.setFastScaleY(a * scale + b * 1f);
                }
            });

            toView.setVisibility(View.VISIBLE);
            toView.setFastAlpha(0f);
            //使用alphaAnim来实现渐显的动画效果
            ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(fadeDuration);
            alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
            alphaAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
                public void onAnimationUpdate(float a, float b) {
                    // don't need to invalidate because we do so above
                    toView.setFastAlpha(a * 0f + b * 1f);
                }
            });
            alphaAnim.setStartDelay(startDelay);
            alphaAnim.start();

            if (toView instanceof LauncherTransitionable) {
                //切换开始时,调用AppsCustomizeTabHost.onLauncherTransitionStart()方法
                ((LauncherTransitionable) toView).onLauncherTransitionStart(instance, scaleAnim,
                        false);
            }
            scaleAnim.addListener(new AnimatorListenerAdapter() {
                boolean animationCancelled = false;

                @Override
                public void onAnimationStart(Animator animation) {
                    updateWallpaperVisibility(true);
                    // Prepare the position
                    toView.setTranslationX(0.0f);
                    toView.setTranslationY(0.0f);
                    toView.setVisibility(View.VISIBLE);
                    toView.bringToFront();
                }
                @Override
                public void onAnimationEnd(Animator animation) {
                    // If we don't set the final scale values here, if this animation is cancelled
                    // it will have the wrong scale value and subsequent cameraPan animations will
                    // not fix that
                    toView.setScaleX(1.0f);
                    toView.setScaleY(1.0f);
                    if (toView instanceof LauncherTransitionable) {
                        //当切换过程完成时,调用AppsCustomizeTabHost.onLauncherTransitionEnd()方法
                        ((LauncherTransitionable) toView).onLauncherTransitionEnd(instance,
                                scaleAnim, false);
                    }

                    ......
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    animationCancelled = true;
                }
            });

            // toView should appear right at the end of the workspace shrink animation

            if (mStateAnimation != null) mStateAnimation.cancel();
            mStateAnimation = new AnimatorSet();
            mStateAnimation.play(scaleAnim).after(startDelay);
            mStateAnimation.start();
        } else {
            //不需要动画效果
            ......
    }

这里演示了使用ValueAnimator来实现动画效果的方式。动画结束之后,页面的切换就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值