Я хочу более полно рассмотреть вопрос о продолжительности прокрутки , которая, если вы выберете какой-либо более ранний ответ, на самом деле будет сильно (и неприемлемо) варьироваться в зависимости от количества прокрутки, необходимого для достижения целевой позиции из текущей позиции.
Чтобы получить единообразную продолжительность прокрутки, скорость (пикселей в миллисекунду) должна учитывать размер каждого отдельного элемента, а когда элементы нестандартного размера, добавляется совершенно новый уровень сложности.
Возможно, поэтому разработчики RecyclerView развернули слишком жесткую корзину для этого жизненно важного аспекта плавной прокрутки.
Предполагая, что вам нужна полуравномерная продолжительность прокрутки и что ваш список содержит полуоднородные элементы, вам понадобится что-то вроде этого.
/** Smoothly scroll to specified position allowing for interval specification. <br>
* Note crude deceleration towards end of scroll
* @param rv Your RecyclerView
* @param toPos Position to scroll to
* @param duration Approximate desired duration of scroll (ms)
* @throws IllegalArgumentException */
private static void smoothScroll(RecyclerView rv, int toPos, int duration) throws IllegalArgumentException {
int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000; // See androidx.recyclerview.widget.LinearSmoothScroller
int itemHeight = rv.getChildAt(0).getHeight(); // Height of first visible view! NB: ViewGroup method!
itemHeight = itemHeight + 33; // Example pixel Adjustment for decoration?
int fvPos = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
int i = Math.abs((fvPos - toPos) * itemHeight);
if (i == 0) { i = (int) Math.abs(rv.getChildAt(0).getY()); }
final int totalPix = i; // Best guess: Total number of pixels to scroll
RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(rv.getContext()) {
@Override protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_START;
}
@Override protected int calculateTimeForScrolling(int dx) {
int ms = (int) ( duration * dx / (float)totalPix );
// Now double the interval for the last fling.
if (dx < TARGET_SEEK_SCROLL_DISTANCE_PX ) { ms = ms*2; } // Crude deceleration!
//lg(format("For dx=%d we allot %dms", dx, ms));
return ms;
}
};
//lg(format("Total pixels from = %d to %d = %d [ itemHeight=%dpix ]", fvPos, toPos, totalPix, itemHeight));
smoothScroller.setTargetPosition(toPos);
rv.getLayoutManager().startSmoothScroll(smoothScroller);
}
PS: Проклинаю тот день, когда я начал без разбора преобразовывать ListView в RecyclerView .
protected int getHorizontalSnapPreference() { return LinearSmoothScroller.SNAP_TO_START; }
. Кроме того, мне пришлось реализовать абстрактный методpublic PointF computeScrollVectorForPosition(int targetPosition) { return layoutManager.computeScrollVectorForPosition(targetPosition); }
.