大家看这篇文章的时候,可能已经看过在launcher 2.1上实现2.2的屏幕标记(http://gqdy365.iteye.com/blog/897636),使用一个imageView显示不同的图片,看一下android里面launcher2里面源代码的实现,在drawable文件夹里面,可以找到一个home_arrows_left.xml的文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="0" android:drawable="@android:color/transparent" />
<item android:maxLevel="1" android:drawable="@drawable/home_arrows_left_1" />
<item android:maxLevel="2" android:drawable="@drawable/home_arrows_left_2" />
<item android:maxLevel="3" android:drawable="@drawable/home_arrows_left_3" />
<item android:maxLevel="4" android:drawable="@drawable/home_arrows_left_4" />
</level-list>
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="0" android:drawable="@android:color/transparent" />
<item android:maxLevel="1" android:drawable="@drawable/home_arrows_left_1" />
<item android:maxLevel="2" android:drawable="@drawable/home_arrows_left_2" />
<item android:maxLevel="3" android:drawable="@drawable/home_arrows_left_3" />
<item android:maxLevel="4" android:drawable="@drawable/home_arrows_left_4" />
</level-list>
同时,在launcher.xml文件中,
<ImageView android:id="@+id/previous_screen"
android:layout_width="93dip" <SPAN style="WHITE-SPACE: pre">
</SPAN>android:layout_height="@dimen/button_bar_height"
android:layout_gravity="bottom|left" <SPAN style="WHITE-SPACE: pre">
</SPAN>android:layout_marginLeft="6dip"
android:scaleType="center" <SPAN style="WHITE-SPACE: pre">
</SPAN>android:src="@drawable/home_arrows_left"
android:onClick="previousScreen" <SPAN style="WHITE-SPACE: pre">
</SPAN>android:focusable="true"
android:clickable="true" />
<ImageView android:id="@+id/previous_screen"
android:layout_width="93dip"
android:layout_height="@dimen/button_bar_height"
android:layout_gravity="bottom|left"
android:layout_marginLeft="6dip"
android:scaleType="center"
android:src="@drawable/home_arrows_left"
android:onClick="previousScreen"
android:focusable="true"
android:clickable="true" />
引用了这个文件,但是他真正在代码中是如何实现的哪,在launcher.java中的setupViews()方法中,有一下代码:
mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
Drawable previous = mPreviousView.getDrawable();
Drawable next = mNextView.getDrawable();
mWorkspace.setIndicators(previous, next);
mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
Drawable previous = mPreviousView.getDrawable();
Drawable next = mNextView.getDrawable();
mWorkspace.setIndicators(previous, next);
通过代码获取这个两旁的图片,然后我们再看一看在workspace.java里面的setIndicator()方法,
void setIndicators(Drawable previous, Drawable next) {
mPreviousIndicator = previous;
mNextIndicator = next;
previous.setLevel(mCurrentScreen);
next.setLevel(mCurrentScreen);
}
void setIndicators(Drawable previous, Drawable next) {
mPreviousIndicator = previous;
mNextIndicator = next;
previous.setLevel(mCurrentScreen);
next.setLevel(mCurrentScreen);
}
让我们找到mCurrentScreen这个参数的定义(73行):
private int mCurrentScreen;
private int mCurrentScreen;
定义的一个整数,对应着home_arrows_left.xml里面的maxLevel,不同的参数ImageView上面显示不同的图片,用以标记页面。
在上面的launcher代码中,有android:onClick="previousScreen" 注册了imageView的点击相应事件,在launcher.java中,对应的代码如下:
@SuppressWarnings({"UnusedDeclaration"})
public void previousScreen(View v) {
if (!isAllAppsVisible()) {
mWorkspace.scrollLeft();
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void nextScreen(View v) {
if (!isAllAppsVisible()) {
mWorkspace.scrollRight();
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void previousScreen(View v) {
if (!isAllAppsVisible()) {
mWorkspace.scrollLeft();
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void nextScreen(View v) {
if (!isAllAppsVisible()) {
mWorkspace.scrollRight();
}
}
我们继续追踪,在workspace.java代码中的scrollLeft和 scrollRight()方法的代码:
public void scrollLeft() {
clearVacantCache();
if (mScroller.isFinished()) {
if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
} else {
if (mNextScreen > 0) snapToScreen(mNextScreen - 1);
}
}
public void scrollRight() {
clearVacantCache();
if (mScroller.isFinished()) {
if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
} else {
if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);
}
}
public void scrollLeft() {
clearVacantCache();
if (mScroller.isFinished()) {
if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
} else {
if (mNextScreen > 0) snapToScreen(mNextScreen - 1);
}
}
public void scrollRight() {
clearVacantCache();
if (mScroller.isFinished()) {
if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
} else {
if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);
}
}
先判断是否滑动到头,然后跳转到目标屏,snapToScreen()方法代码也在workspace中,代码如下:
private void snapToScreen(int whichScreen, int velocity, boolean settle) {
//if (!mScroller.isFinished()) return;
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
clearVacantCache();
enableChildrenCache(mCurrentScreen, whichScreen);
mNextScreen = whichScreen;
mPreviousIndicator.setLevel(mNextScreen);
mNextIndicator.setLevel(mNextScreen);
enableDragLayerChildrenCache();
View focusedChild = getFocusedChild();
if (focusedChild != null && whichScreen != mCurrentScreen &&
focusedChild == getChildAt(mCurrentScreen)) {
focusedChild.clearFocus();
}
final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
final int newX = whichScreen * getWidth();
final int delta = newX - mScrollX;
int duration = (screenDelta + 1) * 100;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
if (settle) {
mScrollInterpolator.setDistance(screenDelta);
} else {
mScrollInterpolator.disableSettle();
}
velocity = Math.abs(velocity);
if (velocity > 0) {
duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
* FLING_VELOCITY_INFLUENCE;
} else {
duration += 100;
}
awakenScrollBars(duration);
mScroller.startScroll(mScrollX, 0, delta, 0, duration*2/3);
invalidate();
}
private void snapToScreen(int whichScreen, int velocity, boolean settle) {
//if (!mScroller.isFinished()) return;
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
clearVacantCache();
enableChildrenCache(mCurrentScreen, whichScreen);
mNextScreen = whichScreen;
mPreviousIndicator.setLevel(mNextScreen);
mNextIndicator.setLevel(mNextScreen);
enableDragLayerChildrenCache();
View focusedChild = getFocusedChild();
if (focusedChild != null && whichScreen != mCurrentScreen &&
focusedChild == getChildAt(mCurrentScreen)) {
focusedChild.clearFocus();
}
final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
final int newX = whichScreen * getWidth();
final int delta = newX - mScrollX;
int duration = (screenDelta + 1) * 100;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
if (settle) {
mScrollInterpolator.setDistance(screenDelta);
} else {
mScrollInterpolator.disableSettle();
}
velocity = Math.abs(velocity);
if (velocity > 0) {
duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
* FLING_VELOCITY_INFLUENCE;
} else {
duration += 100;
}
awakenScrollBars(duration);
mScroller.startScroll(mScrollX, 0, delta, 0, duration*2/3);
invalidate();
}
这就是其实现的基本过程。