进入All Apps界面是通过点击Hotseat中的allAppsButton触发事件,通过前面的分析,已经知道在setupViews()方法中,就为button设置好了onTouchListener:
- private void setupViews() {
- ......
-
- mAllAppsButton = findViewById(R.id.all_apps_button);
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
-
-
-
-
- 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) {
-
- 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()方法。
-
-
-
-
-
-
- public void onClickAllAppsButton(View v) {
- showAllApps(true);
- }
接着进入showAllApps()方法。
- void showAllApps(boolean animated) {
- if (mState != State.WORKSPACE) return;
-
-
- cameraZoomOut(State.APPS_CUSTOMIZE, animated, false);
- mAppsCustomizeTabHost.requestFocus();
-
-
-
- mSearchDropTargetBar.hideSearchBar(animated);
-
-
-
- mState = State.APPS_CUSTOMIZE;
-
-
-
- mUserPresent = false;
- updateRunning();
-
- closeFolder();
-
-
- getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
进入方法后可以看到,最主要的功能是在cameraZoomOut()方法中,以动画的方式来显示AllApps页。接着隐藏了SearchDropTargetBar和Hotseat。为了节省资源,关闭了AppWidget的自动更新。下面进入cameraZoomOut():
-
-
-
-
-
-
- private void cameraZoomOut(State toState, boolean animated, final boolean springLoaded) {
- ......
-
-
- setPivotsForZoom(toView, toState, scale);
-
-
-
- mWorkspace.changeState(Workspace.State.SMALL, animated);
-
- if (animated) {
-
- 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);
-
- 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) {
-
- toView.setFastAlpha(a * 0f + b * 1f);
- }
- });
- alphaAnim.setStartDelay(startDelay);
- alphaAnim.start();
-
- if (toView instanceof LauncherTransitionable) {
-
- ((LauncherTransitionable) toView).onLauncherTransitionStart(instance, scaleAnim,
- false);
- }
- scaleAnim.addListener(new AnimatorListenerAdapter() {
- boolean animationCancelled = false;
-
- @Override
- public void onAnimationStart(Animator animation) {
- updateWallpaperVisibility(true);
-
- toView.setTranslationX(0.0f);
- toView.setTranslationY(0.0f);
- toView.setVisibility(View.VISIBLE);
- toView.bringToFront();
- }
- @Override
- public void onAnimationEnd(Animator animation) {
-
-
-
- toView.setScaleX(1.0f);
- toView.setScaleY(1.0f);
- if (toView instanceof LauncherTransitionable) {
-
- ((LauncherTransitionable) toView).onLauncherTransitionEnd(instance,
- scaleAnim, false);
- }
-
- ......
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- animationCancelled = true;
- }
- });
-
-
-
- if (mStateAnimation != null) mStateAnimation.cancel();
- mStateAnimation = new AnimatorSet();
- mStateAnimation.play(scaleAnim).after(startDelay);
- mStateAnimation.start();
- } else {
-
- ......
- }
这里演示了使用ValueAnimator来实现动画效果的方式。动画结束之后,页面的切换就完成了。
进入All Apps界面是通过点击Hotseat中的allAppsButton触发事件,通过前面的分析,已经知道在setupViews()方法中,就为button设置好了onTouchListener:
- private void setupViews() {
- ......
-
- mAllAppsButton = findViewById(R.id.all_apps_button);
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
-
-
-
-
- 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) {
-
- 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()方法。
-
-
-
-
-
-
- public void onClickAllAppsButton(View v) {
- showAllApps(true);
- }
接着进入showAllApps()方法。
- void showAllApps(boolean animated) {
- if (mState != State.WORKSPACE) return;
-
-
- cameraZoomOut(State.APPS_CUSTOMIZE, animated, false);
- mAppsCustomizeTabHost.requestFocus();
-
-
-
- mSearchDropTargetBar.hideSearchBar(animated);
-
-
-
- mState = State.APPS_CUSTOMIZE;
-
-
-
- mUserPresent = false;
- updateRunning();
-
- closeFolder();
-
-
- getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
进入方法后可以看到,最主要的功能是在cameraZoomOut()方法中,以动画的方式来显示AllApps页。接着隐藏了SearchDropTargetBar和Hotseat。为了节省资源,关闭了AppWidget的自动更新。下面进入cameraZoomOut():
-
-
-
-
-
-
- private void cameraZoomOut(State toState, boolean animated, final boolean springLoaded) {
- ......
-
-
- setPivotsForZoom(toView, toState, scale);
-
-
-
- mWorkspace.changeState(Workspace.State.SMALL, animated);
-
- if (animated) {
-
- 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);
-
- 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) {
-
- toView.setFastAlpha(a * 0f + b * 1f);
- }
- });
- alphaAnim.setStartDelay(startDelay);
- alphaAnim.start();
-
- if (toView instanceof LauncherTransitionable) {
-
- ((LauncherTransitionable) toView).onLauncherTransitionStart(instance, scaleAnim,
- false);
- }
- scaleAnim.addListener(new AnimatorListenerAdapter() {
- boolean animationCancelled = false;
-
- @Override
- public void onAnimationStart(Animator animation) {
- updateWallpaperVisibility(true);
-
- toView.setTranslationX(0.0f);
- toView.setTranslationY(0.0f);
- toView.setVisibility(View.VISIBLE);
- toView.bringToFront();
- }
- @Override
- public void onAnimationEnd(Animator animation) {
-
-
-
- toView.setScaleX(1.0f);
- toView.setScaleY(1.0f);
- if (toView instanceof LauncherTransitionable) {
-
- ((LauncherTransitionable) toView).onLauncherTransitionEnd(instance,
- scaleAnim, false);
- }
-
- ......
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- animationCancelled = true;
- }
- });
-
-
-
- if (mStateAnimation != null) mStateAnimation.cancel();
- mStateAnimation = new AnimatorSet();
- mStateAnimation.play(scaleAnim).after(startDelay);
- mStateAnimation.start();
- } else {
-
- ......
- }
这里演示了使用ValueAnimator来实现动画效果的方式。动画结束之后,页面的切换就完成了。