Added FastScroll capability to KeyListFragment. Removed unnecessary dependency.
This commit is contained in:
@@ -33,7 +33,6 @@ dependencies {
|
||||
compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0'
|
||||
compile 'com.cocosw:bottomsheet:1.3.0@aar'
|
||||
compile 'com.tonicartos:superslim:0.4.13'
|
||||
compile 'com.simplecityapps:recyclerview-fastscroll:1.0.10'
|
||||
|
||||
// Material Drawer
|
||||
compile 'com.mikepenz:materialdrawer:5.2.2@aar'
|
||||
@@ -110,7 +109,6 @@ dependencyVerification {
|
||||
'org.thoughtcrime.ssl.pinning:AndroidPinning:afa1d74e699257fa75cb109ff29bac50726ef269c6e306bdeffe8223cee06ef4',
|
||||
'com.cocosw:bottomsheet:4af6112a7f4cad4e2b70e5fdf1edc39f51275523a0f53011a012837dc103e597',
|
||||
'com.tonicartos:superslim:ca89b5c674660cc6918a8f8fd385065bffeee27983e0d33c7c2f0ad7b34d2d49',
|
||||
'com.simplecityapps:recyclerview-fastscroll:3b4c7ac18c6cff367723f5954643735b777cd9fe32a1a200273259145b5e17b4',
|
||||
'com.mikepenz:materialdrawer:4169462fdde042e2bb53a7c2b4e2334d569d16b2020781ee05741b50e1a2967d',
|
||||
'com.mikepenz:fastadapter:1bfc00216d71dfdfe0d8e7a9d92bb97bfaa1794543930e34b1f79d5d7adbddf6',
|
||||
'com.mikepenz:materialize:575195b2fa5b2414fb14a59470ee21d8a8cd8355b651e0cf52e477e3ff1cd96c',
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package org.sufficientlysecure.keychain.ui.util.recyclerview.fastscroll;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.StaggeredGridLayoutManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.tonicartos.superslim.LayoutManager;
|
||||
|
||||
public class FastScrollRecyclerView extends RecyclerView implements RecyclerView.OnItemTouchListener {
|
||||
private FastScroller mFastScroller;
|
||||
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
|
||||
public FastScrollRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FastScrollRecyclerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public FastScrollRecyclerView(Context context, AttributeSet attributeSet, int defStyleAttr) {
|
||||
super(context, attributeSet, defStyleAttr);
|
||||
mFastScroller = new FastScroller(this, attributeSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
addOnItemTouchListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
mFastScroller.draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(int x, int y) {
|
||||
super.onScrolled(x, y);
|
||||
mFastScroller.updateThumb(
|
||||
computeVerticalScrollOffset(),
|
||||
computeVerticalScrollExtent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
mFastScroller.updateContainer(top, right, bottom);
|
||||
mFastScroller.updateThumb(
|
||||
computeVerticalScrollOffset(),
|
||||
computeVerticalScrollExtent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(int state) {
|
||||
switch (state) {
|
||||
case SCROLL_STATE_IDLE:
|
||||
mFastScroller.hideBar();
|
||||
break;
|
||||
case SCROLL_STATE_DRAGGING:
|
||||
mFastScroller.showBar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
if(mFastScroller.onInterceptTouchEvent(e)) {
|
||||
onTouchEvent(rv, e);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent event) {
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
|
||||
mFastScroller.handleTouchEvent(event.getAction(), x, y, mLastX, mLastY);
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
|
||||
}
|
||||
|
||||
private int getItemCount() {
|
||||
return getAdapter() != null ?
|
||||
getAdapter().getItemCount() : 0;
|
||||
}
|
||||
|
||||
public void scrollToFraction(float fraction) {
|
||||
int count = getItemCount();
|
||||
if (count > 0) {
|
||||
stopScroll();
|
||||
scrollToPosition((int) ((count - 1) * fraction));
|
||||
}
|
||||
}
|
||||
|
||||
public void scrollByFraction(float fraction) {
|
||||
int count = getItemCount();
|
||||
if (count > 0) {
|
||||
stopScroll();
|
||||
|
||||
|
||||
int pixelsToScroll = (int) (computeVerticalScrollRange() * fraction);
|
||||
System.out.println("ScrollBy Fraction: " + fraction + ", Pixel: " + pixelsToScroll);
|
||||
|
||||
scrollBy(0, pixelsToScroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
package org.sufficientlysecure.keychain.ui.util.recyclerview.fastscroll;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.support.v4.view.animation.FastOutLinearInInterpolator;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
|
||||
|
||||
public class FastScroller {
|
||||
private static final int DEFAULT_AUTO_HIDE_DELAY = 1500;
|
||||
private static final boolean DEFAULT_AUTO_HIDE_ENABLED = true;
|
||||
|
||||
private Paint mTrack;
|
||||
private Paint mThumb;
|
||||
|
||||
private int mPosX;
|
||||
private int mPosY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
private Rect mContainer;
|
||||
private boolean mIsDragging;
|
||||
|
||||
private int mAutoHideDelay;
|
||||
private boolean mAutoHideEnabled;
|
||||
|
||||
private final int mTrackColorNormal;
|
||||
private final int mTrackColorDragging;
|
||||
|
||||
private final int mThumbColorNormal;
|
||||
private final int mThumbColorDragging;
|
||||
|
||||
private ValueAnimator mBarAnimator;
|
||||
private final FastScrollRecyclerView mRecyclerView;
|
||||
|
||||
private final int mTouchSlop;
|
||||
private final int mTouchInset;
|
||||
private final int[] mKeyFrames;
|
||||
|
||||
//private final Runnable mHideRunnable;
|
||||
|
||||
public FastScroller(final FastScrollRecyclerView recyclerView, AttributeSet attributeSet) {
|
||||
Context context = recyclerView.getContext();
|
||||
mRecyclerView = recyclerView;
|
||||
|
||||
mTrack = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mThumb = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
mKeyFrames = new int[2];
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
mTouchInset = FormattingUtils.dpToPx(context, 8);
|
||||
|
||||
TypedArray typedArray = context.getTheme().obtainStyledAttributes(
|
||||
attributeSet, R.styleable.FastScroller, 0, 0);
|
||||
|
||||
try {
|
||||
mWidth = typedArray.getDimensionPixelSize(
|
||||
R.styleable.FastScroller_fastScrollScrollBarWidth, FormattingUtils.dpToPx(context, 6));
|
||||
|
||||
mAutoHideDelay = typedArray.getInteger(
|
||||
R.styleable.FastScroller_fastScrollAutoHideDelay, DEFAULT_AUTO_HIDE_DELAY);
|
||||
mAutoHideEnabled = typedArray.getBoolean(
|
||||
R.styleable.FastScroller_fastScrollAutoHideEnabled, DEFAULT_AUTO_HIDE_ENABLED);
|
||||
|
||||
mTrackColorNormal = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollTrackColorNormal, Color.LTGRAY);
|
||||
mTrackColorDragging = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollTrackColorDragging, Color.GRAY);
|
||||
|
||||
mThumbColorNormal = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollThumbColorNormal, Color.GRAY);
|
||||
mThumbColorDragging = typedArray.getColor(
|
||||
R.styleable.FastScroller_fastScrollThumbColorDragging, Color.BLUE);
|
||||
|
||||
mTrack.setColor(mTrackColorNormal);
|
||||
mThumb.setColor(mThumbColorNormal);
|
||||
} finally {
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public void hideBar() {
|
||||
if(mPosX >= mWidth || !mAutoHideEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mKeyFrames[0] = mPosX;
|
||||
mKeyFrames[1] = mWidth;
|
||||
|
||||
prepareAnimator();
|
||||
mBarAnimator.setIntValues(mKeyFrames);
|
||||
mBarAnimator.setStartDelay(mAutoHideDelay);
|
||||
mBarAnimator.setInterpolator(new FastOutLinearInInterpolator());
|
||||
mBarAnimator.start();
|
||||
}
|
||||
|
||||
public void showBar() {
|
||||
if(mPosX < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
mKeyFrames[0] = mPosX;
|
||||
mKeyFrames[1] = 0;
|
||||
|
||||
prepareAnimator();
|
||||
mBarAnimator.setStartDelay(0);
|
||||
mBarAnimator.setIntValues(mKeyFrames);
|
||||
mBarAnimator.setInterpolator(new FastOutSlowInInterpolator());
|
||||
mBarAnimator.start();
|
||||
}
|
||||
|
||||
public boolean isAnimatingShow() {
|
||||
return mKeyFrames[1] == 0 && mBarAnimator.isStarted();
|
||||
}
|
||||
|
||||
public boolean isAnimatingHide() {
|
||||
return mKeyFrames[1] == mWidth && mBarAnimator.isStarted();
|
||||
}
|
||||
|
||||
public boolean isBarFullyShown() {
|
||||
return mPosX < 1;
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return mContainer != null
|
||||
&& (event.getX() < mContainer.right)
|
||||
&& (event.getX() > mContainer.left - mTouchInset)
|
||||
&& (event.getY() < mContainer.bottom)
|
||||
&& (event.getY() > mContainer.top);
|
||||
}
|
||||
|
||||
private boolean isInThumb(int x, int y) {
|
||||
return x > (mContainer.left + mPosX - mTouchInset)
|
||||
&& x < (mContainer.right + mTouchInset)
|
||||
&& y > (mContainer.top + mPosY - mTouchInset)
|
||||
&& y < (mContainer.top + mPosY + mHeight + mTouchInset);
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
if(mPosX < 0 || mPosX >= mWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mRecyclerView.canScrollVertically(-1)
|
||||
&& ! mRecyclerView.canScrollVertically(1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int topBound = mContainer.top + mPosY;
|
||||
int leftBound = mContainer.left + mPosX;
|
||||
|
||||
canvas.drawRect(leftBound, mContainer.top, mContainer.right, mContainer.bottom, mTrack);
|
||||
canvas.drawRect(leftBound, topBound, mContainer.right, topBound + mHeight, mThumb);
|
||||
}
|
||||
|
||||
public void updateThumb(int offset, int extent) {
|
||||
mPosY = offset;
|
||||
mHeight = extent;
|
||||
}
|
||||
|
||||
public void updateContainer(int top, int right, int bottom) {
|
||||
mPosX = 0;
|
||||
mContainer = new Rect(right - mWidth, top, right, bottom);
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void invalidate() {
|
||||
mRecyclerView.invalidate(mContainer);
|
||||
}
|
||||
|
||||
private void prepareAnimator() {
|
||||
if (mBarAnimator != null) {
|
||||
mBarAnimator.cancel();
|
||||
} else {
|
||||
mBarAnimator = new ValueAnimator();
|
||||
mBarAnimator.setDuration(150);
|
||||
mBarAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mPosX = (Integer) animation.getAnimatedValue();
|
||||
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void handleTouchEvent(int action, int x, int y, int lastX, int lastY) {
|
||||
if(!mRecyclerView.canScrollVertically(-1)
|
||||
&& ! mRecyclerView.canScrollVertically(1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if(isBarFullyShown()) { //
|
||||
prepareAnimator(); // cancel any pending animations
|
||||
|
||||
mTrack.setColor(mTrackColorDragging);
|
||||
mThumb.setColor(mThumbColorDragging);
|
||||
|
||||
if(!isInThumb(x, y)) {
|
||||
// jump to point
|
||||
mPosY = Math.min(
|
||||
Math.max(mContainer.top, y - (mHeight / 2)),
|
||||
mContainer.bottom - mHeight
|
||||
);
|
||||
|
||||
float range = (mContainer.bottom - mContainer.top) - mHeight;
|
||||
mRecyclerView.scrollToFraction(mPosY / range);
|
||||
} else {
|
||||
invalidate();
|
||||
}
|
||||
} else {
|
||||
if(!isAnimatingShow()) {
|
||||
showBar();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if((!mIsDragging
|
||||
&& isInThumb(x, y)
|
||||
&& Math.abs(y - lastY) > mTouchSlop)
|
||||
|| mIsDragging) {
|
||||
|
||||
if(!mIsDragging) {
|
||||
mIsDragging = true;
|
||||
}
|
||||
|
||||
float dist = y - lastY;
|
||||
float range = (mContainer.bottom - mContainer.top) - mHeight;
|
||||
|
||||
if(mRecyclerView.canScrollVertically(dist < 0 ? -1 : 1)) {
|
||||
mRecyclerView.scrollByFraction(dist / range);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if(mIsDragging) {
|
||||
mIsDragging = false;
|
||||
}
|
||||
|
||||
mTrack.setColor(mTrackColorNormal);
|
||||
mThumb.setColor(mThumbColorNormal);
|
||||
|
||||
if(!mBarAnimator.isRunning()
|
||||
&& mRecyclerView.getScrollState()
|
||||
== RecyclerView.SCROLL_STATE_IDLE) {
|
||||
hideBar();
|
||||
invalidate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:fab="http://schemas.android.com/apk/res-auto"
|
||||
<FrameLayout xmlns:fab="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
@@ -35,7 +34,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
<org.sufficientlysecure.keychain.ui.util.recyclerview.fastscroll.FastScrollRecyclerView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -45,8 +44,9 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:paddingBottom="72dp"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="vertical"
|
||||
android:scrollbarStyle="outsideOverlay"/>
|
||||
custom:fastScrollScrollBarWidth="8dp"
|
||||
custom:fastScrollThumbColorNormal="@color/selected_gray"
|
||||
custom:fastScrollThumbColorDragging="@color/accent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/empty"
|
||||
|
||||
@@ -28,4 +28,14 @@
|
||||
<attr name="prefix" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="FastScroller">
|
||||
<attr name="fastScrollScrollBarWidth" format="dimension"/>
|
||||
<attr name="fastScrollAutoHideEnabled" format="boolean" />
|
||||
<attr name="fastScrollAutoHideDelay" format="integer" />
|
||||
<attr name="fastScrollThumbColorNormal" format="color" />
|
||||
<attr name="fastScrollTrackColorNormal" format="color" />
|
||||
<attr name="fastScrollThumbColorDragging" format="color" />
|
||||
<attr name="fastScrollTrackColorDragging" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
Reference in New Issue
Block a user