Android Launcher修改--左右滑动屏幕切换源码追踪


在Android的源代码中,屏幕之间的跳转是如何实现的呢?在workspace.java中开始。在这个类中,为实现屏幕切换主要重写了以下几个方法:onMeasure()、onLayout()、onInterceptTouchEvent()、onTouchEvent()方法,另外还是用了CustomScroller mScroller来平滑过渡各个页面之间的切换。

首先,我们看一下onMeasure()方法:

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  3.         final int width = MeasureSpec.getSize(widthMeasureSpec);  
  4.         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  5.         if (widthMode != MeasureSpec.EXACTLY) {  
  6.             throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");  
  7.         }  
  8.         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  9.         if (heightMode != MeasureSpec.EXACTLY) {  
  10.             throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");  
  11.         }  
  12.   
  13.         // The children are given the same width and height as the workspace   
  14.         final int count = getChildCount();  
  15.         for (int i = 0; i < count; i++) {  
  16.             getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  
  17.         }  
  18.         //ADW: measure wallpaper when using old rendering   
  19.         if(!lwpSupport){  
  20.             if (mWallpaperLoaded) {  
  21.                 mWallpaperLoaded = false;  
  22.                 mWallpaperWidth = mWallpaperDrawable.getIntrinsicWidth();  
  23.                 mWallpaperHeight = mWallpaperDrawable.getIntrinsicHeight();  
  24.             }  
  25.   
  26.             final int wallpaperWidth = mWallpaperWidth;  
  27.             mWallpaperOffset = wallpaperWidth > width ? (count * width - wallpaperWidth) /  
  28.                     ((count - 1) * (float) width) : 1.0f;  
  29.         }  
  30.         if (mFirstLayout) {  
  31.             scrollTo(mCurrentScreen * width, 0);  
  32.             mScroller.startScroll(00, mCurrentScreen * width, 00);  
  33.             if(lwpSupport)updateWallpaperOffset(width * (getChildCount() - 1));  
  34.             mFirstLayout = false;  
  35.         }  
  36.         /*int max = 3; 
  37.         int aW = getMeasuredWidth(); 
  38.         float w = aW / max; 
  39.         maxPreviewWidth=(int) w; 
  40.         maxPreviewHeight=(int) (getMeasuredHeight()*(w/getMeasuredWidth()));*/  
  41.     }  
在这里,得到屏幕的宽高,然后再枚举其中所有的子view,设置它们的布局(使他们的���和父控件一样),这样每一个子view就是充满屏幕可以滑动显示的其中一页。
       下面是onLayout()方法:
  1. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  2.         int childLeft = 0;  
  3.         final int count = getChildCount();  
  4.         for (int i = 0; i < count; i++) {  
  5.             final View child = getChildAt(i);  
  6.             if (child.getVisibility() != View.GONE) {  
  7.                 final int childWidth = child.getMeasuredWidth();  
  8.                 child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());  
  9.                 childLeft += childWidth;  
  10.             }  
  11.         }  
  12.         //ADW:updateWallpaperoffset   
  13.         if(lwpSupport){  
  14.             if(mWallpaperScroll)  
  15.                 updateWallpaperOffset();  
  16.             else  
  17.                 centerWallpaperOffset();  
  18.         }  
  19.     }  
onLayout方法中,横向画出每一个子view,view的高与屏幕高一致,宽度为getChildCount()-1个屏幕宽度的view。

再看一下onInterceptTouchEvent()方法:

  1. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  2.         if(mStatus==SENSE_OPEN){  
  3.             if(ev.getAction()==MotionEvent.ACTION_DOWN){  
  4.                 findClickedPreview(ev.getX(),ev.getY());  
  5.             }  
  6.             return true;  
  7.         }  
  8.   
  9.         //Wysie: If multitouch event is detected   
  10.         if (multiTouchController.onTouchEvent(ev)) {  
  11.             return false;  
  12.         }  
  13.   
  14.         if (mLocked || mLauncher.isAllAppsVisible()) {  
  15.             return true;  
  16.         }  
  17.   
  18.         /* 
  19.          * This method JUST determines whether we want to intercept the motion. 
  20.          * If we return true, onTouchEvent will be called and we do the actual 
  21.          * scrolling there. 
  22.          */  
  23.   
  24.         /* 
  25.          * Shortcut the most recurring case: the user is in the dragging 
  26.          * state and he is moving his finger.  We want to intercept this 
  27.          * motion. 
  28.          */  
  29.         final int action = ev.getAction();  
  30.         if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {  
  31.             return true;  
  32.         }  
  33.   
  34.         final float x = ev.getX();  
  35.         final float y = ev.getY();  
  36.   
  37.         switch (action) {  
  38.             case MotionEvent.ACTION_MOVE:  
  39.                 /* 
  40.                  * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 
  41.                  * whether the user has moved far enough from his original down touch. 
  42.                  */  
  43.   
  44.                 /* 
  45.                  * Locally do absolute value. mLastMotionX is set to the y value 
  46.                  * of the down event. 
  47.                  */  
  48.                 final int xDiff = (int) Math.abs(x - mLastMotionX);  
  49.                 final int yDiff = (int) Math.abs(y - mLastMotionY);  
  50.   
  51.                 final int touchSlop = mTouchSlop;  
  52.                 boolean xMoved = xDiff > touchSlop;  
  53.                 boolean yMoved = yDiff > touchSlop;  
  54.                 if (xMoved || yMoved) {  
  55.                     // If xDiff > yDiff means the finger path pitch is smaller than 45deg so we assume the user want to scroll X axis   
  56.                     if (xDiff > yDiff) {  
  57.                         // Scroll if the user moved far enough along the X axis   
  58.                         mTouchState = TOUCH_STATE_SCROLLING;  
  59.                         enableChildrenCache();  
  60.   
  61.                     }  
  62.                     // If yDiff > xDiff means the finger path pitch is bigger than 45deg so we assume the user want to either scroll Y or Y-axis gesture   
  63.                     else if (getOpenFolder()==null)  
  64.                     {  
  65.                         // As x scrolling is left untouched (more or less untouched;)), every gesture should start by dragging in Y axis. In fact I only consider useful, swipe up and down.   
  66.                         // Guess if the first Pointer where the user click belongs to where a scrollable widget is.   
  67.                         mTouchedScrollableWidget = isWidgetAtLocationScrollable((int)mLastMotionX,(int)mLastMotionY);  
  68.                         if (!mTouchedScrollableWidget)  
  69.                         {  
  70.                             // Only y axis movement. So may be a Swipe down or up gesture   
  71.                             if ((y - mLastMotionY) > 0){  
  72.                                 if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_DOWN_GESTURE;  
  73.                             }else{  
  74.                                 if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_UP_GESTURE;  
  75.                             }  
  76.                         }  
  77.                     }  
  78.                     // Either way, cancel any pending longpress   
  79.                     if (mAllowLongPress) {  
  80.                         mAllowLongPress = false;  
  81.                         // Try canceling the long press. It could also have been scheduled   
  82.                         // by a distant descendant, so use the mAllowLongPress flag to block   
  83.                         // everything   
  84.                         final View currentScreen = getChildAt(mCurrentScreen);  
  85.                         currentScreen.cancelLongPress();  
  86.                     }  
  87.                 }  
  88.                 break;  
  89.   
  90.             case MotionEvent.ACTION_DOWN:  
  91.                 // Remember location of down touch   
  92.                 mLastMotionX = x;  
  93.                 mLastMotionY = y;  
  94.                 mAllowLongPress = true;  
  95.   
  96.                 /* 
  97.                  * If being flinged and user touches the screen, initiate drag; 
  98.                  * otherwise don't.  mScroller.isFinished should be false when 
  99.                  * being flinged. 
  100.                  */  
  101.                 mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;  
  102.                 break;  
  103.   
  104.             case MotionEvent.ACTION_CANCEL:  
  105.             case MotionEvent.ACTION_UP:  
  106.   
  107.                 if (mTouchState != TOUCH_STATE_SCROLLING && mTouchState != TOUCH_SWIPE_DOWN_GESTURE && mTouchState != TOUCH_SWIPE_UP_GESTURE) {  
  108.                     final CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);  
  109.                     if (!currentScreen.lastDownOnOccupiedCell()) {  
  110.                         getLocationOnScreen(mTempCell);  
  111.                         // Send a tap to the wallpaper if the last down was on empty space   
  112.                         if(lwpSupport)  
  113.                         mWallpaperManager.sendWallpaperCommand(getWindowToken(),  
  114.                                 "android.wallpaper.tap",  
  115.                                 mTempCell[0] + (int) ev.getX(),  
  116.                                 mTempCell[1] + (int) ev.getY(), 0null);  
  117.                     }  
  118.                 }  
  119.                 // Release the drag   
  120.                 clearChildrenCache();  
  121.                 mTouchState = TOUCH_STATE_REST;  
  122.                 mAllowLongPress = false;  
  123.                 break;  
  124.         }  
  125.   
  126.         /* 
  127.          * The only time we want to intercept motion events is if we are in the 
  128.          * drag mode. 
  129.          */  
  130.         return mTouchState != TOUCH_STATE_REST;  
  131.     }  
  • 1
  • 2
  • 下一页

相关内容