桌面循环的Launcher主要是需要通过canvas的translate(dx, dy)来实现。比如现在有5屛,当屏幕向右滑动的时候,当mCurrentScreen=4(下标从0开始)时,继续往右滑动,这个时候需要判断该桌面是否需要循环,如果需要循环需要对代码做特殊处理,详细见代码:
if (deltaX < 0) { // left
if (mTouchX > 0) {
mTouchX += Math.max(-mTouchX, deltaX);
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
invalidate();
} else if (true && mTouchX > -getWidth()) {
mTouchX += deltaX;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
invalidate();
}
} else if (deltaX > 0) { // right
/*final float availableToScroll = getChildAt(getChildCount() - 1).getRight() -
mTouchX - getWidth();*/
final float availableToScroll = getChildAt(getChildCount() - 1).getRight() -
mTouchX - (true ? 0 : getWidth());
if (availableToScroll > 0) {
mTouchX += Math.min(availableToScroll, deltaX);
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
invalidate();
}
} else {
awakenScrollBars();
}
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 int whichScreen = (int)Math.floor((getScrollX() + (screenWidth / 2.0)) / screenWidth);
final float scrolledPos = (float) getScrollX() / screenWidth;
if (velocityX > SNAP_VELOCITY && mCurrentScreen > (true ? -1 : 0)/*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() - (true ? 0 : 1)/*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);
}
}
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
break;修改3:Worksapce的snapToScreen:
把whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));改为--->whichScreen = Math.max((true ? -1 : 0),
Math.min(whichScreen, getChildCount() - (true ? 0 : 1)));
修改4:Worksapce的computeScroll:
else if (mNextScreen != INVALID_SCREEN ) {
if (mNextScreen == -1 && true) {
mCurrentScreen = getChildCount() - 1;
scrollTo(mCurrentScreen * getWidth(), getScrollY());
updateWallpaperOffset();
} else if (mNextScreen == getChildCount() && true) {
mCurrentScreen = 0;
scrollTo(0, getScrollY());
updateWallpaperOffset();
} else {
mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
}
。。。。
最后最重要的是他的dispatchDraw,当scroller的坐标为(0,0)的时候,我们是滑动不了的,这个时候我们可以通过translate来移动坐标原点,到达移动的效果。具体的修改如下:
if (fastDraw) {
drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());
} else {
long drawingTime = getDrawingTime();
int width = getWidth();
float scrollPos = (float) getScrollX() / width;
boolean endlessScrolling = true;
int leftScreen;
int rightScreen;
boolean isScrollToRight = false;
int childCount = getChildCount();
if (scrollPos < 0 && endlessScrolling) {
leftScreen = childCount - 1;
rightScreen = 0;
} else {
leftScreen = Math.min( (int) scrollPos, childCount - 1 );
rightScreen = leftScreen + 1;
if (endlessScrolling) {
rightScreen = rightScreen % childCount;
isScrollToRight = true;
}
}
if (isScreenNoValid(leftScreen)) {
if (rightScreen == 0 && !isScrollToRight) { // 向左滑动,如果rightScreen是0
int offset = childCount * width;
canvas.translate(-offset, 0);
drawChild(canvas, getChildAt(leftScreen), drawingTime);
canvas.translate(+offset, 0);
} else {
drawChild(canvas, getChildAt(leftScreen), drawingTime);
}
}
if (scrollPos != leftScreen && isScreenNoValid(rightScreen)) {
if (endlessScrolling && rightScreen == 0 && isScrollToRight) {
int offset = childCount * width;
canvas.translate(+offset, 0);
drawChild(canvas, getChildAt(rightScreen), drawingTime);
canvas.translate(-offset, 0);
} else {
drawChild(canvas, getChildAt(rightScreen), drawingTime);
}
}
}
private
boolean
isScreenNoValid(
int
screen) {
return
screen >=
0
&& screen < getChildCount();
}
这样最后就完成了桌面的循环滚动哦。。。
这里还额外的需要修改几个地方:
在抽屉里拖动图标到桌面或者是从一个桌面拖动到其他桌面需要调用scrollLeft和scrollRight,所以我们需要稍作修改,如下
public void scrollLeft() {
clearVacantCache();
final int dest = true ? -1 : 0;
if (mScroller.isFinished()) {
if (mCurrentScreen > dest ) snapToScreen(mCurrentScreen - 1);
} else {
if (mNextScreen > dest ) snapToScreen(mNextScreen - 1);
}
}
public void scrollRight() {
clearVacantCache();
final int dest = true ? 0 : 1;
if (mScroller.isFinished()) {
if (mCurrentScreen < getChildCount() - dest ) snapToScreen(mCurrentScreen + 1);
} else {
if (mNextScreen < getChildCount() - dest ) snapToScreen(mNextScreen + 1);
}
}
以上就是修改Worksapce实现桌面循环滚动需要更改的地方,如以后发现有什么不足的地方,再额外补充。