studio recyclerview hacer como actualizar android swiperefreshlayout android-recyclerview

android - hacer - RecyclerView y SwipeRefreshLayout



swiperefreshlayout android (10)

desafortunadamente, este es un error conocido en LinearLayoutManager. No computaScrollOffset correctamente cuando el primer elemento está visible. será arreglado cuando sea lanzado.

Estoy usando el nuevo RecyclerView-Layout en SwipeRefreshLayout y experimenté un comportamiento extraño. Cuando se desplaza la lista hacia atrás, a veces la vista en la parte superior se recorta.

Si trato de desplazarme a la parte superior ahora, los activadores Pull-To-Refresh se activan.

Si intento y elimino el diseño de actualización deslizante alrededor de la vista recicladora, el problema desapareció. Y es reproducible en cualquier teléfono (no solo dispositivos L-Preview).

<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/contentView" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"> <android.support.v7.widget.RecyclerView android:id="@+id/hot_fragment_recycler" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout>

Ese es mi diseño: las filas están compiladas dinámicamente por RecyclerViewAdapter (2 tipos de vista en esta lista).

public class HotRecyclerAdapter extends TikDaggerRecyclerAdapter<GameRow> { private static final int VIEWTYPE_GAME_TITLE = 0; private static final int VIEWTYPE_GAME_TEAM = 1; @Inject Picasso picasso; public HotRecyclerAdapter(Injector injector) { super(injector); } @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position, int viewType) { switch (viewType) { case VIEWTYPE_GAME_TITLE: { TitleGameRowViewHolder holder = (TitleGameRowViewHolder) viewHolder; holder.bindGameRow(picasso, getItem(position)); break; } case VIEWTYPE_GAME_TEAM: { TeamGameRowViewHolder holder = (TeamGameRowViewHolder) viewHolder; holder.bindGameRow(picasso, getItem(position)); break; } } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { switch (viewType) { case VIEWTYPE_GAME_TITLE: { View view = inflater.inflate(R.layout.game_row_title, viewGroup, false); return new TitleGameRowViewHolder(view); } case VIEWTYPE_GAME_TEAM: { View view = inflater.inflate(R.layout.game_row_team, viewGroup, false); return new TeamGameRowViewHolder(view); } } return null; } @Override public int getItemViewType(int position) { GameRow row = getItem(position); if (row.isTeamGameRow()) { return VIEWTYPE_GAME_TEAM; } return VIEWTYPE_GAME_TITLE; }

Aquí está el adaptador.

hotAdapter = new HotRecyclerAdapter(this); recyclerView.setHasFixedSize(false); recyclerView.setAdapter(hotAdapter); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); contentView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { loadData(); } }); TypedArray colorSheme = getResources().obtainTypedArray(R.array.main_refresh_sheme); contentView.setColorSchemeResources(colorSheme.getResourceId(0, -1), colorSheme.getResourceId(1, -1), colorSheme.getResourceId(2, -1), colorSheme.getResourceId(3, -1));

Y el código del Fragment contiene el Recycler y el SwipeRefreshLayout .

Si alguien más ha experimentado este comportamiento y lo resolvió o al menos encontró la razón para ello?


Antes de usar esta solución: RecyclerView aún no está completo, ¡INTENTE NO UTILIZARLO EN LA PRODUCCIÓN A MENOS QUE USTED SEA COMO YO!

En noviembre de 2014, todavía hay errores en RecyclerView que podrían hacer que canScrollVertically devuelva falso prematuramente. Esta solución resolverá todos los problemas de desplazamiento.

La gota en la solución:

public class FixedRecyclerView extends RecyclerView { public FixedRecyclerView(Context context) { super(context); } public FixedRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canScrollVertically(int direction) { // check if scrolling up if (direction < 1) { boolean original = super.canScrollVertically(direction); return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original; } return super.canScrollVertically(direction); } }

¡Ni siquiera necesita reemplazar RecyclerView en su código con FixedRecyclerView , reemplazar la etiqueta XML sería suficiente! (El asegura que cuando se completa RecyclerView, la transición sería rápida y simple)

Explicación:

Básicamente, canScrollVertically(boolean) devuelve falso demasiado pronto, por lo que verificamos si RecyclerView se desplaza hasta la parte superior de la primera vista (donde la parte superior del primer hijo sería 0) y luego regresa.

EDITAR: Y si no desea extender RecyclerView por alguna razón, puede extender SwipeRefreshLayout y anular el método canChildScrollUp() y poner allí la lógica de verificación.

EDIT2: RecyclerView ha sido lanzado y hasta ahora no hay necesidad de usar esta solución.


He experimentado el mismo problema. Lo resolví agregando un detector de desplazamiento que esperará hasta que se dibuje el primer elemento visible en el RecyclerView . También puede enlazar otros oyentes de desplazamiento, a lo largo de este. El primer valor visible esperado se agrega para usarlo como posición de umbral cuando SwipeRefreshLayout debe habilitar en los casos en que se usan titulares de vista de encabezado.

public class SwipeRefreshLayoutToggleScrollListener extends RecyclerView.OnScrollListener { private List<RecyclerView.OnScrollListener> mScrollListeners = new ArrayList<RecyclerView.OnScrollListener>(); private int mExpectedVisiblePosition = 0; public SwipeRefreshLayoutToggleScrollListener(SwipeRefreshLayout mSwipeLayout) { this.mSwipeLayout = mSwipeLayout; } private SwipeRefreshLayout mSwipeLayout; public void addScrollListener(RecyclerView.OnScrollListener listener){ mScrollListeners.add(listener); } public boolean removeScrollListener(RecyclerView.OnScrollListener listener){ return mScrollListeners.remove(listener); } public void setExpectedFirstVisiblePosition(int position){ mExpectedVisiblePosition = position; } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); notifyScrollStateChanged(recyclerView,newState); LinearLayoutManager llm = (LinearLayoutManager) recyclerView.getLayoutManager(); int firstVisible = llm.findFirstCompletelyVisibleItemPosition(); if(firstVisible != RecyclerView.NO_POSITION) mSwipeLayout.setEnabled(firstVisible == mExpectedVisiblePosition); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); notifyOnScrolled(recyclerView, dx, dy); } private void notifyOnScrolled(RecyclerView recyclerView, int dx, int dy){ for(RecyclerView.OnScrollListener listener : mScrollListeners){ listener.onScrolled(recyclerView, dx, dy); } } private void notifyScrollStateChanged(RecyclerView recyclerView, int newState){ for(RecyclerView.OnScrollListener listener : mScrollListeners){ listener.onScrollStateChanged(recyclerView, newState); } } }

Uso:

SwipeRefreshLayoutToggleScrollListener listener = new SwipeRefreshLayoutToggleScrollListener(mSwiperRefreshLayout); listener.addScrollListener(this); //optional listener.addScrollListener(mScrollListener1); //optional mRecyclerView.setOnScrollLIstener(listener);


Me encontré con el mismo problema recientemente. Probé el enfoque sugerido por @Krunal_Patel, pero funcionó la mayoría de las veces en mi Nexus 4 y no funcionó en absoluto en samsung galaxy s2. Al depurar, recyclerView.getChildAt (0) .getTop () no siempre es correcto para RecyclerView. Entonces, después de pasar por varios métodos, calculé que podemos hacer uso del método findFirstCompletelyComisiblyItemPosition () del LayoutManager para predecir si el primer elemento de RecyclerView es visible o no, para habilitar SwipeRefreshLayout. Encontrar el siguiente código. Espero que ayude a alguien que intenta solucionar el mismo problema. Aclamaciones.

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } public void onScrolled(RecyclerView recyclerView, int dx, int dy) { swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0); } });


Me encuentro con el mismo problema. Mi solución está anulando el método OnScrollListener de OnScrollListener .

La solución está aquí:

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); int offset = dy - ydy;//to adjust scrolling sensitivity of calling OnRefreshListener ydy = dy;//updated old value boolean shouldRefresh = (linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) && (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) && offset > 30; if (shouldRefresh) { swipeRefreshLayout.setRefreshing(true); } else { swipeRefreshLayout.setRefreshing(false); } } });


Esta es una forma de manejar esto, que también maneja ListView / GridView.

public class SwipeRefreshLayout extends android.support.v4.widget.SwipeRefreshLayout { public SwipeRefreshLayout(Context context) { super(context); } public SwipeRefreshLayout(Context context,AttributeSet attrs) { super(context,attrs); } @Override public boolean canChildScrollUp() { View target=getChildAt(0); if(target instanceof AbsListView) { final AbsListView absListView=(AbsListView)target; return absListView.getChildCount()>0 &&(absListView.getFirstVisiblePosition()>0||absListView.getChildAt(0) .getTop()<absListView.getPaddingTop()); } else return ViewCompat.canScrollVertically(target,-1); } }


escriba el siguiente código en addOnScrollListener of the RecyclerView

Me gusta esto:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){ @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop(); swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0); } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } });


La solución de krunal es buena, pero funciona como una revisión y no cubre algunos casos específicos, por ejemplo este:

Digamos que RecyclerView contiene un EditText en el medio de la pantalla. Comenzamos la aplicación (topRowVerticalPosition = 0), toques en EditText. Como resultado, aparece el teclado del software, se reduce el tamaño de RecyclerView, se desplaza automáticamente por el sistema para mantener el EditText visible y topRowVerticalPosition no debe ser 0, pero no se llama aScrolled y no se vuelve a calcular la posición de TopRowVertical.

Por lo tanto, sugiero esta solución:

public class SupportSwipeRefreshLayout extends SwipeRefreshLayout { private RecyclerView mInternalRecyclerView = null; public SupportSwipeRefreshLayout(Context context) { super(context); } public SupportSwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); } public void setInternalRecyclerView(RecyclerView internalRecyclerView) { mInternalRecyclerView = internalRecyclerView; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (mInternalRecyclerView.canScrollVertically(-1)) { return false; } return super.onInterceptTouchEvent(ev); } }

Después de especificar RecyclerView interno para SupportSwipeRefreshLayout, enviará automáticamente el evento táctil a SupportSwipeRefreshLayout si RecyclerView no se puede desplazar hacia arriba y RecyclerView de lo contrario.


Así es como he resuelto este problema en mi caso. Podría ser útil para otra persona que termine aquí buscando soluciones similares a esta.

recyclerView.addOnScrollListener(new OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // TODO Auto-generated method stub super.onScrolled(recyclerView, dx, dy); } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { // TODO Auto-generated method stub //super.onScrollStateChanged(recyclerView, newState); int firstPos=linearLayoutManager.findFirstCompletelyVisibleItemPosition(); if (firstPos>0) { swipeLayout.setEnabled(false); } else { swipeLayout.setEnabled(true); } } });

Espero que esto definitivamente ayude a alguien que está buscando una solución similar.


Código fuente https://drive.google.com/open?id=0BzBKpZ4nzNzURkRGNVFtZXV1RWM

recyclerView.setOnScrollListener (new RecyclerView.OnScrollListener () {

public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } public void onScrolled(RecyclerView recyclerView, int dx, int dy) { swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0); } });