android - setnestedscrollingenabled - RecyclerView scrollToPosition no activa scrollListener
setitemviewcachesize (8)
Es un poco rudimentario, pero puedes probar esta Subclase de RecyclerView:
public class PatchedRecyclerView extends RecyclerView {
private OnScrollListener listener;
public PatchedRecyclerView(Context context) {
super(context);
}
public PatchedRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PatchedRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setOnScrollListener(OnScrollListener listener) {
super.setOnScrollListener(listener);
this.listener = listener;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int preFirstChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(0)).getPosition() : -1;
int preLastChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(getChildCount() - 1)).getPosition() : -1;
super.onLayout(changed, l, t, r, b);
int postFirstChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(0)).getPosition() : -1;
int postLastChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(getChildCount() - 1)).getPosition() : -1;
// TODO: Insert proper DX and DY values
if (preFirstChildPosition != postFirstChildPosition || preLastChildPosition != postLastChildPosition)
listener.onScrolled(this, 0, 0);
}
}
Estoy usando RecyclerView, con ScrollListener:
mRecyclerView.setOnScrollListener(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);
// Do my logic
}
});
Cuando me desplazo con el dedo, el oyente de desplazamiento se activó bien.
Pero cuando me desplazo progremáticamente, así:
mRecyclerView.scrollToPosition(LAST_POSITION);
El oyente de desplazamiento no se activa.
Este es un problema conocido. Esto se debe al hecho de que RecyclerView no sabe cómo gestionará LayoutManager el desplazamiento o si lo hará.
En la próxima versión, recibirá una llamada a onScrolled
si la primera y la última posición secundaria cambian después de un diseño (que generalmente es el resultado de llamar al desplazamiento a la posición).
Desafortunadamente, dx y dy serán 0 porque RecyclerView no sabe realmente cuánto se desplazó el administrador de diseño para manejar la solicitud de scrollTo
. Alternativamente, también puede utilizar la devolución de llamada de desplazamiento del ViewTreeObserver.
He enfrentado el mismo problema y he encontrado una solución alternativa, que consiste en utilizar smoothScrollToPosition en el administrador de diseño. Este método activa el oyente de desplazamiento. Así que básicamente esto es lo que suelo tener:
recyclerView.scrollToPosition(recyclerAdapter.getItemCount() - 1);
Y ahora he cambiado a esto:
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null, recyclerAdapter.getItemCount() - 1);
y está funcionando bien para mí.
Muito legal seu conselho.
Button maisOpcoes = (Button) findViewById(R.id.maisOpcoes);
maisOpcoes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null , recyclerViewTmd.getItemCount() - 1);
maisOpcoes.setVisibility(View.GONE);
}
});
No pude usar el smoothScrollToPosition (tuvimos algunos problemas con él en el pasado) y, dependiendo de la posición del primer elemento, parecía poco confiable, por lo que terminé usando la respuesta de (ya se publicó), desafortunadamente no fue así. t trabajar siempre (no estoy seguro de por qué).
Así que terminé usando un detector de desplazamiento que había agregado previamente a RecyclerView, pero lamentablemente no puedo encontrar el origen de esta solución.
No creo que debas usar a este oyente si necesitas uno constante, por suerte solo necesito escucharlo en momentos específicos.
Anular el RecyclerView:
public class MyRecyclerView extends RecyclerView {
public interface OnScrollStoppedListener{
void onScrollStopped();
}
private static final int NEW_CHECK_INTERVAL = 100;
private OnScrollStoppedListener mOnScrollStoppedListener;
private Runnable mScrollerTask;
private int mInitialPosition;
public MyRecyclerView(Context context) {
super(context);
init();
}
public MyRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mScrollerTask = new Runnable() {
public void run() {
int newPosition = getScrollY();
if(mInitialPosition - newPosition == 0) {//has stopped
if(mOnScrollStoppedListener !=null) {
mOnScrollStoppedListener.onScrollStopped();
}
} else {
startScrollerTask();
}
}
};
}
public void setOnScrollStoppedListener(MyRecyclerView.OnScrollStoppedListener listener){
mOnScrollStoppedListener = listener;
}
public void startScrollerTask() {
mInitialPosition = getScrollY();
postDelayed(mScrollerTask, NEW_CHECK_INTERVAL);
}
}
Uso:
myRecyclerView.setOnScrollStoppedListener(new MyRecyclerView.OnScrollStoppedListener() {
@Override
public void onScrollStopped() {
// Do your thing
}
});
myRecyclerView.startScrollerTask();
Para activar explícitamente el uso de la vista onScrollListener sobre el reciclador:
recyclerView.smoothScrollBy(x, y);
//x is the horizontal displacement and y is vertical displacement.
Por favor intente con
LinearLayoutManager.scrollToPositionWithOffset(int, int).
LayoutManager.scrollToPosition()
posible que LayoutManager.scrollToPosition()
no funcione bien, pero LinearLayoutManager.scrollToPositionWithOffset()
funcionará. Y similarmente GridLayoutManager también.
O tenemos que escribir nuestra forma personalizada de implementación porque RecyclerView no sabe cómo LayoutManager desplaza la vista.
class CustomLayoutManager extends LinearLayoutManager{
public void smoothScrollToPosition(RecyclerView recyclerView,
RecyclerView.State state, final int position) {
LinearSmoothScroller smoothScroller =
new LinearSmoothScroller(mContext) {
//Override the methods and write your implementation as per your requirement
//one which controls the direction and another one calculate the speed per Pixel
}
}
A veces esto hace el truco
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
yourList.scrollToPosition(position);
}
}, 200);
int mFirst=0, mLast=0;
recyclerview.setOnScrollListener(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);
LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager();
mLast = llm.findLastCompletelyVisibleItemPosition();
mFirst = llm.findFirstCompletelyVisibleItemPosition();
}
});
imgRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager();
llm.scrollToPositionWithOffset(mLast + 1, List.length());
}
});
imgLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager();
llm.scrollToPositionWithOffset(mFirst - 1, List.length());
}
});