NekoX/TMessagesProj/src/main/java/androidx/recyclerview/widget/LinearSmoothScrollerMiddle....

153 lines
5.3 KiB
Java
Raw Normal View History

2017-07-08 18:32:04 +02:00
/*
2019-01-23 18:03:33 +01:00
* This is the source code of Telegram for Android v. 5.x.x.
2017-07-08 18:32:04 +02:00
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov, 2013-2018.
2017-07-08 18:32:04 +02:00
*/
2019-05-14 14:08:05 +02:00
package androidx.recyclerview.widget;
2017-07-08 18:32:04 +02:00
import android.content.Context;
import android.graphics.PointF;
2019-05-14 14:08:05 +02:00
import androidx.annotation.Nullable;
2017-07-08 18:32:04 +02:00
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
public class LinearSmoothScrollerMiddle extends RecyclerView.SmoothScroller {
private static final float MILLISECONDS_PER_INCH = 25f;
private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000;
private static final float TARGET_SEEK_EXTRA_SCROLL_RATIO = 1.2f;
protected final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
protected final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator(1.5f);
protected PointF mTargetVector;
private final float MILLISECONDS_PER_PX;
protected int mInterimTargetDx = 0, mInterimTargetDy = 0;
public LinearSmoothScrollerMiddle(Context context) {
MILLISECONDS_PER_PX = MILLISECONDS_PER_INCH / context.getResources().getDisplayMetrics().densityDpi;
}
@Override
protected void onStart() {
}
@Override
protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
final int dy = calculateDyToMakeVisible(targetView);
final int time = calculateTimeForDeceleration(dy);
if (time > 0) {
action.update(0, -dy, Math.max(400, time), mDecelerateInterpolator);
}
}
@Override
protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state, Action action) {
if (getChildCount() == 0) {
stop();
return;
}
mInterimTargetDx = clampApplyScroll(mInterimTargetDx, dx);
mInterimTargetDy = clampApplyScroll(mInterimTargetDy, dy);
if (mInterimTargetDx == 0 && mInterimTargetDy == 0) {
updateActionForInterimTarget(action);
}
}
@Override
protected void onStop() {
mInterimTargetDx = mInterimTargetDy = 0;
mTargetVector = null;
}
protected int calculateTimeForDeceleration(int dx) {
2018-07-30 04:07:02 +02:00
return (int) Math.ceil(calculateTimeForScrolling(dx) / .3356);
2017-07-08 18:32:04 +02:00
}
protected int calculateTimeForScrolling(int dx) {
return (int) Math.ceil(Math.abs(dx) * MILLISECONDS_PER_PX);
}
protected void updateActionForInterimTarget(Action action) {
// find an interim target position
PointF scrollVector = computeScrollVectorForPosition(getTargetPosition());
if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) {
final int target = getTargetPosition();
action.jumpTo(target);
stop();
return;
}
normalize(scrollVector);
mTargetVector = scrollVector;
mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x);
mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y);
final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX);
// To avoid UI hiccups, trigger a smooth scroll to a distance little further than the
// interim target. Since we track the distance travelled in onSeekTargetStep callback, it
// won't actually scroll more than what we need.
action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO)
, (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO)
, (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator);
}
private int clampApplyScroll(int tmpDt, int dt) {
final int before = tmpDt;
tmpDt -= dt;
if (before * tmpDt <= 0) {
return 0;
}
return tmpDt;
}
public int calculateDyToMakeVisible(View view) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (layoutManager == null || !layoutManager.canScrollVertically()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
int top = layoutManager.getDecoratedTop(view) - params.topMargin;
int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin;
int start = layoutManager.getPaddingTop();
int end = layoutManager.getHeight() - layoutManager.getPaddingBottom();
int boxSize = end - start;
int viewSize = bottom - top;
2019-03-03 21:40:48 +01:00
if (viewSize > boxSize) {
start = 0;
} else {
start = (boxSize - viewSize) / 2;
}
2017-07-08 18:32:04 +02:00
end = start + viewSize;
final int dtStart = start - top;
if (dtStart > 0) {
return dtStart;
}
final int dtEnd = end - bottom;
if (dtEnd < 0) {
return dtEnd;
}
return 0;
}
@Nullable
public PointF computeScrollVectorForPosition(int targetPosition) {
RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof ScrollVectorProvider) {
return ((ScrollVectorProvider) layoutManager).computeScrollVectorForPosition(targetPosition);
}
return null;
}
}