Voglio affrontare in modo più completo il problema della durata dello scorrimento , che, se dovessi scegliere una risposta precedente, in effetti varierà notevolmente (e in modo inaccettabile) in base alla quantità di scorrimento necessaria per raggiungere la posizione di destinazione dalla posizione corrente.
Per ottenere una durata di scorrimento uniforme, la velocità (pixel per millisecondo) deve tenere conto della dimensione di ogni singolo elemento - e quando gli elementi sono di dimensioni non standard, viene aggiunto un nuovo livello di complessità.
Questo potrebbe essere il motivo per cui gli sviluppatori di RecyclerView hanno implementato il cestino troppo rigido per questo aspetto vitale dello scorrimento fluido.
Supponendo che tu voglia una durata di scorrimento semi-uniforme e che il tuo elenco contenga elementi semi-uniformi , avrai bisogno di qualcosa di simile.
/** 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: maledico il giorno in cui ho iniziato a convertire indiscriminatamente ListView in RecyclerView .
protected int getHorizontalSnapPreference() { return LinearSmoothScroller.SNAP_TO_START; }
. Inoltre ho dovuto implementare il metodo astrattopublic PointF computeScrollVectorForPosition(int targetPosition) { return layoutManager.computeScrollVectorForPosition(targetPosition); }
.