diff options
author | Winson Chung <winsonc@google.com> | 2015-03-24 17:33:30 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-03-24 17:33:30 +0000 |
commit | dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a (patch) | |
tree | 6e36274efd690e8a9657f88cb1d0bc3541b600c8 /src | |
parent | 10451a967f65c577010d359e1226fd0b5897dbe6 (diff) | |
parent | f819dc2bc782e93ac9ecc163a99af0da62821d31 (diff) | |
download | android_packages_apps_Trebuchet-dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a.tar.gz android_packages_apps_Trebuchet-dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a.tar.bz2 android_packages_apps_Trebuchet-dcb3fa6939c6f1c173e5c8ac3a52ae1093dbfb1a.zip |
Merge "Making the scrollbar scrubbable." into ub-launcher3-burnaby
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher3/AppsContainerRecyclerView.java | 227 | ||||
-rw-r--r-- | src/com/android/launcher3/AppsContainerView.java | 10 |
2 files changed, 189 insertions, 48 deletions
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java index c5a508c9c..4d6b9d412 100644 --- a/src/com/android/launcher3/AppsContainerRecyclerView.java +++ b/src/com/android/launcher3/AppsContainerRecyclerView.java @@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.MotionEvent; +import android.view.View; import android.view.ViewConfiguration; import java.util.List; @@ -42,7 +43,9 @@ public class AppsContainerRecyclerView extends RecyclerView private AlphabeticalAppsList mApps; private int mNumAppsPerRow; + private Drawable mScrollbar; private Drawable mFastScrollerBg; + private Rect mVerticalScrollbarBounds = new Rect(); private boolean mDraggingFastScroller; private String mFastScrollSectionName; private Paint mFastScrollTextPaint; @@ -52,7 +55,9 @@ public class AppsContainerRecyclerView extends RecyclerView private int mDownY; private int mLastX; private int mLastY; - private int mGutterSize; + private int mScrollbarWidth; + private int mScrollbarMinHeight; + private int mScrollbarInset; public AppsContainerRecyclerView(Context context) { this(context, null); @@ -72,14 +77,19 @@ public class AppsContainerRecyclerView extends RecyclerView Resources res = context.getResources(); int fastScrollerSize = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_popup_size); - mFastScrollerBg = res.getDrawable(R.drawable.apps_list_fastscroll_bg); + mScrollbar = context.getDrawable(R.drawable.apps_list_scrollbar_thumb); + mFastScrollerBg = context.getDrawable(R.drawable.apps_list_fastscroll_bg); mFastScrollerBg.setBounds(0, 0, fastScrollerSize, fastScrollerSize); mFastScrollTextPaint = new Paint(); mFastScrollTextPaint.setColor(Color.WHITE); mFastScrollTextPaint.setAntiAlias(true); mFastScrollTextPaint.setTextSize(res.getDimensionPixelSize( R.dimen.apps_view_fast_scroll_text_size)); - mGutterSize = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_gutter_size); + mScrollbarWidth = res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_bar_width); + mScrollbarMinHeight = + res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_bar_min_height); + mScrollbarInset = + res.getDimensionPixelSize(R.dimen.apps_view_fast_scroll_scrubber_touch_inset); setFastScrollerAlpha(getFastScrollerAlpha()); } @@ -112,6 +122,13 @@ public class AppsContainerRecyclerView extends RecyclerView return mFastScrollAlpha; } + /** + * Returns the scroll bar width. + */ + public int getScrollbarWidth() { + return mScrollbarWidth; + } + @Override protected void onFinishInflate() { addOnItemTouchListener(this); @@ -120,38 +137,13 @@ public class AppsContainerRecyclerView extends RecyclerView @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - - if (mFastScrollAlpha > 0f) { - boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == - LAYOUT_DIRECTION_RTL); - Rect bgBounds = mFastScrollerBg.getBounds(); - int restoreCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); - int x; - if (isRtl) { - x = getPaddingLeft() + getScrollBarSize(); - } else { - x = getWidth() - getPaddingRight() - getScrollBarSize() - bgBounds.width(); - } - int y = mLastY - (int) (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * bgBounds.height()); - y = Math.max(getPaddingTop(), Math.min(y, getHeight() - getPaddingBottom() - - bgBounds.height())); - canvas.translate(x, y); - mFastScrollerBg.setAlpha((int) (mFastScrollAlpha * 255)); - mFastScrollerBg.draw(canvas); - mFastScrollTextPaint.setAlpha((int) (mFastScrollAlpha * 255)); - mFastScrollTextPaint.getTextBounds(mFastScrollSectionName, 0, - mFastScrollSectionName.length(), mFastScrollTextBounds); - canvas.drawText(mFastScrollSectionName, - (bgBounds.width() - mFastScrollTextBounds.width()) / 2, - bgBounds.height() - (bgBounds.height() - mFastScrollTextBounds.height()) / 2, - mFastScrollTextPaint); - canvas.restoreToCount(restoreCount); - } + drawVerticalScrubber(canvas); + drawFastScrollerPopup(canvas); } /** * We intercept the touch handling only to support fast scrolling when initiated from the - * gutter. Otherwise, we fall back to the default RecyclerView touch handling. + * scroll bar. Otherwise, we fall back to the default RecyclerView touch handling. */ @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) { @@ -182,15 +174,7 @@ public class AppsContainerRecyclerView extends RecyclerView break; case MotionEvent.ACTION_MOVE: // Check if we are scrolling - boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == - LAYOUT_DIRECTION_RTL); - boolean isInGutter; - if (isRtl) { - isInGutter = mDownX < mGutterSize; - } else { - isInGutter = mDownX >= (getWidth() - mGutterSize); - } - if (!mDraggingFastScroller && isInGutter && + if (!mDraggingFastScroller && isPointNearScrollbar(mDownX, mDownY) && Math.abs(y - mDownY) > config.getScaledTouchSlop()) { getParent().requestDisallowInterceptTouchEvent(true); mDraggingFastScroller = true; @@ -230,6 +214,67 @@ public class AppsContainerRecyclerView extends RecyclerView } /** + * Returns whether a given point is near the scrollbar. + */ + private boolean isPointNearScrollbar(int x, int y) { + // Check if we are scrolling + updateVerticalScrollbarBounds(); + mVerticalScrollbarBounds.inset(mScrollbarInset, mScrollbarInset); + return mVerticalScrollbarBounds.contains(x, y); + } + + /** + * Draws the fast scroller popup. + */ + private void drawFastScrollerPopup(Canvas canvas) { + int x; + int y; + boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == + LAYOUT_DIRECTION_RTL); + + if (mFastScrollAlpha > 0f) { + // Calculate the position for the fast scroller popup + Rect bgBounds = mFastScrollerBg.getBounds(); + if (isRtl) { + x = getPaddingLeft() + getScrollBarSize(); + } else { + x = getWidth() - getPaddingRight() - getScrollBarSize() - bgBounds.width(); + } + y = mLastY - (int) (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * bgBounds.height()); + y = Math.max(getPaddingTop(), Math.min(y, getHeight() - getPaddingBottom() - + bgBounds.height())); + + // Draw the fast scroller popup + int restoreCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.translate(x, y); + mFastScrollerBg.setAlpha((int) (mFastScrollAlpha * 255)); + mFastScrollerBg.draw(canvas); + mFastScrollTextPaint.setAlpha((int) (mFastScrollAlpha * 255)); + mFastScrollTextPaint.getTextBounds(mFastScrollSectionName, 0, + mFastScrollSectionName.length(), mFastScrollTextBounds); + canvas.drawText(mFastScrollSectionName, + (bgBounds.width() - mFastScrollTextBounds.width()) / 2, + bgBounds.height() - (bgBounds.height() - mFastScrollTextBounds.height()) / 2, + mFastScrollTextPaint); + canvas.restoreToCount(restoreCount); + } + } + + /** + * Draws the vertical scrollbar. + */ + private void drawVerticalScrubber(Canvas canvas) { + updateVerticalScrollbarBounds(); + + // Draw the scroll bar + int restoreCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.translate(mVerticalScrollbarBounds.left, mVerticalScrollbarBounds.top); + mScrollbar.setBounds(0, 0, mScrollbarWidth, mVerticalScrollbarBounds.height()); + mScrollbar.draw(canvas); + canvas.restoreToCount(restoreCount); + } + + /** * Invalidates the fast scroller popup. */ private void invalidateFastScroller() { @@ -243,11 +288,7 @@ public class AppsContainerRecyclerView extends RecyclerView private String scrollToPositionAtProgress(float progress) { List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections(); // Get the total number of rows - int rowCount = 0; - for (AlphabeticalAppsList.SectionInfo info : sections) { - int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow); - rowCount += numRowsInSection; - } + int rowCount = getNumRows(); // Find the index of the first app in that row and scroll to that position int rowAtProgress = (int) (progress * rowCount); @@ -270,4 +311,100 @@ public class AppsContainerRecyclerView extends RecyclerView // Returns the section name of the row return mApps.getSectionNameForApp(appInfo); } + + /** + * Returns the bounds for the scrollbar. + */ + private void updateVerticalScrollbarBounds() { + int x; + int y; + boolean isRtl = (getResources().getConfiguration().getLayoutDirection() == + LAYOUT_DIRECTION_RTL); + + // Skip early if there are no items + if (mApps.getApps().isEmpty()) { + mVerticalScrollbarBounds.setEmpty(); + return; + } + + // Find the index and height of the first visible row (all rows have the same height) + int rowIndex = -1; + int rowTopOffset = -1; + int rowHeight = -1; + int rowCount = getNumRows(); + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + int position = getChildPosition(child); + if (position != NO_POSITION) { + AppInfo info = mApps.getApps().get(position); + if (info != AlphabeticalAppsList.SECTION_BREAK_INFO) { + int appIndex = mApps.getAppsWithoutSectionBreaks().indexOf(info); + rowIndex = findRowForAppIndex(appIndex); + rowTopOffset = getLayoutManager().getDecoratedTop(child); + rowHeight = child.getHeight(); + break; + } + } + } + + if (rowIndex != -1) { + int height = getHeight() - getPaddingTop() - getPaddingBottom(); + int totalScrollHeight = rowCount * rowHeight; + if (totalScrollHeight > height) { + int scrollbarHeight = Math.max(mScrollbarMinHeight, + (int) (height / ((float) totalScrollHeight / height))); + + // Calculate the position and size of the scroll bar + if (isRtl) { + x = getPaddingLeft(); + } else { + x = getWidth() - getPaddingRight() - mScrollbarWidth; + } + + // To calculate the offset, we compute the percentage of the total scrollable height + // that the user has already scrolled and then map that to the scroll bar bounds + int availableY = totalScrollHeight - height; + int availableScrollY = height - scrollbarHeight; + y = (rowIndex * rowHeight) - rowTopOffset; + y = getPaddingTop() + + (int) (((float) (getPaddingTop() + y) / availableY) * availableScrollY); + + mVerticalScrollbarBounds.set(x, y, x + mScrollbarWidth, y + scrollbarHeight); + return; + } + } + mVerticalScrollbarBounds.setEmpty(); + } + + /** + * Returns the row index for a given position in the list. + */ + private int findRowForAppIndex(int position) { + List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections(); + int appIndex = 0; + int rowCount = 0; + for (AlphabeticalAppsList.SectionInfo info : sections) { + int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow); + if (appIndex + info.numAppsInSection > position) { + return rowCount + ((position - appIndex) / mNumAppsPerRow); + } + appIndex += info.numAppsInSection; + rowCount += numRowsInSection; + } + return appIndex; + } + + /** + * Returns the total number of rows in the list. + */ + private int getNumRows() { + List<AlphabeticalAppsList.SectionInfo> sections = mApps.getSections(); + int rowCount = 0; + for (AlphabeticalAppsList.SectionInfo info : sections) { + int numRowsInSection = (int) Math.ceil((float) info.numAppsInSection / mNumAppsPerRow); + rowCount += numRowsInSection; + } + return rowCount; + } } diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java index ea12fa361..e7b6628cc 100644 --- a/src/com/android/launcher3/AppsContainerView.java +++ b/src/com/android/launcher3/AppsContainerView.java @@ -168,12 +168,16 @@ public class AppsContainerView extends FrameLayout implements DragSource, Insett mAppsListView.setAdapter(mAdapter); mAppsListView.setHasFixedSize(true); if (isRtl) { - mAppsListView.setPadding(mAppsListView.getPaddingLeft(), mAppsListView.getPaddingTop(), + mAppsListView.setPadding( + mAppsListView.getPaddingLeft(), + mAppsListView.getPaddingTop(), mAppsListView.getPaddingRight() + mContentMarginStart, mAppsListView.getPaddingBottom()); } else { - mAppsListView.setPadding(mAppsListView.getPaddingLeft() + mContentMarginStart, - mAppsListView.getPaddingTop(), mAppsListView.getPaddingRight(), + mAppsListView.setPadding( + mAppsListView.getPaddingLeft() + mContentMarginStart, + mAppsListView.getPaddingTop(), + mAppsListView.getPaddingRight(), mAppsListView.getPaddingBottom()); } if (mItemDecoration != null) { |