Merge "Tweaking fast scroller to follow touch closer." into ub-launcher3-burnaby
This commit is contained in:
+2
-2
@@ -3,8 +3,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
-keep class com.android.launcher3.BaseRecyclerViewFastScrollBar {
|
-keep class com.android.launcher3.BaseRecyclerViewFastScrollBar {
|
||||||
public void setWidth(int);
|
public void setThumbWidth(int);
|
||||||
public int getWidth();
|
public int getThumbWidth();
|
||||||
public void setTrackAlpha(int);
|
public void setTrackAlpha(int);
|
||||||
public int getTrackAlpha();
|
public int getTrackAlpha();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,9 +92,15 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
// TODO(winsonc): If we want to animate the section heads while scrolling, we can
|
// TODO(winsonc): If we want to animate the section heads while scrolling, we can
|
||||||
// initiate that here if the recycler view scroll state is not
|
// initiate that here if the recycler view scroll state is not
|
||||||
// RecyclerView.SCROLL_STATE_IDLE.
|
// RecyclerView.SCROLL_STATE_IDLE.
|
||||||
|
|
||||||
|
onUpdateScrollbar(dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
mScrollbar.reattachThumbToScroll();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
@@ -143,7 +149,7 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
|
mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return mScrollbar.isDragging();
|
return mScrollbar.isDraggingThumb();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||||
@@ -185,12 +191,10 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
* AvailableScrollHeight = Total height of the all items - last page height
|
* AvailableScrollHeight = Total height of the all items - last page height
|
||||||
*
|
*
|
||||||
* This assumes that all rows are the same height.
|
* This assumes that all rows are the same height.
|
||||||
*
|
|
||||||
* @param yOffset the offset from the top of the recycler view to start tracking.
|
|
||||||
*/
|
*/
|
||||||
protected int getAvailableScrollHeight(int rowCount, int rowHeight, int yOffset) {
|
protected int getAvailableScrollHeight(int rowCount, int rowHeight) {
|
||||||
int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom;
|
int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom;
|
||||||
int scrollHeight = getPaddingTop() + yOffset + rowCount * rowHeight + getPaddingBottom();
|
int scrollHeight = getPaddingTop() + rowCount * rowHeight + getPaddingBottom();
|
||||||
int availableScrollHeight = scrollHeight - visibleHeight;
|
int availableScrollHeight = scrollHeight - visibleHeight;
|
||||||
return availableScrollHeight;
|
return availableScrollHeight;
|
||||||
}
|
}
|
||||||
@@ -222,7 +226,7 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
@Override
|
@Override
|
||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
super.dispatchDraw(canvas);
|
super.dispatchDraw(canvas);
|
||||||
onUpdateScrollbar();
|
onUpdateScrollbar(0);
|
||||||
mScrollbar.draw(canvas);
|
mScrollbar.draw(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,24 +238,21 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
* @param scrollPosState the current scroll position
|
* @param scrollPosState the current scroll position
|
||||||
* @param rowCount the number of rows, used to calculate the total scroll height (assumes that
|
* @param rowCount the number of rows, used to calculate the total scroll height (assumes that
|
||||||
* all rows are the same height)
|
* all rows are the same height)
|
||||||
* @param yOffset the offset to start tracking in the recycler view (only used for all apps)
|
|
||||||
*/
|
*/
|
||||||
protected void synchronizeScrollBarThumbOffsetToViewScroll(ScrollPositionState scrollPosState,
|
protected void synchronizeScrollBarThumbOffsetToViewScroll(ScrollPositionState scrollPosState,
|
||||||
int rowCount, int yOffset) {
|
int rowCount) {
|
||||||
int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight,
|
|
||||||
yOffset);
|
|
||||||
int availableScrollBarHeight = getAvailableScrollBarHeight();
|
|
||||||
|
|
||||||
// Only show the scrollbar if there is height to be scrolled
|
// Only show the scrollbar if there is height to be scrolled
|
||||||
|
int availableScrollBarHeight = getAvailableScrollBarHeight();
|
||||||
|
int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight);
|
||||||
if (availableScrollHeight <= 0) {
|
if (availableScrollHeight <= 0) {
|
||||||
mScrollbar.setScrollbarThumbOffset(-1, -1);
|
mScrollbar.setThumbOffset(-1, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the current scroll position, the scrollY of the recycler view accounts for the
|
// Calculate the current scroll position, the scrollY of the recycler view accounts for the
|
||||||
// view padding, while the scrollBarY is drawn right up to the background padding (ignoring
|
// view padding, while the scrollBarY is drawn right up to the background padding (ignoring
|
||||||
// padding)
|
// padding)
|
||||||
int scrollY = getPaddingTop() + yOffset +
|
int scrollY = getPaddingTop() +
|
||||||
(scrollPosState.rowIndex * scrollPosState.rowHeight) - scrollPosState.rowTopOffset;
|
(scrollPosState.rowIndex * scrollPosState.rowHeight) - scrollPosState.rowTopOffset;
|
||||||
int scrollBarY = mBackgroundPadding.top +
|
int scrollBarY = mBackgroundPadding.top +
|
||||||
(int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
|
(int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
|
||||||
@@ -261,9 +262,9 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
if (Utilities.isRtl(getResources())) {
|
if (Utilities.isRtl(getResources())) {
|
||||||
scrollBarX = mBackgroundPadding.left;
|
scrollBarX = mBackgroundPadding.left;
|
||||||
} else {
|
} else {
|
||||||
scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getWidth();
|
scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth();
|
||||||
}
|
}
|
||||||
mScrollbar.setScrollbarThumbOffset(scrollBarX, scrollBarY);
|
mScrollbar.setThumbOffset(scrollBarX, scrollBarY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -276,10 +277,15 @@ public abstract class BaseRecyclerView extends RecyclerView
|
|||||||
* Updates the bounds for the scrollbar.
|
* Updates the bounds for the scrollbar.
|
||||||
* <p>Override in each subclass of this base class.
|
* <p>Override in each subclass of this base class.
|
||||||
*/
|
*/
|
||||||
public abstract void onUpdateScrollbar();
|
public abstract void onUpdateScrollbar(int dy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Override in each subclass of this base class.
|
* <p>Override in each subclass of this base class.
|
||||||
*/
|
*/
|
||||||
public void onFastScrollCompleted() {}
|
public void onFastScrollCompleted() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns information about the item that the recycler view is currently scrolled to.
|
||||||
|
*/
|
||||||
|
protected abstract void getCurScrollState(ScrollPositionState stateOut);
|
||||||
}
|
}
|
||||||
@@ -56,9 +56,12 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
private int mThumbMaxWidth;
|
private int mThumbMaxWidth;
|
||||||
@Thunk int mThumbWidth;
|
@Thunk int mThumbWidth;
|
||||||
@Thunk int mThumbHeight;
|
@Thunk int mThumbHeight;
|
||||||
|
private float mLastTouchY;
|
||||||
// The inset is the buffer around which a point will still register as a click on the scrollbar
|
// The inset is the buffer around which a point will still register as a click on the scrollbar
|
||||||
private int mTouchInset;
|
private int mTouchInset;
|
||||||
private boolean mIsDragging;
|
private boolean mIsDragging;
|
||||||
|
private boolean mIsThumbDetached;
|
||||||
|
private boolean mCanThumbDetach;
|
||||||
|
|
||||||
// This is the offset from the top of the scrollbar when the user first starts touching. To
|
// This is the offset from the top of the scrollbar when the user first starts touching. To
|
||||||
// prevent jumping, this offset is applied as the user scrolls.
|
// prevent jumping, this offset is applied as the user scrolls.
|
||||||
@@ -84,7 +87,15 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
mTouchInset = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_touch_inset);
|
mTouchInset = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_touch_inset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScrollbarThumbOffset(int x, int y) {
|
public void setDetachThumbOnFastScroll() {
|
||||||
|
mCanThumbDetach = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reattachThumbToScroll() {
|
||||||
|
mIsThumbDetached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThumbOffset(int x, int y) {
|
||||||
if (mThumbOffset.x == x && mThumbOffset.y == y) {
|
if (mThumbOffset.x == x && mThumbOffset.y == y) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -95,8 +106,12 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
mRv.invalidate(mInvalidateRect);
|
mRv.invalidate(mInvalidateRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Point getThumbOffset() {
|
||||||
|
return mThumbOffset;
|
||||||
|
}
|
||||||
|
|
||||||
// Setter/getter for the search bar width for animations
|
// Setter/getter for the search bar width for animations
|
||||||
public void setWidth(int width) {
|
public void setThumbWidth(int width) {
|
||||||
mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight());
|
mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight());
|
||||||
mThumbWidth = width;
|
mThumbWidth = width;
|
||||||
mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth,
|
mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth,
|
||||||
@@ -104,7 +119,7 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
mRv.invalidate(mInvalidateRect);
|
mRv.invalidate(mInvalidateRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth() {
|
public int getThumbWidth() {
|
||||||
return mThumbWidth;
|
return mThumbWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,10 +142,18 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
return mThumbMaxWidth;
|
return mThumbMaxWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDragging() {
|
public float getLastTouchY() {
|
||||||
|
return mLastTouchY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDraggingThumb() {
|
||||||
return mIsDragging;
|
return mIsDragging;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isThumbDetached() {
|
||||||
|
return mIsThumbDetached;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the touch event and determines whether to show the fast scroller (or updates it if
|
* Handles the touch event and determines whether to show the fast scroller (or updates it if
|
||||||
* it is already showing).
|
* it is already showing).
|
||||||
@@ -152,6 +175,9 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
Math.abs(y - downY) > config.getScaledTouchSlop()) {
|
Math.abs(y - downY) > config.getScaledTouchSlop()) {
|
||||||
mRv.getParent().requestDisallowInterceptTouchEvent(true);
|
mRv.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
mIsDragging = true;
|
mIsDragging = true;
|
||||||
|
if (mCanThumbDetach) {
|
||||||
|
mIsThumbDetached = true;
|
||||||
|
}
|
||||||
mTouchOffset += (lastY - downY);
|
mTouchOffset += (lastY - downY);
|
||||||
mPopup.animateVisibility(true);
|
mPopup.animateVisibility(true);
|
||||||
animateScrollbar(true);
|
animateScrollbar(true);
|
||||||
@@ -166,11 +192,13 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
mPopup.setSectionName(sectionName);
|
mPopup.setSectionName(sectionName);
|
||||||
mPopup.animateVisibility(!sectionName.isEmpty());
|
mPopup.animateVisibility(!sectionName.isEmpty());
|
||||||
mRv.invalidate(mPopup.updateFastScrollerBounds(mRv, lastY));
|
mRv.invalidate(mPopup.updateFastScrollerBounds(mRv, lastY));
|
||||||
|
mLastTouchY = boundedY;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_CANCEL:
|
||||||
mTouchOffset = 0;
|
mTouchOffset = 0;
|
||||||
|
mLastTouchY = 0;
|
||||||
if (mIsDragging) {
|
if (mIsDragging) {
|
||||||
mIsDragging = false;
|
mIsDragging = false;
|
||||||
mPopup.animateVisibility(false);
|
mPopup.animateVisibility(false);
|
||||||
@@ -205,7 +233,7 @@ public class BaseRecyclerViewFastScrollBar {
|
|||||||
}
|
}
|
||||||
ObjectAnimator trackAlphaAnim = ObjectAnimator.ofInt(this, "trackAlpha",
|
ObjectAnimator trackAlphaAnim = ObjectAnimator.ofInt(this, "trackAlpha",
|
||||||
isScrolling ? MAX_TRACK_ALPHA : 0);
|
isScrolling ? MAX_TRACK_ALPHA : 0);
|
||||||
ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "width",
|
ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "thumbWidth",
|
||||||
isScrolling ? mThumbMaxWidth : mThumbMinWidth);
|
isScrolling ? mThumbMaxWidth : mThumbMinWidth);
|
||||||
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
|
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
|
||||||
mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor);
|
mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor);
|
||||||
|
|||||||
@@ -555,8 +555,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
|
|||||||
@Override
|
@Override
|
||||||
public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
|
public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
|
||||||
if (toWorkspace) {
|
if (toWorkspace) {
|
||||||
// Reset the search bar after transitioning home
|
// Reset the search bar and base recycler view after transitioning home
|
||||||
mSearchBarController.reset();
|
mSearchBarController.reset();
|
||||||
|
mAppsRecyclerView.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
|||||||
public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
|
public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
|
||||||
int defStyleRes) {
|
int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
|
mScrollbar.setDetachThumbOnFastScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,8 +169,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map the touch position back to the scroll of the recycler view
|
// Map the touch position back to the scroll of the recycler view
|
||||||
getCurScrollState(mScrollPosState, mApps.getAdapterItems());
|
getCurScrollState(mScrollPosState);
|
||||||
int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0);
|
int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight);
|
||||||
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
|
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
|
||||||
if (mFastScrollMode == FAST_SCROLL_MODE_FREE_SCROLL) {
|
if (mFastScrollMode == FAST_SCROLL_MODE_FREE_SCROLL) {
|
||||||
layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
|
layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
|
||||||
@@ -216,24 +217,73 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
|||||||
* Updates the bounds for the scrollbar.
|
* Updates the bounds for the scrollbar.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onUpdateScrollbar() {
|
public void onUpdateScrollbar(int dy) {
|
||||||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||||
|
|
||||||
// Skip early if there are no items or we haven't been measured
|
// Skip early if there are no items or we haven't been measured
|
||||||
if (items.isEmpty() || mNumAppsPerRow == 0) {
|
if (items.isEmpty() || mNumAppsPerRow == 0) {
|
||||||
mScrollbar.setScrollbarThumbOffset(-1, -1);
|
mScrollbar.setThumbOffset(-1, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the index and height of the first visible row (all rows have the same height)
|
// Find the index and height of the first visible row (all rows have the same height)
|
||||||
int rowCount = mApps.getNumAppRows();
|
int rowCount = mApps.getNumAppRows();
|
||||||
getCurScrollState(mScrollPosState, items);
|
getCurScrollState(mScrollPosState);
|
||||||
if (mScrollPosState.rowIndex < 0) {
|
if (mScrollPosState.rowIndex < 0) {
|
||||||
mScrollbar.setScrollbarThumbOffset(-1, -1);
|
mScrollbar.setThumbOffset(-1, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0);
|
// Only show the scrollbar if there is height to be scrolled
|
||||||
|
int availableScrollBarHeight = getAvailableScrollBarHeight();
|
||||||
|
int availableScrollHeight = getAvailableScrollHeight(mApps.getNumAppRows(), mScrollPosState.rowHeight);
|
||||||
|
if (availableScrollHeight <= 0) {
|
||||||
|
mScrollbar.setThumbOffset(-1, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the current scroll position, the scrollY of the recycler view accounts for the
|
||||||
|
// view padding, while the scrollBarY is drawn right up to the background padding (ignoring
|
||||||
|
// padding)
|
||||||
|
int scrollY = getPaddingTop() +
|
||||||
|
(mScrollPosState.rowIndex * mScrollPosState.rowHeight) - mScrollPosState.rowTopOffset;
|
||||||
|
int scrollBarY = mBackgroundPadding.top +
|
||||||
|
(int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
|
||||||
|
|
||||||
|
if (mScrollbar.isThumbDetached()) {
|
||||||
|
int scrollBarX;
|
||||||
|
if (Utilities.isRtl(getResources())) {
|
||||||
|
scrollBarX = mBackgroundPadding.left;
|
||||||
|
} else {
|
||||||
|
scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mScrollbar.isDraggingThumb()) {
|
||||||
|
// If the thumb is detached, then just update the thumb to the current
|
||||||
|
// touch position
|
||||||
|
mScrollbar.setThumbOffset(scrollBarX, (int) mScrollbar.getLastTouchY());
|
||||||
|
} else {
|
||||||
|
int thumbScrollY = mScrollbar.getThumbOffset().y;
|
||||||
|
int diffScrollY = scrollBarY - thumbScrollY;
|
||||||
|
if (diffScrollY * dy > 0f) {
|
||||||
|
// User is scrolling in the same direction the thumb needs to catch up to the
|
||||||
|
// current scroll position.
|
||||||
|
thumbScrollY += dy < 0 ? Math.max(dy, diffScrollY) : Math.min(dy, diffScrollY);
|
||||||
|
thumbScrollY = Math.max(0, Math.min(availableScrollBarHeight, thumbScrollY));
|
||||||
|
mScrollbar.setThumbOffset(scrollBarX, thumbScrollY);
|
||||||
|
if (scrollBarY == thumbScrollY) {
|
||||||
|
mScrollbar.reattachThumbToScroll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// User is scrolling in an opposite direction to the direction that the thumb
|
||||||
|
// needs to catch up to the scroll position. Do nothing except for updating
|
||||||
|
// the scroll bar x to match the thumb width.
|
||||||
|
mScrollbar.setThumbOffset(scrollBarX, thumbScrollY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -285,13 +335,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
|||||||
/**
|
/**
|
||||||
* Returns the current scroll state of the apps rows.
|
* Returns the current scroll state of the apps rows.
|
||||||
*/
|
*/
|
||||||
private void getCurScrollState(ScrollPositionState stateOut,
|
protected void getCurScrollState(ScrollPositionState stateOut) {
|
||||||
List<AlphabeticalAppsList.AdapterItem> items) {
|
|
||||||
stateOut.rowIndex = -1;
|
stateOut.rowIndex = -1;
|
||||||
stateOut.rowTopOffset = -1;
|
stateOut.rowTopOffset = -1;
|
||||||
stateOut.rowHeight = -1;
|
stateOut.rowHeight = -1;
|
||||||
|
|
||||||
// Return early if there are no items or we haven't been measured
|
// Return early if there are no items or we haven't been measured
|
||||||
|
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||||
if (items.isEmpty() || mNumAppsPerRow == 0) {
|
if (items.isEmpty() || mNumAppsPerRow == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ public class AlphabeticalAppsList {
|
|||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
private static final boolean DEBUG_PREDICTIONS = false;
|
private static final boolean DEBUG_PREDICTIONS = false;
|
||||||
|
|
||||||
|
private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION = 0;
|
||||||
|
private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS = 1;
|
||||||
|
|
||||||
|
private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Info about a section in the alphabetic list
|
* Info about a section in the alphabetic list
|
||||||
*/
|
*/
|
||||||
@@ -85,8 +90,6 @@ public class AlphabeticalAppsList {
|
|||||||
/** Section & App properties */
|
/** Section & App properties */
|
||||||
// The section for this item
|
// The section for this item
|
||||||
public SectionInfo sectionInfo;
|
public SectionInfo sectionInfo;
|
||||||
// The row that this item shows up on
|
|
||||||
public int rowIndex;
|
|
||||||
|
|
||||||
/** App-only properties */
|
/** App-only properties */
|
||||||
// The section name of this app. Note that there can be multiple items with different
|
// The section name of this app. Note that there can be multiple items with different
|
||||||
@@ -94,6 +97,8 @@ public class AlphabeticalAppsList {
|
|||||||
public String sectionName = null;
|
public String sectionName = null;
|
||||||
// The index of this app in the section
|
// The index of this app in the section
|
||||||
public int sectionAppIndex = -1;
|
public int sectionAppIndex = -1;
|
||||||
|
// The row that this item shows up on
|
||||||
|
public int rowIndex;
|
||||||
// The index of this app in the row
|
// The index of this app in the row
|
||||||
public int rowAppIndex;
|
public int rowAppIndex;
|
||||||
// The associated AppInfo for the app
|
// The associated AppInfo for the app
|
||||||
@@ -188,7 +193,6 @@ public class AlphabeticalAppsList {
|
|||||||
private int mNumAppsPerRow;
|
private int mNumAppsPerRow;
|
||||||
private int mNumPredictedAppsPerRow;
|
private int mNumPredictedAppsPerRow;
|
||||||
private int mNumAppRowsInAdapter;
|
private int mNumAppRowsInAdapter;
|
||||||
private boolean mDisableEmptyText;
|
|
||||||
|
|
||||||
public AlphabeticalAppsList(Context context) {
|
public AlphabeticalAppsList(Context context) {
|
||||||
mLauncher = (Launcher) context;
|
mLauncher = (Launcher) context;
|
||||||
@@ -215,13 +219,6 @@ public class AlphabeticalAppsList {
|
|||||||
mAdapter = adapter;
|
mAdapter = adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the empty text message when there are no search results.
|
|
||||||
*/
|
|
||||||
public void disableEmptyText() {
|
|
||||||
mDisableEmptyText = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all the apps.
|
* Returns all the apps.
|
||||||
*/
|
*/
|
||||||
@@ -523,18 +520,36 @@ public class AlphabeticalAppsList {
|
|||||||
}
|
}
|
||||||
mNumAppRowsInAdapter = rowIndex + 1;
|
mNumAppRowsInAdapter = rowIndex + 1;
|
||||||
|
|
||||||
// Pre-calculate all the fast scroller fractions based on the number of rows
|
// Pre-calculate all the fast scroller fractions
|
||||||
float rowFraction = 1f / mNumAppRowsInAdapter;
|
switch (mFastScrollDistributionMode) {
|
||||||
for (FastScrollSectionInfo info : mFastScrollerSections) {
|
case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION:
|
||||||
AdapterItem item = info.fastScrollToItem;
|
float rowFraction = 1f / mNumAppRowsInAdapter;
|
||||||
if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
|
for (FastScrollSectionInfo info : mFastScrollerSections) {
|
||||||
item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
|
AdapterItem item = info.fastScrollToItem;
|
||||||
info.touchFraction = 0f;
|
if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
|
||||||
continue;
|
item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
|
||||||
}
|
info.touchFraction = 0f;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow);
|
float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow);
|
||||||
info.touchFraction = item.rowIndex * rowFraction + subRowFraction;
|
info.touchFraction = item.rowIndex * rowFraction + subRowFraction;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS:
|
||||||
|
float perSectionTouchFraction = 1f / mFastScrollerSections.size();
|
||||||
|
float cumulativeTouchFraction = 0f;
|
||||||
|
for (FastScrollSectionInfo info : mFastScrollerSections) {
|
||||||
|
AdapterItem item = info.fastScrollToItem;
|
||||||
|
if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
|
||||||
|
item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
|
||||||
|
info.touchFraction = 0f;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
info.touchFraction = cumulativeTouchFraction;
|
||||||
|
cumulativeTouchFraction += perSectionTouchFraction;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
|
|||||||
|
|
||||||
getCurScrollState(mScrollPosState);
|
getCurScrollState(mScrollPosState);
|
||||||
float pos = rowCount * touchFraction;
|
float pos = rowCount * touchFraction;
|
||||||
int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0);
|
int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight);
|
||||||
LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());
|
LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());
|
||||||
layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
|
layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
|
||||||
|
|
||||||
@@ -115,29 +115,29 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
|
|||||||
* Updates the bounds for the scrollbar.
|
* Updates the bounds for the scrollbar.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onUpdateScrollbar() {
|
public void onUpdateScrollbar(int dy) {
|
||||||
int rowCount = mWidgets.getPackageSize();
|
int rowCount = mWidgets.getPackageSize();
|
||||||
|
|
||||||
// Skip early if, there are no items.
|
// Skip early if, there are no items.
|
||||||
if (rowCount == 0) {
|
if (rowCount == 0) {
|
||||||
mScrollbar.setScrollbarThumbOffset(-1, -1);
|
mScrollbar.setThumbOffset(-1, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip early if, there no child laid out in the container.
|
// Skip early if, there no child laid out in the container.
|
||||||
getCurScrollState(mScrollPosState);
|
getCurScrollState(mScrollPosState);
|
||||||
if (mScrollPosState.rowIndex < 0) {
|
if (mScrollPosState.rowIndex < 0) {
|
||||||
mScrollbar.setScrollbarThumbOffset(-1, -1);
|
mScrollbar.setThumbOffset(-1, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0);
|
synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current scroll state.
|
* Returns the current scroll state.
|
||||||
*/
|
*/
|
||||||
private void getCurScrollState(ScrollPositionState stateOut) {
|
protected void getCurScrollState(ScrollPositionState stateOut) {
|
||||||
stateOut.rowIndex = -1;
|
stateOut.rowIndex = -1;
|
||||||
stateOut.rowTopOffset = -1;
|
stateOut.rowTopOffset = -1;
|
||||||
stateOut.rowHeight = -1;
|
stateOut.rowHeight = -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user