aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2015-11-03 17:38:47 -0800
committerScott Jackson <daneren2005@gmail.com>2015-11-03 17:38:47 -0800
commit3ab717d12df8a045ec79f51d982017be3b45c0b3 (patch)
treeeb8651bda04985fa2da879b2a72baf72b1c7b013
parent35aad94204cbe560fac2a8468f5ab8b3ee92b557 (diff)
downloaddsub-3ab717d12df8a045ec79f51d982017be3b45c0b3.tar.gz
dsub-3ab717d12df8a045ec79f51d982017be3b45c0b3.tar.bz2
dsub-3ab717d12df8a045ec79f51d982017be3b45c0b3.zip
Make dragging fast scroller smooth instead of jumping between the tops of items
-rw-r--r--app/src/main/java/github/daneren2005/dsub/view/FastScroller.java126
-rw-r--r--app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java3
2 files changed, 77 insertions, 52 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java b/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java
index ee5900bd..7cb29835 100644
--- a/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java
+++ b/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java
@@ -21,11 +21,13 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
+import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.AdapterDataObserver;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -108,11 +110,7 @@ public class FastScroller extends LinearLayout {
}
handle.setSelected(true);
case MotionEvent.ACTION_MOVE:
- final float y = event.getY();
- if(handle.getY() <= 0 || (handle.getY() + handle.getHeight()) >= height - TRACK_SNAP_RANGE) {
- setBubbleAndHandlePosition(y);
- }
- setRecyclerViewPosition(y);
+ setRecyclerViewPosition(event.getY());
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
@@ -141,18 +139,38 @@ public class FastScroller extends LinearLayout {
}
private void setRecyclerViewPosition(float y) {
- if(recyclerView != null)
- {
+ if(recyclerView != null) {
+ if(recyclerView.getChildCount() == 0) {
+ return;
+ }
+
int itemCount = recyclerView.getAdapter().getItemCount();
- float proportion;
- if(handle.getY() == 0)
- proportion = 0f;
- else if(handle.getY()+handle.getHeight()>=height-TRACK_SNAP_RANGE)
- proportion = 1f;
- else
- proportion = y/(float)height;
- int targetPos = getValueInRange(0,itemCount-1,(int)(proportion*(float)itemCount));
- ((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(targetPos,0);
+ float proportion = getValueInRange(0, 1f, y / (float) height);
+
+ float targetPosFloat = getValueInRange(0, itemCount - 1, proportion * (float)itemCount);
+ int targetPos = (int) targetPosFloat;
+
+ // Immediately make sure that the target is visible
+ LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
+ // layoutManager.scrollToPositionWithOffset(targetPos, 0);
+ View firstVisibleView = recyclerView.getChildAt(0);
+
+ // Calculate how far through this position we are
+ int columns = Math.round(recyclerView.getWidth() / firstVisibleView.getWidth());
+ int firstVisiblePosition = recyclerView.getChildPosition(firstVisibleView);
+ int remainder = (targetPos - firstVisiblePosition) % columns;
+ float offsetPercentage = (targetPosFloat - targetPos + remainder) / columns;
+ if(offsetPercentage < 0) {
+ offsetPercentage = 1 + offsetPercentage;
+ }
+ int firstVisibleHeight = firstVisibleView.getHeight();
+ if(columns > 1) {
+ firstVisibleHeight += (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, GridSpacingDecoration.SPACING, firstVisibleView.getResources().getDisplayMetrics());
+ }
+ int offset = (int) (offsetPercentage * firstVisibleHeight);
+
+ layoutManager.scrollToPositionWithOffset(targetPos, -offset);
+ onUpdateScroll(1, 1);
try {
String bubbleText = null;
@@ -166,6 +184,7 @@ public class FastScroller extends LinearLayout {
bubble.setVisibility(View.INVISIBLE);
} else {
bubble.setText(bubbleText);
+ bubble.setVisibility(View.VISIBLE);
visibleBubble = true;
}
} catch(Exception e) {
@@ -174,8 +193,8 @@ public class FastScroller extends LinearLayout {
}
}
- private int getValueInRange(int min,int max,int value) {
- int minimum = Math.max(min,value);
+ private float getValueInRange(float min, float max, float value) {
+ float minimum = Math.max(min, value);
return Math.min(minimum,max);
}
@@ -183,7 +202,7 @@ public class FastScroller extends LinearLayout {
int bubbleHeight = bubble.getHeight();
int handleHeight = handle.getHeight();
handle.setY(getValueInRange(0,height-handleHeight,(int)(y-handleHeight/2)));
- bubble.setY(getValueInRange(0,height-bubbleHeight-handleHeight/2,(int)(y-bubbleHeight)));
+ bubble.setY(getValueInRange(0, height - bubbleHeight - handleHeight / 2, (int) (y - bubbleHeight)));
}
private void showBubble() {
@@ -264,44 +283,49 @@ public class FastScroller extends LinearLayout {
private class ScrollListener extends OnScrollListener {
@Override
public void onScrolled(RecyclerView rv,int dx,int dy) {
- if(recyclerView.getWidth() == 0) {
- return;
- }
- registerAdapter();
+ onUpdateScroll(dx, dy);
+ }
+ }
- View firstVisibleView = recyclerView.getChildAt(0);
- if(firstVisibleView == null) {
- return;
- }
- int firstVisiblePosition = recyclerView.getChildPosition(firstVisibleView);
- if(visibleRange == -1) {
- visibleRange = recyclerView.getChildCount();
- }
- int itemCount = recyclerView.getAdapter().getItemCount();
- int columns = Math.round(recyclerView.getWidth() / firstVisibleView.getWidth());
+ private void onUpdateScroll(int dx, int dy) {
+ if(recyclerView.getWidth() == 0) {
+ return;
+ }
+ registerAdapter();
+
+ View firstVisibleView = recyclerView.getChildAt(0);
+ if(firstVisibleView == null) {
+ return;
+ }
+ int firstVisiblePosition = recyclerView.getChildPosition(firstVisibleView);
+
+ int itemCount = recyclerView.getAdapter().getItemCount();
+ int columns = Math.round(recyclerView.getWidth() / firstVisibleView.getWidth());
+ if(visibleRange == -1) {
+ visibleRange = recyclerView.getChildCount();
+ }
- // Add the percentage of the item the user has scrolled past already
- float pastFirst = -firstVisibleView.getY() / firstVisibleView.getHeight() * columns;
- float position = firstVisiblePosition + pastFirst;
+ // Add the percentage of the item the user has scrolled past already
+ float pastFirst = -firstVisibleView.getY() / firstVisibleView.getHeight() * columns;
+ float position = firstVisiblePosition + pastFirst;
- // Scale this so as we move down the visible range gets added to position from 0 -> visible range
- float scaledVisibleRange = position / (float) (itemCount - visibleRange) * visibleRange;
- position += scaledVisibleRange;
+ // Scale this so as we move down the visible range gets added to position from 0 -> visible range
+ float scaledVisibleRange = position / (float) (itemCount - visibleRange) * visibleRange;
+ position += scaledVisibleRange;
- float proportion = position / itemCount;
- setBubbleAndHandlePosition(height * proportion);
+ float proportion = position / itemCount;
+ setBubbleAndHandlePosition(height * proportion);
- if((visibleRange * 2) < itemCount) {
- if (!hasScrolled && (dx > 0 || dy > 0)) {
- setVisibility(View.VISIBLE);
- hasScrolled = true;
- recyclerView.setVerticalScrollBarEnabled(false);
- }
- } else if(hasScrolled) {
- setVisibility(View.GONE);
- hasScrolled = false;
- recyclerView.setVerticalScrollBarEnabled(true);
+ if((visibleRange * 2) < itemCount) {
+ if (!hasScrolled && (dx > 0 || dy > 0)) {
+ setVisibility(View.VISIBLE);
+ hasScrolled = true;
+ recyclerView.setVerticalScrollBarEnabled(false);
}
+ } else if(hasScrolled) {
+ setVisibility(View.GONE);
+ hasScrolled = false;
+ recyclerView.setVerticalScrollBarEnabled(true);
}
}
diff --git a/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java b/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java
index 2d7f4c44..b59e7157 100644
--- a/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java
+++ b/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java
@@ -22,12 +22,13 @@ import android.util.TypedValue;
import android.view.View;
public class GridSpacingDecoration extends RecyclerView.ItemDecoration {
+ public static final int SPACING = 10;
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
- int spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, view.getResources().getDisplayMetrics());
+ int spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SPACING, view.getResources().getDisplayMetrics());
int halfSpacing = spacing / 2;
int childCount = parent.getChildCount();