holder - Android: ¿Cómo obtener el desplazamiento X actual de RecyclerView?
getadapterposition (6)
Estoy usando una
Scrollview
de
Scrollview
para un "carrusel
Scrollview
de tiempo" infinito y descubrí que no es el mejor enfoque (
última pregunta
)
Ahora, encontré la Vista del reciclador, pero no puedo obtener el desplazamiento del desplazamiento actual en la dirección X de la vista del reciclador . (Digamos que cada elemento tiene un ancho de 100 px y el segundo elemento solo es visible al 50%, por lo que el desplazamiento del desplazamiento es de 150 px)
- Todos los artículos tienen el mismo ancho, pero hay algún espacio antes del primero, después del último artículo
-
recyclerView.getScrollX()
devuelve0
(los documentos dicen: valor de desplazamiento inicial) -
LayoutManager
tienefindFirstVisibleItemPosition
, pero no puedo calcular el desplazamiento de X con eso
ACTUALIZAR
¡Acabo de encontrar una manera de seguir rastreando la posición X, mientras actualizo el valor con la
onScrolled
llamada
onScrolled
, pero preferiría obtener el valor real en lugar de rastrearlo todo el tiempo!
private int overallXScroll = 0;
//...
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
overallXScroll = overallXScroll + dx;
Log.i("check","overallXScroll->" + overallXScroll);
}
});
¡Gracias a @ umar-qureshi por el liderazgo correcto!
Parece que puede determinar el porcentaje de desplazamiento con
Offset
,
Extent
y
Range
manera que
percentage = 100 * offset / (range - extent)
Por ejemplo (para poner en un
OnScrollListener
):
int offset = recyclerView.computeVerticalScrollOffset();
int extent = recyclerView.computeVerticalScrollExtent();
int range = recyclerView.computeVerticalScrollRange();
int percentage = (int)(100.0 * offset / (float)(range - extent));
Log.i("RecyclerView, "scroll percentage: "+ percentage + "%");
RecyclerView ya tiene un método para obtener desplazamiento de desplazamiento horizontal y vertical
mRecyclerView.computeHorizontalScrollOffset()
mRecyclerView.computeVerticalScrollOffset()
Esto funcionará para RecyclerViews que contienen celdas de la misma altura (para desplazamiento de desplazamiento vertical) y el mismo ancho (para desplazamiento de desplazamiento horizontal)
Si necesita conocer la página actual y su desplazamiento en comparación con el ancho de RecyclerView, puede intentar algo como esto:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final int scrollOffset = recyclerView.computeHorizontalScrollOffset();
final int width = recyclerView.getWidth();
final int currentPage = scrollOffset / width;
final float pageOffset = (float) (scrollOffset % width) / width;
// the following lines just the example of how you can use it
if (currentPage == 0) {
leftIndicator.setAlpha(pageOffset);
}
if (adapter.getItemCount() <= 1) {
rightIndicator.setAlpha(pageOffset);
} else if (currentPage == adapter.getItemCount() - 2) {
rightIndicator.setAlpha(1f - pageOffset);
}
}
});
Si
currentPage
tiene el índice 0,
leftIndicator
(flecha) será transparente, y también lo será y
rightIndicator
si solo hay una
page
(en el ejemplo, el adaptador siempre tiene al menos un elemento para mostrar, por lo que no se verifica el valor vacío).
De esta manera, básicamente tendrá casi la misma funcionalidad que si hubiera estado utilizando la página de devolución de llamada
pageScrolled
desde
ViewPager.OnPageChangeListener
.
anulando RecyclerView
onScrolled(int dx,int dy)
, puede obtener el desplazamiento del desplazamiento.
pero cuando agrega o elimina el elemento, el valor puede ser incorrecto.
public class TempRecyclerView extends RecyclerView {
private int offsetX = 0;
private int offsetY = 0;
public TempRecyclerView(Context context) {
super(context);
}
public TempRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TempRecyclerView(Context context, @Nullable AttributeSet attrs,int defStyle){
super(context, attrs, defStyle);
}
/**
* Called when the scroll position of this RecyclerView changes. Subclasses
should usethis method to respond to scrolling within the adapter''s data
set instead of an explicit listener.
* <p>This method will always be invoked before listeners. If a subclass
needs to perform any additional upkeep or bookkeeping after scrolling but
before listeners run, this is a good place to do so.</p>
*/
@Override
public void onScrolled(int dx, int dy) {
// super.onScrolled(dx, dy);
offsetX+=dx;
offsetY+=dy;
}
}
Solución 1:
setOnScrollListener
Guarde su posición X como variable de clase y actualice cada cambio dentro de
onScrollListener
.
Asegúrese de no restablecer
overallXScroll
(por
onScreenRotationChange
)
private int overallXScroll = 0;
//...
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
overallXScroll = overallXScroll + dx;
Log.i("check","overall X = " + overallXScroll);
}
});
Solución 2: Calcular la posición actual.
En mi caso, tengo una Lista horizontal que está llena de valores de tiempo (0:00, 0:30, 1:00, 1:30 ... 23:00, 23:30).
Estoy calculando el tiempo a partir del elemento de tiempo, que se encuentra en el medio de la pantalla (punto de cálculo).
Es por eso que necesito la posición exacta de X-Scroll de mi
RecycleView
- Cada elemento de tiempo tiene el mismo ancho de 60dp (para su información: 60dp = 30min, 2dp = 1min)
-
El primer elemento (elemento de encabezado) tiene un relleno adicional, para establecer 0 minutos al centro
private int mScreenWidth = 0; private int mHeaderItemWidth = 0; private int mCellWidth = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //init recycle views //... LinearLayoutManager mLLM = (LinearLayoutManager) getLayoutManager(); DisplayMetrics displaymetrics = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); this.mScreenWidth = displaymetrics.widthPixels; //calculate value on current device mCellWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources() .getDisplayMetrics()); //get offset of list to the right (gap to the left of the screen from the left side of first item) final int mOffset = (this.mScreenWidth / 2) - (mCellWidth / 2); //HeaderItem width (blue rectangle in graphic) mHeaderItemWidth = mOffset + mCellWidth; mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //get first visible item View firstVisibleItem = mLLM.findViewByPosition(mLLM.findFirstVisibleItemPosition()); int leftScrollXCalculated = 0; if (firstItemPosition == 0){ //if first item, get width of headerview (getLeft() < 0, that''s why I Use Math.abs()) leftScrollXCalculated = Math.abs(firstVisibleItem.getLeft()); } else{ //X-Position = Gap to the right + Number of cells * width - cell offset of current first visible item //(mHeaderItemWidth includes already width of one cell, that''s why I have to subtract it again) leftScrollXCalculated = (mHeaderItemWidth - mCellWidth) + firstItemPosition * mCellWidth + firstVisibleItem.getLeft(); } Log.i("asdf","calculated X to left = " + leftScrollXCalculated); } });
}
public class CustomRecyclerView extends RecyclerView {
public CustomRecyclerView(Context context) {
super(context);
}
public CustomRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public int getHorizontalOffset() {
return super.computeHorizontalScrollOffset();
}
}
De donde necesita obtener el desplazamiento:
recyclerView.getHorizontalOffset()