实现左右屏切换

 http://blog.csdn.net/sharetop/article/details/6313654

 

其实要实现这个效果在Android中并非难事,因为官方的Launcher已经有现成的源代码放在那儿了,就是那个Workspace.java。大家可以去http://android.git.kernel.org/ 下载。

 

而我们要做的事情就是分析它并精简它(毕竟我们只是打算左右滑动罢了,并不需要能创建快捷方式文件夹之类的东西,更不需要在上面拖放图标)。

 

 

  1. public class Workspace extends ViewGroup   
  2.  implements DropTarget, DragSource, DragScroller {  
  3.   
  4. }  

 

 

 

 

因此,不管是Drop还是Drag,统统不需要了:

 

  1. public class Workspace extends ViewGroup {  
  2.   
  3. }  

 

 

 

 

同时,把那些个接口所要求实现的方法,以及那些与Drag/Drop相关的成员变量都去掉吧。
看看我精简后剩下什么成员变量:

 

 

  1. private static final int INVALID_SCREEN = -1;  
  2.   
  3. private int mDefaultScreen;  
  4.   
  5. private boolean mFirstLayout = true;  
  6.   
  7. private int mCurrentScreen;  
  8. private int mNextScreen = INVALID_SCREEN;  
  9. private Scroller mScroller;  
  10.   
  11.   
  12. private float mLastMotionX;  
  13. private float mLastMotionY;  
  14.   
  15. private final static int TOUCH_STATE_REST = 0;  
  16. private final static int TOUCH_STATE_SCROLLING = 1;  
  17.   
  18. private int mTouchState = TOUCH_STATE_REST;  
  19.   
  20. private int mTouchSlop;  

 

 

 


以上足矣。

 

然后在Eclipse中会有大量的错误,没关系,删吧。

 

addView 是用来在代码中添加新的子view的方法,不需要,我们只需要在layout xml中直接指定就好了。
getOpenFolder/getOpenFolders 文件夹相关的,当然不需要了。
addInCurrentScreen/addWidget 都没什么用处了,可以删掉。
与Cell相关的那些也可以删掉。

 

因为我们的代码不能直接访问mScrollX,所以需要换成getScrollX()。这一点是需要特别注意的。

 

看看我精简后都剩下些什么方法:

 

 


最后只要不报错,就OK了。

 

我们来分析一下几个关键的方法,其一是 onTouchEvent:

 

 

  1. @Override  
  2. public boolean onTouchEvent(MotionEvent ev) {  
  3.      
  4.   
  5.     final int action = ev.getAction();  
  6.     final float x = ev.getX();  
  7.   
  8.     switch (action) {  
  9.     case MotionEvent.ACTION_DOWN:  
  10.   
  11.         if (!mScroller.isFinished()) {  
  12.             mScroller.abortAnimation();  
  13.         }  
  14.   
  15.         // Remember where the motion event started   
  16.         mLastMotionX = x;  
  17.         break;  
  18.     case MotionEvent.ACTION_MOVE:  
  19.  //跟着手指拖动屏幕的处理。   
  20.         if (mTouchState == TOUCH_STATE_SCROLLING) {  
  21.             // Scroll to follow the motion event   
  22.             final int deltaX = (int) (mLastMotionX - x);  
  23.             mLastMotionX = x;  
  24.              
  25.             if (deltaX < 0) {  
  26.                 if (getScrollX() > 0) {  
  27.                  scrollBy(Math.max(-1*getScrollX(), deltaX), 0);                          
  28.                 }  
  29.             } else if (deltaX > 0) {  
  30.                 final int availableToScroll = getChildAt(getChildCount() - 1).getRight() -  
  31.                         getScrollX() - getWidth();  
  32.                 if (availableToScroll > 0) {  
  33.                  scrollBy(Math.min(availableToScroll, deltaX), 0);  
  34.                 }  
  35.             }  
  36.         }  
  37.         break;  
  38.     case MotionEvent.ACTION_UP:  
  39.  //抬起手指后,切换屏幕的处理   
  40.         if (mTouchState == TOUCH_STATE_SCROLLING) {  
  41.          snapToDestination();  
  42.         }  
  43.         mTouchState = TOUCH_STATE_REST;  
  44.         break;  
  45.     case MotionEvent.ACTION_CANCEL:  
  46.         mTouchState = TOUCH_STATE_REST;  
  47.     }  
  48.   
  49.     return true;  
  50. }  

 

 

 


其二 snapToDestination和snapToScreen:

 

 

  1.   private void snapToDestination() {  
  2. //计算应该去哪个屏   
  3.        final int screenWidth = getWidth();  
  4.        final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;  
  5. //切换   
  6.        snapToScreen(whichScreen);  
  7.    }  
  8.   
  9.    void snapToScreen(int whichScreen) {  
  10.        if (!mScroller.isFinished()) return;  
  11.   
  12.        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));  
  13.        boolean changingScreens = whichScreen != mCurrentScreen;  
  14.          
  15.        mNextScreen = whichScreen;  
  16.          
  17.        View focusedChild = getFocusedChild();  
  18.        if (focusedChild != null && changingScreens && focusedChild == getChildAt(mCurrentScreen)) {  
  19.            focusedChild.clearFocus();  
  20.        }  
  21.   
  22.        //让mScroller启动滚动   
  23.        final int cx = getScrollX();  
  24.        final int newX = whichScreen * getWidth();  
  25.        final int delta = newX - cx;  
  26.        mScroller.startScroll(cx, 0, delta, 0, Math.abs(delta) * 4);  
  27.        invalidate();  
  28.    }  

 

 

 

其三 computeScroll,让Workspace滚动到合适的位置:

 

 

  1. @Override  
  2. public void computeScroll() {  
  3.     if (mScroller.computeScrollOffset()) {  
  4.         scrollTo(mScroller.getCurrX(),mScroller.getCurrY());  
  5.         postInvalidate();  
  6.     } else if (mNextScreen != INVALID_SCREEN) {  
  7.         mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));  
  8.         mNextScreen = INVALID_SCREEN;              
  9.     }  
  10.       
  11. }  

 

 

 

 

基本上就是这些了,其它方法都是辅助的,很好理解。

 

其实有一个问题,我们发现UCWeb主页下面有三个点指示当前所处的位置,这个指示器我的想法是可以放在Workspace外面来做,利用Workspace当前的mCurrentScreen值显示出当前正处于哪个屏。

 

给出我的layout xml描述:

 

 

  1.  <cn.sharetop.demo.ui.Workspace  
  2.   android:id="@id/friends_switcher"  
  3.   android:layout_width="fill_parent"   
  4.   android:layout_height="640.0dip"   
  5.   android:layout_weight="1.0"  
  6.   xmessenger:defaultScreen="0"  
  7.   >  
  8.   <include layout="@layout/screen1" />  
  9.   <include layout="@layout/screen2" />  
  10.     
  11.  </cn.sharetop.demo.ui.Workspace>  
  12. <TextView   
  13.   android:layout_width="fill_parent"   
  14.   android:layout_height="wrap_content"   
  15.   android:textColor="#000000"   
  16.   android:background="@android:color/transparent"   
  17.   android:gravity="center"   
  18.   android:text="[1]2" />  

 

 

 

就这样了。这个分页指示器就留给你自己去发挥了。

posted @ 2012-12-24 17:52  GreyWolf  阅读(302)  评论(0编辑  收藏  举报