diff options
author | Michael Jurka <mikejurka@google.com> | 2010-08-25 17:46:15 -0700 |
---|---|---|
committer | Michael Jurka <mikejurka@google.com> | 2010-09-01 14:54:34 -0700 |
commit | 0142d49e1378a7155bcca1fb59965d9e73016dbc (patch) | |
tree | 36d700bbf061564e34f359c2ef009ede5f88d20f /src/com/android/launcher2/PagedView.java | |
parent | 6b4adbc0558fcebbd44998bd00dcd334ddbee32d (diff) | |
download | packages_apps_trebuchet-0142d49e1378a7155bcca1fb59965d9e73016dbc.zip packages_apps_trebuchet-0142d49e1378a7155bcca1fb59965d9e73016dbc.tar.gz packages_apps_trebuchet-0142d49e1378a7155bcca1fb59965d9e73016dbc.tar.bz2 |
Changed Workspace to inherit from PagedView
- adds support for seeing dimmed side-pages on
home
- adds workspace support for pages that are
smaller than workspace itself
- removing a lot of code duplicated between
PagedView and Workspace
- tested new Workspace on Nexus One, and perf.
was indistinguishable from old Workspace in my
tests
Change-Id: Ie33ab4e8b35ac01b22894cff66650bb0ece8dfcc
Diffstat (limited to 'src/com/android/launcher2/PagedView.java')
-rw-r--r-- | src/com/android/launcher2/PagedView.java | 308 |
1 files changed, 223 insertions, 85 deletions
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java index 6154947..5052a59 100644 --- a/src/com/android/launcher2/PagedView.java +++ b/src/com/android/launcher2/PagedView.java @@ -42,37 +42,42 @@ import com.android.launcher.R; /** * An abstraction of the original Workspace which supports browsing through a - * sequential list of "pages" (or PagedViewCellLayouts). + * sequential list of "pages" */ public abstract class PagedView extends ViewGroup { private static final String TAG = "PagedView"; - private static final int INVALID_PAGE = -1; - - // the velocity at which a fling gesture will cause us to snap to the next page - private static final int SNAP_VELOCITY = 500; + protected static final int INVALID_PAGE = -1; // the min drag distance for a fling to register, to prevent random page shifts private static final int MIN_LENGTH_FOR_FLING = 50; - private boolean mFirstLayout = true; + protected static final float NANOTIME_DIV = 1000000000.0f; + + // the velocity at which a fling gesture will cause us to snap to the next page + protected int mSnapVelocity = 500; + + protected float mSmoothingTime; + protected float mTouchX; - private int mCurrentPage; - private int mNextPage = INVALID_PAGE; - private Scroller mScroller; + protected boolean mFirstLayout = true; + + protected int mCurrentPage; + protected int mNextPage = INVALID_PAGE; + protected Scroller mScroller; private VelocityTracker mVelocityTracker; private float mDownMotionX; private float mLastMotionX; private float mLastMotionY; - private final static int TOUCH_STATE_REST = 0; - private final static int TOUCH_STATE_SCROLLING = 1; - private final static int TOUCH_STATE_PREV_PAGE = 2; - private final static int TOUCH_STATE_NEXT_PAGE = 3; + protected final static int TOUCH_STATE_REST = 0; + protected final static int TOUCH_STATE_SCROLLING = 1; + protected final static int TOUCH_STATE_PREV_PAGE = 2; + protected final static int TOUCH_STATE_NEXT_PAGE = 3; - private int mTouchState = TOUCH_STATE_REST; + protected int mTouchState = TOUCH_STATE_REST; - private OnLongClickListener mLongClickListener; + protected OnLongClickListener mLongClickListener; private boolean mAllowLongPress = true; @@ -84,13 +89,29 @@ public abstract class PagedView extends ViewGroup { private int mActivePointerId = INVALID_POINTER; + private enum PageMovingState { PAGE_BEGIN_MOVING, PAGE_END_MOVING }; private PageSwitchListener mPageSwitchListener; + private PageMovingListener mPageMovingListener; private ArrayList<Boolean> mDirtyPageContent; private boolean mDirtyPageAlpha; protected PagedViewIconCache mPageViewIconCache; + // If true, syncPages and syncPageItems will be called to refresh pages + protected boolean mContentIsRefreshable = true; + + // If true, modify alpha of neighboring pages as user scrolls left/right + protected boolean mFadeInAdjacentScreens = true; + + // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding + // to switch to a new page + protected boolean mUsePagingTouchSlop = true; + + // If true, the subclass should directly update mScrollX itself in its computeScroll method + // (SmoothPagedView does this) + protected boolean mDeferScrollUpdate = false; + /** * Simple cache mechanism for PagedViewIcon outlines. */ @@ -117,6 +138,11 @@ public abstract class PagedView extends ViewGroup { void onPageSwitch(View newPage, int newPageIndex); } + public interface PageMovingListener { + void onPageBeginMoving(); + void onPageEndMoving(); + } + public PagedView(Context context) { this(context, null); } @@ -129,13 +155,13 @@ public abstract class PagedView extends ViewGroup { super(context, attrs, defStyle); setHapticFeedbackEnabled(false); - initWorkspace(); + init(); } /** * Initializes various states for this workspace. */ - private void initWorkspace() { + protected void init() { mDirtyPageContent = new ArrayList<Boolean>(); mDirtyPageContent.ensureCapacity(32); mPageViewIconCache = new PagedViewIconCache(); @@ -190,12 +216,20 @@ public abstract class PagedView extends ViewGroup { notifyPageSwitchListener(); } - private void notifyPageSwitchListener() { + protected void notifyPageSwitchListener() { if (mPageSwitchListener != null) { mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage); } } + // a method that subclasses can override to add behavior + protected void pageBeginMoving() { + } + + // a method that subclasses can override to add behavior + protected void pageEndMoving() { + } + /** * Registers the specified listener on each page contained in this workspace. * @@ -211,15 +245,31 @@ public abstract class PagedView extends ViewGroup { } @Override - public void computeScroll() { + public void scrollTo(int x, int y) { + super.scrollTo(x, y); + mTouchX = x; + mSmoothingTime = System.nanoTime() / NANOTIME_DIV; + } + + // we moved this functionality to a helper function so SmoothPagedView can reuse it + protected boolean computeScrollHelper() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); - postInvalidate(); + invalidate(); + return true; } else if (mNextPage != INVALID_PAGE) { mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1)); - notifyPageSwitchListener(); mNextPage = INVALID_PAGE; + notifyPageSwitchListener(); + pageEndMoving(); + return true; } + return false; + } + + @Override + public void computeScroll() { + computeScrollHelper(); } @Override @@ -247,6 +297,7 @@ public abstract class PagedView extends ViewGroup { if (mFirstLayout) { setHorizontalScrollBarEnabled(false); scrollTo(mCurrentPage * widthSize, 0); + mScroller.setFinalX(mCurrentPage * widthSize); setHorizontalScrollBarEnabled(true); mFirstLayout = false; } @@ -272,32 +323,67 @@ public abstract class PagedView extends ViewGroup { @Override protected void dispatchDraw(Canvas canvas) { - if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) { - int screenCenter = mScrollX + (getMeasuredWidth() / 2); - final int childCount = getChildCount(); - for (int i = 0; i < childCount; ++i) { - PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); - int childWidth = layout.getMeasuredWidth(); - int halfChildWidth = (childWidth / 2); - int childCenter = getChildOffset(i) + halfChildWidth; - int distanceFromScreenCenter = Math.abs(childCenter - screenCenter); - float alpha = 0.0f; - if (distanceFromScreenCenter < halfChildWidth) { - alpha = 1.0f; - } else if (distanceFromScreenCenter > childWidth) { - alpha = 0.0f; - } else { - float dimAlpha = (float) (distanceFromScreenCenter - halfChildWidth) / halfChildWidth; - dimAlpha = Math.max(0.0f, Math.min(1.0f, (dimAlpha * dimAlpha))); - alpha = 1.0f - dimAlpha; - } - if (Float.compare(alpha, layout.getAlpha()) != 0) { - layout.setAlpha(alpha); + if (mFadeInAdjacentScreens) { + if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) { + int screenCenter = mScrollX + (getMeasuredWidth() / 2); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; ++i) { + View layout = (View) getChildAt(i); + int childWidth = layout.getMeasuredWidth(); + int halfChildWidth = (childWidth / 2); + int childCenter = getChildOffset(i) + halfChildWidth; + int distanceFromScreenCenter = Math.abs(childCenter - screenCenter); + float alpha = 0.0f; + if (distanceFromScreenCenter < halfChildWidth) { + alpha = 1.0f; + } else if (distanceFromScreenCenter > childWidth) { + alpha = 0.0f; + } else { + float dimAlpha = (float) (distanceFromScreenCenter - halfChildWidth) / halfChildWidth; + dimAlpha = Math.max(0.0f, Math.min(1.0f, (dimAlpha * dimAlpha))); + alpha = 1.0f - dimAlpha; + } + if (Float.compare(alpha, layout.getAlpha()) != 0) { + layout.setAlpha(alpha); + } } + mDirtyPageAlpha = false; } - mDirtyPageAlpha = false; } - super.dispatchDraw(canvas); + + // Find out which screens are visible; as an optimization we only call draw on them + + // As an optimization, this code assumes that all pages have the same width as the 0th + // page. + final int pageWidth = getChildAt(0).getMeasuredWidth(); + final int pageCount = getChildCount(); + final int screenWidth = getMeasuredWidth(); + int x = getRelativeChildOffset(0) + pageWidth; + int leftScreen = 0; + int rightScreen = 0; + while (x <= mScrollX) { + leftScreen++; + x += pageWidth; + // replace above line with this if you don't assume all pages have same width as 0th + // page: + // x += getChildAt(leftScreen).getMeasuredWidth(); + } + rightScreen = leftScreen; + while (x < mScrollX + screenWidth) { + rightScreen++; + x += pageWidth; + // replace above line with this if you don't assume all pages have same width as 0th + // page: + //if (rightScreen < pageCount) { + // x += getChildAt(rightScreen).getMeasuredWidth(); + //} + } + rightScreen = Math.min(getChildCount() - 1, rightScreen); + + final long drawingTime = getDrawingTime(); + for (int i = leftScreen; i <= rightScreen; i++) { + drawChild(canvas, getChildAt(i), drawingTime); + } } @Override @@ -466,6 +552,7 @@ public abstract class PagedView extends ViewGroup { case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: // Release the drag + pageEndMoving(); mTouchState = TOUCH_STATE_REST; mAllowLongPress = false; mActivePointerId = INVALID_POINTER; @@ -522,10 +609,13 @@ public abstract class PagedView extends ViewGroup { boolean yMoved = yDiff > touchSlop; if (xMoved || yMoved) { - if (xPaged) { + if (mUsePagingTouchSlop ? xPaged : 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; + pageBeginMoving(); } // Either way, cancel any pending longpress if (mAllowLongPress) { @@ -561,6 +651,9 @@ public abstract class PagedView extends ViewGroup { // Remember where the motion event started mDownMotionX = mLastMotionX = ev.getX(); mActivePointerId = ev.getPointerId(0); + if (mTouchState == TOUCH_STATE_SCROLLING) { + pageBeginMoving(); + } break; case MotionEvent.ACTION_MOVE: @@ -574,14 +667,28 @@ public abstract class PagedView extends ViewGroup { int sx = getScrollX(); if (deltaX < 0) { if (sx > 0) { - scrollBy(Math.max(-sx, deltaX), 0); + mTouchX += Math.max(-mTouchX, deltaX); + mSmoothingTime = System.nanoTime() / NANOTIME_DIV; + if (!mDeferScrollUpdate) { + scrollBy(Math.max(-sx, deltaX), 0); + } else { + // This will trigger a call to computeScroll() on next drawChild() call + invalidate(); + } } } else if (deltaX > 0) { final int lastChildIndex = getChildCount() - 1; final int availableToScroll = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex) - sx; if (availableToScroll > 0) { - scrollBy(Math.min(availableToScroll, deltaX), 0); + mTouchX += Math.min(availableToScroll, deltaX); + mSmoothingTime = System.nanoTime() / NANOTIME_DIV; + if (!mDeferScrollUpdate) { + scrollBy(Math.min(availableToScroll, deltaX), 0); + } else { + // This will trigger a call to computeScroll() on next drawChild() call + invalidate(); + } } } else { awakenScrollBars(); @@ -602,11 +709,12 @@ public abstract class PagedView extends ViewGroup { int velocityX = (int) velocityTracker.getXVelocity(activePointerId); boolean isfling = Math.abs(mDownMotionX - x) > MIN_LENGTH_FOR_FLING; - if (isfling && velocityX > SNAP_VELOCITY && mCurrentPage > 0) { - snapToPage(mCurrentPage - 1); - } else if (isfling && velocityX < -SNAP_VELOCITY && + final int snapVelocity = mSnapVelocity; + if (isfling && velocityX > snapVelocity && mCurrentPage > 0) { + snapToPageWithVelocity(mCurrentPage - 1, velocityX); + } else if (isfling && velocityX < -snapVelocity && mCurrentPage < getChildCount() - 1) { - snapToPage(mCurrentPage + 1); + snapToPageWithVelocity(mCurrentPage + 1, velocityX); } else { snapToDestination(); } @@ -701,7 +809,7 @@ public abstract class PagedView extends ViewGroup { int screenCenter = mScrollX + (getMeasuredWidth() / 2); final int childCount = getChildCount(); for (int i = 0; i < childCount; ++i) { - PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); + View layout = (View) getChildAt(i); int childWidth = layout.getMeasuredWidth(); int halfChildWidth = (childWidth / 2); int childCenter = getChildOffset(i) + halfChildWidth; @@ -714,29 +822,47 @@ public abstract class PagedView extends ViewGroup { snapToPage(minDistanceFromScreenCenterIndex, 1000); } - void snapToPage(int whichPage) { + protected void snapToPageWithVelocity(int whichPage, int velocity) { + // We ignore velocity in this implementation, but children (e.g. SmoothPagedView) + // can use it + snapToPage(whichPage); + } + + protected void snapToPage(int whichPage) { snapToPage(whichPage, 1000); } - void snapToPage(int whichPage, int duration) { + protected void snapToPage(int whichPage, int duration) { whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1)); - mNextPage = whichPage; int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage); final int sX = getScrollX(); final int delta = newX - sX; + snapToPage(whichPage, delta, duration); + } + + protected void snapToPage(int whichPage, int delta, int duration) { + mNextPage = whichPage; + + View focusedChild = getFocusedChild(); + if (focusedChild != null && whichPage != mCurrentPage && + focusedChild == getChildAt(mCurrentPage)) { + focusedChild.clearFocus(); + } + + pageBeginMoving(); awakenScrollBars(duration); if (duration == 0) { duration = Math.abs(delta); } if (!mScroller.isFinished()) mScroller.abortAnimation(); - mScroller.startScroll(sX, 0, delta, 0, duration); + mScroller.startScroll(getScrollX(), 0, delta, 0, duration); // only load some associated pages loadAssociatedPages(mNextPage); - + notifyPageSwitchListener(); invalidate(); } @@ -793,6 +919,14 @@ public abstract class PagedView extends ViewGroup { return mAllowLongPress; } + /** + * Set true to allow long-press events to be triggered, usually checked by + * {@link Launcher} to accept or block dpad-initiated long-presses. + */ + public void setAllowLongPress(boolean allowLongPress) { + mAllowLongPress = allowLongPress; + } + public static class SavedState extends BaseSavedState { int currentPage = -1; @@ -824,23 +958,25 @@ public abstract class PagedView extends ViewGroup { } public void loadAssociatedPages(int page) { - final int count = getChildCount(); - if (page < count) { - int lowerPageBound = Math.max(0, page - 1); - int upperPageBound = Math.min(page + 1, count - 1); - for (int i = 0; i < count; ++i) { - final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); - final int childCount = layout.getChildCount(); - if (lowerPageBound <= i && i <= upperPageBound) { - if (mDirtyPageContent.get(i)) { - syncPageItems(i); - mDirtyPageContent.set(i, false); - } - } else { - if (childCount > 0) { - layout.removeAllViews(); + if (mContentIsRefreshable) { + final int count = getChildCount(); + if (page < count) { + int lowerPageBound = Math.max(0, page - 1); + int upperPageBound = Math.min(page + 1, count - 1); + for (int i = 0; i < count; ++i) { + final ViewGroup layout = (ViewGroup) getChildAt(i); + final int childCount = layout.getChildCount(); + if (lowerPageBound <= i && i <= upperPageBound) { + if (mDirtyPageContent.get(i)) { + syncPageItems(i); + mDirtyPageContent.set(i, false); + } + } else { + if (childCount > 0) { + layout.removeAllViews(); + } + mDirtyPageContent.set(i, true); } - mDirtyPageContent.set(i, true); } } } @@ -861,19 +997,21 @@ public abstract class PagedView extends ViewGroup { public abstract void syncPageItems(int page); public void invalidatePageData() { - // Update all the pages - syncPages(); + if (mContentIsRefreshable) { + // Update all the pages + syncPages(); - // Mark each of the pages as dirty - final int count = getChildCount(); - mDirtyPageContent.clear(); - for (int i = 0; i < count; ++i) { - mDirtyPageContent.add(true); - } + // Mark each of the pages as dirty + final int count = getChildCount(); + mDirtyPageContent.clear(); + for (int i = 0; i < count; ++i) { + mDirtyPageContent.add(true); + } - // Load any pages that are necessary for the current window of views - loadAssociatedPages(mCurrentPage); - mDirtyPageAlpha = true; - requestLayout(); + // Load any pages that are necessary for the current window of views + loadAssociatedPages(mCurrentPage); + mDirtyPageAlpha = true; + requestLayout(); + } } } |