首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

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

2012-09-07 
Launcher 桌面的3D转屏效果实现(1)-matrix setPolyToPoly从现有方法来讲为了实现桌面的3D转屏效果主要是通

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

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

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

?

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

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

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

?

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

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

///CellLayout.java?  @Override    public void dispatchDraw(Canvas canvas) {        long start_time = System.currentTimeMillis();        startRotate(canvas, currentX, canvas.getWidth(), canvas.getHeight());        super.dispatchDraw(canvas);        canvas.restore();        long end_time = System.currentTimeMillis();        Log.d("CellLayout" + currentScrenn, (end_time - start_time) + " ms");    }    // 上面的Log信息是用来对比用opengl实现两者效率       //startRotate使用来计算该屏显示的位置以及显示的大小,xCor是手指移动的位置大小   public void startRotate(Canvas mCanvas, float xCor, int width, int height) {        boolean flag = true;        if (isCurrentScrenn && xCor < 0) {            xCor = width + xCor;            flag = false;        } else if (isCurrentScrenn && xCor >= 0) {            // xCor = width - xCor;        } else if (!isCurrentScrenn && xCor < 0) {            xCor = width + xCor;        } else if (!isCurrentScrenn && xCor >= 0) {            flag = false;        }        final float SPAN = 0.000424f;        float f = xCor - 10;        if (f <= 0) {            f = 0;            xCor = 10;        }// the maximum left        float value = f * SPAN;        if (f > width) {            xCor = width - 10;            value = 0.127225f;        }// the maximum right        if (isBorder) {            doDraw(mCanvas, new float[] {                    0, 0, width, 0, width, height, 0, height            }, new float[] {                    0, 0, width, 0, width, height, 0, height            });        } else if (!flag) {            doDraw(mCanvas, new float[] {                    0, 0, width, 0, width, height, 0, height            }, new float[] {                    0, 0, xCor, height * (1 / 7.0f - value), xCor, height * (6 / 7.0f + value), 0,                    height            });        } else {            doDraw(mCanvas, new float[] {                    0, 0, width, 0, width, height, 0, height            }, new float[] {                    xCor, height * (1 / 30.0f + value), width, 0, width, height, xCor,                    height * (29 / 30.0f - value)            });        }    }    private Matrix mMatrix = new Matrix();    private int currentScrenn;    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    private boolean isBorder;       //doDraw使用计算该屏如何变形,这里使用matrix的polyToPoly来实现,具体描述见APIDemo    private void doDraw(Canvas canvas, float src[], float dst[]) {        canvas.save();        mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);        canvas.concat(mMatrix);        switch (currentScrenn) {            case 0:                mPaint.setColor(Color.RED);                break;            case 1:                mPaint.setColor(Color.BLUE);                break;            case 2:                mPaint.setColor(Color.YELLOW);                break;            case 3:                mPaint.setColor(Color.CYAN);                break;            case 4:                mPaint.setColor(Color.GREEN);                break;        }        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);        canvas.drawRect(0, 0, src[4], src[5], mPaint);    }

?

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

?

// 该方法用来画屏    protected void dispatchDraw(Canvas canvas) {        boolean restore = false;        int restoreCount = 0;        // ViewGroup.dispatchDraw() supports many features we don't need:        // clip to padding, layout animation, animation listener, disappearing        // children, etc. The following implementation attempts to fast-track        // the drawing dispatch by drawing only what we know needs to be drawn.        boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;        Log.d("Scroller","dispatchDraw"+mScrollX);        // If we are not scrolling or flinging, draw only the current screen        if (fastDraw) {            ((CellLayout) getChildAt(mCurrentScreen)).setPara(mCurrentScreen,                    (mCurrentScreen - mCurrentScreen) >= 0 ? true : false, true,                    mChangeMotionX - mLastMotionX);            drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());        } else {            final long drawingTime = getDrawingTime();            final float scrollPos = (float) mScrollX / getWidth();            final int leftScreen = (int) scrollPos;            final int rightScreen = leftScreen + 1;                    if (leftScreen >= 0) {                ((CellLayout) getChildAt(leftScreen)).setPara(leftScreen,                        (leftScreen - mCurrentScreen) >= 0 ? true : false, scrollPos == leftScreen,                        mChangeMotionX - mLastMotionX);                drawChild(canvas, getChildAt(leftScreen), drawingTime);            }            if (scrollPos != leftScreen && rightScreen < getChildCount()) {                ((CellLayout) getChildAt(rightScreen)).setPara(rightScreen, mCurrentScreen                        - rightScreen >= 0 ? true : false, scrollPos == leftScreen, mChangeMotionX                        - mLastMotionX);                drawChild(canvas, getChildAt(rightScreen), drawingTime);            }        }        if (restore) {            canvas.restoreToCount(restoreCount);        }    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (mLauncher.isWorkspaceLocked()) {            return false; // We don't want the events. Let them fall through to            // the all apps view.        }        if (mLauncher.isAllAppsVisible()) {            // Cancel any scrolling that is in progress.            if (!mScroller.isFinished()) {                mScroller.abortAnimation();            }            snapToScreen(mCurrentScreen);            return false; // We don't want the events. Let them fall through to            // the all apps view.        }        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(ev);        final int action = ev.getAction();        switch (action & MotionEvent.ACTION_MASK) {            case MotionEvent.ACTION_DOWN:                /*                 * If being flinged and user touches, stop the fling. isFinished                 * will be false if being flinged.                 */                if (!mScroller.isFinished()) {                    mScroller.abortAnimation();                }                // Remember where the motion event started                mLastMotionX = ev.getX();                mChangeMotionX = mLastMotionX;                mActivePointerId = ev.getPointerId(0);                if (mTouchState == TOUCH_STATE_SCROLLING) {                    enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);                }                break;            case MotionEvent.ACTION_MOVE:                if (mTouchState == TOUCH_STATE_SCROLLING) {                    // Scroll to follow the motion event                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);                    final float x = ev.getX(pointerIndex);                    final float deltaX = mLastMotionX - x;                    mLastMotionX = x;                    if (deltaX < 0) {                        if (mTouchX > 0) {                            mTouchX += Math.max(-mTouchX, deltaX);                            mSmoothingTime = System.nanoTime() / NANOTIME_DIV;                            invalidate();                        }                    } else if (deltaX > 0) {                        final float availableToScroll = getChildAt(getChildCount() - 1).getRight()                                - mTouchX - getWidth();                        if (availableToScroll > 0) {                            mTouchX += Math.min(availableToScroll, deltaX);                            mSmoothingTime = System.nanoTime() / NANOTIME_DIV;                            invalidate();                        }                    } else {                        awakenScrollBars();                    }                }                break;            case MotionEvent.ACTION_UP:                if (mTouchState == TOUCH_STATE_SCROLLING) {                    final VelocityTracker velocityTracker = mVelocityTracker;                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);                    final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);                    final int screenWidth = getWidth();                    final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;                    final float scrolledPos = (float) mScrollX / screenWidth;                    mChangeMotionX = mLastMotionX;                    if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {                        // Fling hard enough to move left.                        // Don't fling across more than one screen at a time.                        final int bound = scrolledPos < whichScreen ? mCurrentScreen - 1                                : mCurrentScreen;                        snapToScreen(Math.min(whichScreen, bound), velocityX, true);                    } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {                        // Fling hard enough to move right                        // Don't fling across more than one screen at a time.                        final int bound = scrolledPos > whichScreen ? mCurrentScreen + 1                                : mCurrentScreen;                        snapToScreen(Math.max(whichScreen, bound), velocityX, true);                    } else {                        snapToScreen(whichScreen, 0, true);                    }                    if (mVelocityTracker != null) {                        mVelocityTracker.recycle();                        mVelocityTracker = null;                    }                }                mTouchState = TOUCH_STATE_REST;                mActivePointerId = INVALID_POINTER;                break;            case MotionEvent.ACTION_CANCEL:                mTouchState = TOUCH_STATE_REST;                mActivePointerId = INVALID_POINTER;                break;            case MotionEvent.ACTION_POINTER_UP:                onSecondaryPointerUp(ev);                break;        }        return true;    }   //修改该方法主要目的是记录滑动的距离    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        final boolean workspaceLocked = mLauncher.isWorkspaceLocked();        final boolean allAppsVisible = mLauncher.isAllAppsVisible();        if (workspaceLocked || allAppsVisible) {            return false; // We don't want the events. Let them fall through to            // the all apps view.        }        /*         * This method JUST determines whether we want to intercept the motion.         * If we return true, onTouchEvent will be called and we do the actual         * scrolling there.         */        /*         * Shortcut the most recurring case: the user is in the dragging state         * and he is moving his finger. We want to intercept this motion.         */        final int action = ev.getAction();        if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {            return true;        }        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(ev);        switch (action & MotionEvent.ACTION_MASK) {            case MotionEvent.ACTION_MOVE: {                /*                 * mIsBeingDragged == false, otherwise the shortcut would have                 * caught it. Check whether the user has moved far enough from                 * his original down touch.                 */                /*                 * Locally do absolute value. mLastMotionX is set to the y value                 * of the down event.                 */                final int pointerIndex = ev.findPointerIndex(mActivePointerId);                final float x = ev.getX(pointerIndex);                final float y = ev.getY(pointerIndex);                final int xDiff = (int) Math.abs(x - mLastMotionX);                final int yDiff = (int) Math.abs(y - mLastMotionY);                final int touchSlop = mTouchSlop;                boolean xMoved = xDiff > touchSlop;                boolean yMoved = yDiff > touchSlop;                if (xMoved || yMoved) {                    if (xMoved) {                        // Scroll if the user moved far enough along the X axis                        mTouchState = TOUCH_STATE_SCROLLING;                        mLastMotionX = x;                        mTouchX = mScrollX;                        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;                        enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);                    }                    // Either way, cancel any pending longpress                    if (mAllowLongPress) {                        mAllowLongPress = false;                        // Try canceling the long press. It could also have been                        // scheduled                        // by a distant descendant, so use the mAllowLongPress                        // flag to block                        // everything                        final View currentScreen = getChildAt(mCurrentScreen);                        currentScreen.cancelLongPress();                    }                }                break;            }            case MotionEvent.ACTION_DOWN: {                final float x = ev.getX();                final float y = ev.getY();                // Remember location of down touch                mLastMotionX = x;                mChangeMotionX = x;                mLastMotionY = y;                mActivePointerId = ev.getPointerId(0);                mAllowLongPress = true;                /*                 * If being flinged and user touches the screen, initiate drag;                 * otherwise don't. mScroller.isFinished should be false when                 * being flinged.                 */                mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;                break;            }            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:                if (mTouchState != TOUCH_STATE_SCROLLING) {                    final CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);                    if (!currentScreen.lastDownOnOccupiedCell()) {                        getLocationOnScreen(mTempCell);                        // Send a tap to the wallpaper if the last down was on                        // empty space                        final int pointerIndex = ev.findPointerIndex(mActivePointerId);                        mWallpaperManager.sendWallpaperCommand(getWindowToken(),                                "android.wallpaper.tap",                                mTempCell[0] + (int) ev.getX(pointerIndex), mTempCell[1]                                        + (int) ev.getY(pointerIndex), 0, null);                    }                }                // Release the drag                clearChildrenCache();                mTouchState = TOUCH_STATE_REST;                mActivePointerId = INVALID_POINTER;                mAllowLongPress = false;                if (mVelocityTracker != null) {                    mVelocityTracker.recycle();                    mVelocityTracker = null;                }                break;            case MotionEvent.ACTION_POINTER_UP:                onSecondaryPointerUp(ev);                break;        }        /*         * The only time we want to intercept motion events is if we are in the         * drag mode.         */        return mTouchState != TOUCH_STATE_REST;    }

?

?

?

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

12 楼 烧伤的火柴 2012-02-09   setPara函数是做什么用的呢? 13 楼 ishelf 2012-02-13   setPara烧伤的火柴 写道setPara函数是做什么用的呢?
你查看一下1.6的Launcher源码,这个是在1.6上开发的,早了 14 楼 烧伤的火柴 2012-02-20   ishelf 写道setPara烧伤的火柴 写道setPara函数是做什么用的呢?
你查看一下1.6的Launcher源码,这个是在1.6上开发的,早了
谢谢大师指点

热点排行