正文  UI设计 > Launcher >

launcher修改--页面标记

大家看这篇文章的时候,可能已经看过在launcher 2.1上实现2.2的屏幕标记(http://gqdy365.iteye.com/blog/897636),使用一个imageView显示不同的图片,看一下android里面launcher2里面源代码的实现,在drawabl......

大家看这篇文章的时候,可能已经看过在launcher 2.1上实现2.2的屏幕标记(http://gqdy365.iteye.com/blog/897636),使用一个imageView显示不同的图片,看一下android里面launcher2里面源代码的实现,在drawable文件夹里面,可以找到一个home_arrows_left.xml的文件,内容如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <level-list xmlns:android="http://schemas.android.com/apk/res/android">
  3. <item android:maxLevel="0" android:drawable="@android:color/transparent" />
  4. <item android:maxLevel="1" android:drawable="@drawable/home_arrows_left_1" />
  5. <item android:maxLevel="2" android:drawable="@drawable/home_arrows_left_2" />
  6. <item android:maxLevel="3" android:drawable="@drawable/home_arrows_left_3" />
  7. <item android:maxLevel="4" android:drawable="@drawable/home_arrows_left_4" />
  8. </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文件中,

  1. <ImageView android:id="@+id/previous_screen"
  2. android:layout_width="93dip" <SPAN style="WHITE-SPACE: pre">
  3. </SPAN>android:layout_height="@dimen/button_bar_height"
  4. android:layout_gravity="bottom|left" <SPAN style="WHITE-SPACE: pre">
  5. </SPAN>android:layout_marginLeft="6dip"
  6. android:scaleType="center" <SPAN style="WHITE-SPACE: pre">
  7. </SPAN>android:src="@drawable/home_arrows_left"
  8. android:onClick="previousScreen" <SPAN style="WHITE-SPACE: pre">
  9. </SPAN>android:focusable="true"
  10. 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()方法中,有一下代码:

 

  1. mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
  2. mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
  3.  
  4. Drawable previous = mPreviousView.getDrawable();
  5. Drawable next = mNextView.getDrawable();
  6. 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()方法,

  1. void setIndicators(Drawable previous, Drawable next) {
  2. mPreviousIndicator = previous;
  3. mNextIndicator = next;
  4. previous.setLevel(mCurrentScreen);
  5. next.setLevel(mCurrentScreen);
  6. }
void setIndicators(Drawable previous, Drawable next) {
        mPreviousIndicator = previous;
        mNextIndicator = next;
        previous.setLevel(mCurrentScreen);
        next.setLevel(mCurrentScreen);
    }
让我们找到mCurrentScreen这个参数的定义(73行):
  1. private int mCurrentScreen;
private int mCurrentScreen;

定义的一个整数,对应着home_arrows_left.xml里面的maxLevel,不同的参数ImageView上面显示不同的图片,用以标记页面。

在上面的launcher代码中,有android:onClick="previousScreen" 注册了imageView的点击相应事件,在launcher.java中,对应的代码如下:

  1. @SuppressWarnings({"UnusedDeclaration"})
  2. public void previousScreen(View v) {
  3. if (!isAllAppsVisible()) {
  4. mWorkspace.scrollLeft();
  5. }
  6. }
  7.  
  8. @SuppressWarnings({"UnusedDeclaration"})
  9. public void nextScreen(View v) {
  10. if (!isAllAppsVisible()) {
  11. mWorkspace.scrollRight();
  12. }
  13. }
@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()方法的代码:
  1. public void scrollLeft() {
  2. clearVacantCache();
  3. if (mScroller.isFinished()) {
  4. if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
  5. } else {
  6. if (mNextScreen > 0) snapToScreen(mNextScreen - 1);
  7. }
  8. }
  9.  
  10. public void scrollRight() {
  11. clearVacantCache();
  12. if (mScroller.isFinished()) {
  13. if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
  14. } else {
  15. if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);
  16. }
  17. }
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中,代码如下:
  1. private void snapToScreen(int whichScreen, int velocity, boolean settle) {
  2. //if (!mScroller.isFinished()) return;
  3.  
  4. whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
  5.  
  6. clearVacantCache();
  7. enableChildrenCache(mCurrentScreen, whichScreen);
  8.  
  9. mNextScreen = whichScreen;
  10.  
  11. mPreviousIndicator.setLevel(mNextScreen);
  12. mNextIndicator.setLevel(mNextScreen);
  13. enableDragLayerChildrenCache();
  14.  
  15. View focusedChild = getFocusedChild();
  16. if (focusedChild != null && whichScreen != mCurrentScreen &&
  17. focusedChild == getChildAt(mCurrentScreen)) {
  18. focusedChild.clearFocus();
  19. }
  20.  
  21. final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
  22. final int newX = whichScreen * getWidth();
  23. final int delta = newX - mScrollX;
  24. int duration = (screenDelta + 1) * 100;
  25.  
  26. if (!mScroller.isFinished()) {
  27. mScroller.abortAnimation();
  28. }
  29.  
  30. if (settle) {
  31. mScrollInterpolator.setDistance(screenDelta);
  32. } else {
  33. mScrollInterpolator.disableSettle();
  34. }
  35.  
  36. velocity = Math.abs(velocity);
  37. if (velocity > 0) {
  38. duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
  39. * FLING_VELOCITY_INFLUENCE;
  40. } else {
  41. duration += 100;
  42. }
  43.  
  44. awakenScrollBars(duration);
  45. mScroller.startScroll(mScrollX, 0, delta, 0, duration*2/3);
  46. invalidate();
  47. }
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();
    }

这就是其实现的基本过程。