您的位置:首页 > 移动开发

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

2014-03-02 19:42 543 查看
Android交流群1 QQ: 102063643 欢迎大家加入一起学习

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

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

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

[java] view
plaincopy

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()被调用。

[java] view
plaincopy

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()方法中

[java] view
plaincopy

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()方法。

[java] view
plaincopy

/**

* 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()方法。

[java] view
plaincopy

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():

[java] view
plaincopy

/**

* 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来实现动画效果的方式。动画结束之后,页面的切换就完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: