Launcher 桌面的3D转屏效果实现(1)-matrix setPolyToPoly

从现有方法来讲为了实现桌面的3D转屏效果主要是通过Launcher中的workspace实现(现有的有源码的方法),具体实现见:

     http://www.eoeandroid.com/viewthread.php?tid=27079&extra=&page=1 (写这篇文章也是为了“报答”该作者开源的贡献,共同学习)

 

     不过该方法存在以下几个问题:

  1. 不同机器的分辨率和内存大小不同,从而使用cache保持截图的方法很有可能会出现内存方面的错误
  2. 界面上面的变化,例如图标增加和删除,需要程序对应做出很多修改,用以保证整体效果的统一。其根本原因就是修改的模块位置在Launcher中过于考上
  3. 图标变形和覆盖(我在2.2源码上总是搞不出来,╮(╯▽╰)╭)

     转载请注明http://ishelf.iteye.com/admin/blogs/836929

 

     依据以上问题本文从每个屏的dispatchDraw入手,修改CellLayout的dispatchDraw方法,这篇文章先给出2D的实现方式(利用Matrix实现):

      由于代码过多,本文只给出做过修改的代码

Java代码   收藏代码
  1. ///CellLayout.java  
  2.   
  3.    
  4.   @Override  
  5.     public void dispatchDraw(Canvas canvas) {  
  6.         long start_time = System.currentTimeMillis();  
  7.         startRotate(canvas, currentX, canvas.getWidth(), canvas.getHeight());  
  8.         super.dispatchDraw(canvas);  
  9.         canvas.restore();  
  10.         long end_time = System.currentTimeMillis();  
  11.         Log.d("CellLayout" + currentScrenn, (end_time - start_time) + " ms");  
  12.     }  
  13.     // 上面的Log信息是用来对比用opengl实现两者效率  
  14.      
  15.     //startRotate使用来计算该屏显示的位置以及显示的大小,xCor是手指移动的位置大小  
  16.    public void startRotate(Canvas mCanvas, float xCor, int width, int height) {  
  17.         boolean flag = true;  
  18.         if (isCurrentScrenn && xCor < 0) {  
  19.             xCor = width + xCor;  
  20.             flag = false;  
  21.         } else if (isCurrentScrenn && xCor >= 0) {  
  22.             // xCor = width - xCor;  
  23.         } else if (!isCurrentScrenn && xCor < 0) {  
  24.             xCor = width + xCor;  
  25.         } else if (!isCurrentScrenn && xCor >= 0) {  
  26.             flag = false;  
  27.         }  
  28.         final float SPAN = 0.000424f;  
  29.         float f = xCor - 10;  
  30.         if (f <= 0) {  
  31.             f = 0;  
  32.             xCor = 10;  
  33.         }// the maximum left  
  34.         float value = f * SPAN;  
  35.         if (f > width) {  
  36.             xCor = width - 10;  
  37.             value = 0.127225f;  
  38.         }// the maximum right  
  39.   
  40.         if (isBorder) {  
  41.             doDraw(mCanvas, new float[] {  
  42.                     00, width, 0, width, height, 0, height  
  43.             }, new float[] {  
  44.                     00, width, 0, width, height, 0, height  
  45.             });  
  46.         } else if (!flag) {  
  47.             doDraw(mCanvas, new float[] {  
  48.                     00, width, 0, width, height, 0, height  
  49.             }, new float[] {  
  50.                     00, xCor, height * (1 / 7.0f - value), xCor, height * (6 / 7.0f + value), 0,  
  51.                     height  
  52.   
  53.             });  
  54.         } else {  
  55.             doDraw(mCanvas, new float[] {  
  56.                     00, width, 0, width, height, 0, height  
  57.             }, new float[] {  
  58.                     xCor, height * (1 / 30.0f + value), width, 0, width, height, xCor,  
  59.                     height * (29 / 30.0f - value)  
  60.             });  
  61.         }  
  62.     }  
  63.   
  64.     private Matrix mMatrix = new Matrix();  
  65.   
  66.     private int currentScrenn;  
  67.   
  68.     private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  69.   
  70.     private boolean isBorder;  
  71.      
  72.     //doDraw使用计算该屏如何变形,这里使用matrix的polyToPoly来实现,具体描述见APIDemo  
  73.     private void doDraw(Canvas canvas, float src[], float dst[]) {  
  74.         canvas.save();  
  75.         mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);  
  76.         canvas.concat(mMatrix);  
  77.         switch (currentScrenn) {  
  78.             case 0:  
  79.                 mPaint.setColor(Color.RED);  
  80.                 break;  
  81.             case 1:  
  82.                 mPaint.setColor(Color.BLUE);  
  83.                 break;  
  84.             case 2:  
  85.                 mPaint.setColor(Color.YELLOW);  
  86.                 break;  
  87.             case 3:  
  88.                 mPaint.setColor(Color.CYAN);  
  89.                 break;  
  90.             case 4:  
  91.                 mPaint.setColor(Color.GREEN);  
  92.                 break;  
  93.         }  
  94.         mPaint.setStyle(Paint.Style.FILL_AND_STROKE);  
  95.         canvas.drawRect(00, src[4], src[5], mPaint);  
  96.     }  

 

    以下是workspace,该类主要是要传给cellLayout移动的参数

 

Java代码   收藏代码
  1. // 该方法用来画屏     
  2.  protected void dispatchDraw(Canvas canvas) {  
  3.         boolean restore = false;  
  4.         int restoreCount = 0;  
  5.   
  6.         // ViewGroup.dispatchDraw() supports many features we don't need:  
  7.         // clip to padding, layout animation, animation listener, disappearing  
  8.         // children, etc. The following implementation attempts to fast-track  
  9.         // the drawing dispatch by drawing only what we know needs to be drawn.  
  10.   
  11.         boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;  
  12.         Log.d("Scroller","dispatchDraw"+mScrollX);  
  13.         // If we are not scrolling or flinging, draw only the current screen  
  14.         if (fastDraw) {  
  15.             ((CellLayout) getChildAt(mCurrentScreen)).setPara(mCurrentScreen,  
  16.                     (mCurrentScreen - mCurrentScreen) >= 0 ? true : falsetrue,  
  17.                     mChangeMotionX - mLastMotionX);  
  18.             drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());  
  19.         } else {  
  20.             final long drawingTime = getDrawingTime();  
  21.             final float scrollPos = (float) mScrollX / getWidth();  
  22.             final int leftScreen = (int) scrollPos;  
  23.             final int rightScreen = leftScreen + 1;  
  24.           
  25.             if (leftScreen >= 0) {  
  26.                 ((CellLayout) getChildAt(leftScreen)).setPara(leftScreen,  
  27.                         (leftScreen - mCurrentScreen) >= 0 ? true : false, scrollPos == leftScreen,  
  28.                         mChangeMotionX - mLastMotionX);  
  29.                 drawChild(canvas, getChildAt(leftScreen), drawingTime);  
  30.             }  
  31.             if (scrollPos != leftScreen && rightScreen < getChildCount()) {  
  32.                 ((CellLayout) getChildAt(rightScreen)).setPara(rightScreen, mCurrentScreen  
  33.                         - rightScreen >= 0 ? true : false, scrollPos == leftScreen, mChangeMotionX  
  34.                         - mLastMotionX);  
  35.                 drawChild(canvas, getChildAt(rightScreen), drawingTime);  
  36.             }  
  37.         }  
  38.   
  39.         if (restore) {  
  40.             canvas.restoreToCount(restoreCount);  
  41.         }  
  42.     }  
  43.   
  44.     @Override  
  45.     public boolean onTouchEvent(MotionEvent ev) {  
  46.   
  47.         if (mLauncher.isWorkspaceLocked()) {  
  48.             return false// We don't want the events. Let them fall through to  
  49.             // the all apps view.  
  50.         }  
  51.         if (mLauncher.isAllAppsVisible()) {  
  52.             // Cancel any scrolling that is in progress.  
  53.             if (!mScroller.isFinished()) {  
  54.                 mScroller.abortAnimation();  
  55.             }  
  56.             snapToScreen(mCurrentScreen);  
  57.             return false// We don't want the events. Let them fall through to  
  58.             // the all apps view.  
  59.         }  
  60.   
  61.         if (mVelocityTracker == null) {  
  62.             mVelocityTracker = VelocityTracker.obtain();  
  63.         }  
  64.         mVelocityTracker.addMovement(ev);  
  65.   
  66.         final int action = ev.getAction();  
  67.   
  68.         switch (action & MotionEvent.ACTION_MASK) {  
  69.             case MotionEvent.ACTION_DOWN:  
  70.                 /* 
  71.                  * If being flinged and user touches, stop the fling. isFinished 
  72.                  * will be false if being flinged. 
  73.                  */  
  74.                 if (!mScroller.isFinished()) {  
  75.                     mScroller.abortAnimation();  
  76.                 }  
  77.   
  78.                 // Remember where the motion event started  
  79.                 mLastMotionX = ev.getX();  
  80.                 mChangeMotionX = mLastMotionX;  
  81.                 mActivePointerId = ev.getPointerId(0);  
  82.                 if (mTouchState == TOUCH_STATE_SCROLLING) {  
  83.                     enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);  
  84.                 }  
  85.                 break;  
  86.             case MotionEvent.ACTION_MOVE:  
  87.                 if (mTouchState == TOUCH_STATE_SCROLLING) {  
  88.                     // Scroll to follow the motion event  
  89.                     final int pointerIndex = ev.findPointerIndex(mActivePointerId);  
  90.                     final float x = ev.getX(pointerIndex);  
  91.                     final float deltaX = mLastMotionX - x;  
  92.                     mLastMotionX = x;  
  93.                     if (deltaX < 0) {  
  94.                         if (mTouchX > 0) {  
  95.                             mTouchX += Math.max(-mTouchX, deltaX);  
  96.                             mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  97.                             invalidate();  
  98.                         }  
  99.                     } else if (deltaX > 0) {  
  100.                         final float availableToScroll = getChildAt(getChildCount() - 1).getRight()  
  101.                                 - mTouchX - getWidth();  
  102.                         if (availableToScroll > 0) {  
  103.                             mTouchX += Math.min(availableToScroll, deltaX);  
  104.                             mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  105.                             invalidate();  
  106.                         }  
  107.                     } else {  
  108.                         awakenScrollBars();  
  109.                     }  
  110.                 }  
  111.                 break;  
  112.             case MotionEvent.ACTION_UP:  
  113.                 if (mTouchState == TOUCH_STATE_SCROLLING) {  
  114.                     final VelocityTracker velocityTracker = mVelocityTracker;  
  115.                     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
  116.                     final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);  
  117.   
  118.                     final int screenWidth = getWidth();  
  119.                     final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;  
  120.                     final float scrolledPos = (float) mScrollX / screenWidth;  
  121.   
  122.                     mChangeMotionX = mLastMotionX;  
  123.                     if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {  
  124.                         // Fling hard enough to move left.  
  125.                         // Don't fling across more than one screen at a time.  
  126.                         final int bound = scrolledPos < whichScreen ? mCurrentScreen - 1  
  127.                                 : mCurrentScreen;  
  128.                         snapToScreen(Math.min(whichScreen, bound), velocityX, true);  
  129.                     } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {  
  130.                         // Fling hard enough to move right  
  131.                         // Don't fling across more than one screen at a time.  
  132.                         final int bound = scrolledPos > whichScreen ? mCurrentScreen + 1  
  133.                                 : mCurrentScreen;  
  134.                         snapToScreen(Math.max(whichScreen, bound), velocityX, true);  
  135.                     } else {  
  136.                         snapToScreen(whichScreen, 0true);  
  137.                     }  
  138.   
  139.                     if (mVelocityTracker != null) {  
  140.                         mVelocityTracker.recycle();  
  141.                         mVelocityTracker = null;  
  142.                     }  
  143.                 }  
  144.                 mTouchState = TOUCH_STATE_REST;  
  145.                 mActivePointerId = INVALID_POINTER;  
  146.                 break;  
  147.             case MotionEvent.ACTION_CANCEL:  
  148.                 mTouchState = TOUCH_STATE_REST;  
  149.                 mActivePointerId = INVALID_POINTER;  
  150.                 break;  
  151.             case MotionEvent.ACTION_POINTER_UP:  
  152.                 onSecondaryPointerUp(ev);  
  153.                 break;  
  154.         }  
  155.   
  156.         return true;  
  157.     }  
  158.   
  159.    //修改该方法主要目的是记录滑动的距离  
  160.     @Override  
  161.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  162.         final boolean workspaceLocked = mLauncher.isWorkspaceLocked();  
  163.         final boolean allAppsVisible = mLauncher.isAllAppsVisible();  
  164.         if (workspaceLocked || allAppsVisible) {  
  165.             return false// We don't want the events. Let them fall through to  
  166.             // the all apps view.  
  167.         }  
  168.   
  169.         /* 
  170.          * This method JUST determines whether we want to intercept the motion. 
  171.          * If we return true, onTouchEvent will be called and we do the actual 
  172.          * scrolling there. 
  173.          */  
  174.   
  175.         /* 
  176.          * Shortcut the most recurring case: the user is in the dragging state 
  177.          * and he is moving his finger. We want to intercept this motion. 
  178.          */  
  179.         final int action = ev.getAction();  
  180.         if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {  
  181.             return true;  
  182.         }  
  183.   
  184.         if (mVelocityTracker == null) {  
  185.             mVelocityTracker = VelocityTracker.obtain();  
  186.         }  
  187.         mVelocityTracker.addMovement(ev);  
  188.   
  189.         switch (action & MotionEvent.ACTION_MASK) {  
  190.             case MotionEvent.ACTION_MOVE: {  
  191.                 /* 
  192.                  * mIsBeingDragged == false, otherwise the shortcut would have 
  193.                  * caught it. Check whether the user has moved far enough from 
  194.                  * his original down touch. 
  195.                  */  
  196.   
  197.                 /* 
  198.                  * Locally do absolute value. mLastMotionX is set to the y value 
  199.                  * of the down event. 
  200.                  */  
  201.                 final int pointerIndex = ev.findPointerIndex(mActivePointerId);  
  202.                 final float x = ev.getX(pointerIndex);  
  203.                 final float y = ev.getY(pointerIndex);  
  204.                 final int xDiff = (int) Math.abs(x - mLastMotionX);  
  205.                 final int yDiff = (int) Math.abs(y - mLastMotionY);  
  206.   
  207.                 final int touchSlop = mTouchSlop;  
  208.                 boolean xMoved = xDiff > touchSlop;  
  209.                 boolean yMoved = yDiff > touchSlop;  
  210.   
  211.                 if (xMoved || yMoved) {  
  212.   
  213.                     if (xMoved) {  
  214.                         // Scroll if the user moved far enough along the X axis  
  215.                         mTouchState = TOUCH_STATE_SCROLLING;  
  216.                         mLastMotionX = x;  
  217.                         mTouchX = mScrollX;  
  218.                         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;  
  219.                         enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);  
  220.                     }  
  221.                     // Either way, cancel any pending longpress  
  222.                     if (mAllowLongPress) {  
  223.                         mAllowLongPress = false;  
  224.                         // Try canceling the long press. It could also have been  
  225.                         // scheduled  
  226.                         // by a distant descendant, so use the mAllowLongPress  
  227.                         // flag to block  
  228.                         // everything  
  229.                         final View currentScreen = getChildAt(mCurrentScreen);  
  230.                         currentScreen.cancelLongPress();  
  231.                     }  
  232.                 }  
  233.                 break;  
  234.             }  
  235.   
  236.             case MotionEvent.ACTION_DOWN: {  
  237.                 final float x = ev.getX();  
  238.                 final float y = ev.getY();  
  239.                 // Remember location of down touch  
  240.                 mLastMotionX = x;  
  241.                 mChangeMotionX = x;  
  242.                 mLastMotionY = y;  
  243.                 mActivePointerId = ev.getPointerId(0);  
  244.                 mAllowLongPress = true;  
  245.   
  246.                 /* 
  247.                  * If being flinged and user touches the screen, initiate drag; 
  248.                  * otherwise don't. mScroller.isFinished should be false when 
  249.                  * being flinged. 
  250.                  */  
  251.                 mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;  
  252.                 break;  
  253.             }  
  254.   
  255.             case MotionEvent.ACTION_CANCEL:  
  256.             case MotionEvent.ACTION_UP:  
  257.                 if (mTouchState != TOUCH_STATE_SCROLLING) {  
  258.                     final CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);  
  259.                     if (!currentScreen.lastDownOnOccupiedCell()) {  
  260.                         getLocationOnScreen(mTempCell);  
  261.                         // Send a tap to the wallpaper if the last down was on  
  262.                         // empty space  
  263.                         final int pointerIndex = ev.findPointerIndex(mActivePointerId);  
  264.                         mWallpaperManager.sendWallpaperCommand(getWindowToken(),  
  265.                                 "android.wallpaper.tap",  
  266.                                 mTempCell[0] + (int) ev.getX(pointerIndex), mTempCell[1]  
  267.                                         + (int) ev.getY(pointerIndex), 0null);  
  268.                     }  
  269.                 }  
  270.   
  271.                 // Release the drag  
  272.                 clearChildrenCache();  
  273.                 mTouchState = TOUCH_STATE_REST;  
  274.                 mActivePointerId = INVALID_POINTER;  
  275.                 mAllowLongPress = false;  
  276.   
  277.                 if (mVelocityTracker != null) {  
  278.                     mVelocityTracker.recycle();  
  279.                     mVelocityTracker = null;  
  280.                 }  
  281.   
  282.                 break;  
  283.   
  284.             case MotionEvent.ACTION_POINTER_UP:  
  285.                 onSecondaryPointerUp(ev);  
  286.                 break;  
  287.         }  
  288.   
  289.         /* 
  290.          * The only time we want to intercept motion events is if we are in the 
  291.          * drag mode. 
  292.          */  
  293.         return mTouchState != TOUCH_STATE_REST;  
  294.     }  

 

 

 

    这些类的修改特别是变换时一定要注意canvas的save和restore方法,不清楚的先百度一下,不然很容易就变形了。下篇讨论使用openGL实现的方法


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值