本文来自http://blog.csdn.net/chenshaoyang0011 转载请申明文章出处!
文中如有纰漏之处,望不吝指教~~~欢迎讨论,共同学习~~~
进入All Apps界面是通过点击Hotseat中的allAppsButton触发事件,通过前面的分析,已经知道在setupViews()方法中,就为button设置好了onTouchListener:
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,二进制的值为11111111。ACTION_DOWN的值为0x00000000,二进制为00000000。在真实的设备中通常支持多点触控,但根据直观的判断,多指“按下”和单指“按下”都属于“按下”。Android中ACTION_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()被调用。
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()方法中
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()方法。
/** * 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()方法。
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页。接着隐藏了SearchDropTargetBar和Hotseat。为了节省资源,关闭了AppWidget的自动更新。下面进入cameraZoomOut():
/** * 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 { //不需要动画效果 ...... }