Android交流群1 QQ: 102063643 欢迎大家加入一起学习
本文来自http://blog.youkuaiyun.com/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);
- }
接着,顺着启动的过程,进入到了Hotseat.resetLayout()方法中
- void resetLayout() {
- ......
- allAppsButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(android.view.View v) {
- if (mLauncher != null) {
- mLauncher.onClickAllAppsButton(v);
- }
- }
- });
- ......
- }
- /**
- * 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);
- }
- 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 {
- //不需要动画效果
- ......
- }
这里演示了使用ValueAnimator来实现动画效果的方式。动画结束之后,页面的切换就完成了。