歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android Launcher修改--左右滑動屏幕切換源碼追蹤

Android Launcher修改--左右滑動屏幕切換源碼追蹤

日期:2017/3/1 11:08:15   编辑:Linux編程
在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. // The children are given the same width and height as the workspace
  13. final int count = getChildCount();
  14. for (int i = 0; i < count; i++) {
  15. getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
  16. }
  17. //ADW: measure wallpaper when using old rendering
  18. if(!lwpSupport){
  19. if (mWallpaperLoaded) {
  20. mWallpaperLoaded = false;
  21. mWallpaperWidth = mWallpaperDrawable.getIntrinsicWidth();
  22. mWallpaperHeight = mWallpaperDrawable.getIntrinsicHeight();
  23. }
  24. final int wallpaperWidth = mWallpaperWidth;
  25. mWallpaperOffset = wallpaperWidth > width ? (count * width - wallpaperWidth) /
  26. ((count - 1) * (float) width) : 1.0f;
  27. }
  28. if (mFirstLayout) {
  29. scrollTo(mCurrentScreen * width, 0);
  30. mScroller.startScroll(0, 0, mCurrentScreen * width, 0, 0);
  31. if(lwpSupport)updateWallpaperOffset(width * (getChildCount() - 1));
  32. mFirstLayout = false;
  33. }
  34. /*int max = 3;
  35. int aW = getMeasuredWidth();
  36. float w = aW / max;
  37. maxPreviewWidth=(int) w;
  38. maxPreviewHeight=(int) (getMeasuredHeight()*(w/getMeasuredWidth()));*/
  39. }
在這裡,得到屏幕的寬高,然後再枚舉其中所有的子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. //Wysie: If multitouch event is detected
  9. if (multiTouchController.onTouchEvent(ev)) {
  10. return false;
  11. }
  12. if (mLocked || mLauncher.isAllAppsVisible()) {
  13. return true;
  14. }
  15. /*
  16. * This method JUST determines whether we want to intercept the motion.
  17. * If we return true, onTouchEvent will be called and we do the actual
  18. * scrolling there.
  19. */
  20. /*
  21. * Shortcut the most recurring case: the user is in the dragging
  22. * state and he is moving his finger. We want to intercept this
  23. * motion.
  24. */
  25. final int action = ev.getAction();
  26. if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
  27. return true;
  28. }
  29. final float x = ev.getX();
  30. final float y = ev.getY();
  31. switch (action) {
  32. case MotionEvent.ACTION_MOVE:
  33. /*
  34. * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
  35. * whether the user has moved far enough from his original down touch.
  36. */
  37. /*
  38. * Locally do absolute value. mLastMotionX is set to the y value
  39. * of the down event.
  40. */
  41. final int xDiff = (int) Math.abs(x - mLastMotionX);
  42. final int yDiff = (int) Math.abs(y - mLastMotionY);
  43. final int touchSlop = mTouchSlop;
  44. boolean xMoved = xDiff > touchSlop;
  45. boolean yMoved = yDiff > touchSlop;
  46. if (xMoved || yMoved) {
  47. // If xDiff > yDiff means the finger path pitch is smaller than 45deg so we assume the user want to scroll X axis
  48. if (xDiff > yDiff) {
  49. // Scroll if the user moved far enough along the X axis
  50. mTouchState = TOUCH_STATE_SCROLLING;
  51. enableChildrenCache();
  52. }
  53. // 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
  54. else if (getOpenFolder()==null)
  55. {
  56. // 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.
  57. // Guess if the first Pointer where the user click belongs to where a scrollable widget is.
  58. mTouchedScrollableWidget = isWidgetAtLocationScrollable((int)mLastMotionX,(int)mLastMotionY);
  59. if (!mTouchedScrollableWidget)
  60. {
  61. // Only y axis movement. So may be a Swipe down or up gesture
  62. if ((y - mLastMotionY) > 0){
  63. if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_DOWN_GESTURE;
  64. }else{
  65. if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_UP_GESTURE;
  66. }
  67. }
  68. }
  69. // Either way, cancel any pending longpress
  70. if (mAllowLongPress) {
  71. mAllowLongPress = false;
  72. // Try canceling the long press. It could also have been scheduled
  73. // by a distant descendant, so use the mAllowLongPress flag to block
  74. // everything
  75. final View currentScreen = getChildAt(mCurrentScreen);
  76. currentScreen.cancelLongPress();
  77. }
  78. }
  79. break;
  80. case MotionEvent.ACTION_DOWN:
  81. // Remember location of down touch
  82. mLastMotionX = x;
  83. mLastMotionY = y;
  84. mAllowLongPress = true;
  85. /*
  86. * If being flinged and user touches the screen, initiate drag;
  87. * otherwise don't. mScroller.isFinished should be false when
  88. * being flinged.
  89. */
  90. mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
  91. break;
  92. case MotionEvent.ACTION_CANCEL:
  93. case MotionEvent.ACTION_UP:
  94. if (mTouchState != TOUCH_STATE_SCROLLING && mTouchState != TOUCH_SWIPE_DOWN_GESTURE && mTouchState != TOUCH_SWIPE_UP_GESTURE) {
  95. final CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);
  96. if (!currentScreen.lastDownOnOccupiedCell()) {
  97. getLocationOnScreen(mTempCell);
  98. // Send a tap to the wallpaper if the last down was on empty space
  99. if(lwpSupport)
  100. mWallpaperManager.sendWallpaperCommand(getWindowToken(),
  101. "android.wallpaper.tap",
  102. mTempCell[0] + (int) ev.getX(),
  103. mTempCell[1] + (int) ev.getY(), 0, null);
  104. }
  105. }
  106. // Release the drag
  107. clearChildrenCache();
  108. mTouchState = TOUCH_STATE_REST;
  109. mAllowLongPress = false;
  110. break;
  111. }
  112. /*
  113. * The only time we want to intercept motion events is if we are in the
  114. * drag mode.
  115. */
  116. return mTouchState != TOUCH_STATE_REST;
  117. }
Copyright © Linux教程網 All Rights Reserved