java - recyclerview - Desplazar hacia arriba no funciona con SwipeRefreshLayout en Listview
swiperefreshlayout recyclerview (6)
Crea un diseño como este.
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/guides_no_results"
android:id="@+id/empty_view"
android:gravity="center"
android:padding="16dp"
android:fontFamily="sans-serif-light"
android:textSize="20sp"
android:visibility="gone"/>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="true"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:id="@+id/guides_list" />
</LinearLayout>
Si usa esto tal como está, cada vez que se desplaza hacia arriba en esa vista, el SwipeRefreshLayout se activa y se actualiza, lo que hace que su aplicación no pueda desplazarse hacia arriba en una lista.
El truco aquí es cablear OnScrollListener desde ListView manualmente. Simplemente verifique si la primera fila que se muestra coincide con la primera posición superior y luego habilite SwipeRefreshLayout. De lo contrario, deshabilítelo.
guidesList.setOnScrollListener(new AbsListView.OnScrollListener()
{
@Override
public void onScrollStateChanged(AbsListView view, int scrollState)
{
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
int topRowVerticalPosition = (guidesList == null || guidesList.getChildCount() == 0) ? 0 : guidesList.getChildAt(0).getTop();
swipeContainer.setEnabled(firstVisibleItem == 0 && topRowVerticalPosition >= 0);
}
});
Con este pequeño fragmento ahora funciona perfectamente.
Feliz codificación!
Fuente - http://nlopez.io/swiperefreshlayout-with-listview-done-right/
Deseo implementar la funcionalidad de desplazamiento para actualizar con un listView. También hay otros elementos de vista en el mismo archivo de diseño que se muestran si la lista está vacía. Aquí está mi archivo de diseño. El problema es que cuando me desplazo hacia abajo y luego trato de desplazarme hacia arriba, en lugar de desplazarme hacia la parte superior y luego actualizarlo, simplemente se actualiza y el desplazamiento hacia arriba no funciona.
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="64dp"
android:paddingLeft="16dp"
android:paddingRight="16dp" >
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@drawable/inbox_empty" />
<TextView
android:id="@+id/noEventsText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_toRightOf="@+id/noEventsIcon" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignParentBottom="true"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:background="@color/dividerOnBlack" />
</RelativeLayout>
<ListView
android:id="@+id/list_items"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:cacheColorHint="@android:color/transparent"
android:choiceMode="multipleChoice"
android:descendantFocusability="afterDescendants"
android:divider="@android:color/transparent"
android:dividerHeight="0px"
android:scrollbars="none" />
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
Este es mi método onScroll.
@Override
public void onScroll(AbsListView view,int firstVisibleItem,int visibleItemCount,int totalItemCount) {
// If the total item count is zero and the previous isn''t, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) { this.loading = true; }
}
// If it''s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
currentPage++;
}
// If reverse then the firstVisibleItem is calculated wrong
if (reverse) {
firstVisibleItem = totalItemCount - firstVisibleItem;
}
// If it isn''t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
if (!loading && (totalItemCount - visibleItemCount)<=(firstVisibleItem + visibleThreshold)) {
onLoadMore(currentPage + 1, totalItemCount);
loading = true;
}
}
Incluso más simple simplemente configure SwipeRefreshLayout
habilitado si firstVisibleItem
o deshabilitado si no:
yourList.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
yourSwipeRefreshLayout.setEnabled(firstVisibleItem == 0);
}
});
Para que SwipeRefreshLayout funcione, debe ser el padre directo de ListView y ListView debería ser la primera vista secundaria activa de SwipeRefreshLayout.
La documentación de SwipeRefreshLayout dice que ListView debería ser el único elemento secundario, pero está bien si tiene más de un elemento secundario, siempre que ListView sea el primero. Esto significa, por ejemplo, que SwipeRefreshLayout funcionará bien si está usando un adaptador con una vista para "vacío". Por ejemplo:
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NearbyJobsActivity$PlaceholderFragment">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/list_divider"
android:dividerHeight="1dp"
android:listSelector="@drawable/list_row_selector" />
<TextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" />
</android.support.v4.widget.SwipeRefreshLayout>
Si puede administrar este tipo de diseño, SwipeRefreshLayout funcionará bien y no necesitará ninguna de las soluciones alternativas enumeradas en otras respuestas.
Mi propio problema fue que estaba cargando mi ListView como un Fragmento, así que en realidad tenía:
<SwipeRefreshLayout>
<FrameLayout> )
<ListView/> / fragment
<TextView/> /
</FrameLayout> )
</SwipeRefreshLayout>
Así que SwipeRefreshLayout elegía FrameLayout ya que es "objetivo" y su canChildScrollUp()
predeterminada canChildScrollUp()
siempre devolvía false. Una vez que moví SwipeRefreshLayout dentro del Fragment, todo comenzó a funcionar correctamente.
<FrameLayout>
<SwipeRefreshLayout> )
<ListView/> / fragment
<TextView/> /
</SwipeRefreshLayout> )
</FrameLayout>
Realice su propia implementación de SwipeRefreshLayout y anule canChildScrollUp de esta manera:
@Override
public boolean canChildScrollUp() {
if (scrollView != null)
return scrollView.canScrollVertically(-1);
return false;
}
simplemente reemplácelo con cualquier subclase de ScrollView.
Tuve el mismo problema y lo resolví:
listView = (ListView) findViewById(R.id.listView);
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (listView.getChildAt(0) != null) {
swipeRefreshLayout.setEnabled(listView.getFirstVisiblePosition() == 0 && listView.getChildAt(0).getTop() == 0);
}
}
});
Tuve un problema similar cuando el elemento secundario de mi SwipeRefreshLayout
era un FrameLayout
que tenía un TextView
y ListView
como elementos TextView
y cuando me desplazaba hacia arriba en el ListView
, intentaba hacer una actualización.
Lo arreglé usando un FrameLayout
personalizado que anula el método canScrollVertically()
paquete com.wi.director.ui.common;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* Created by devansh on 9/22/15.
*/
public class FrameLayoutForSwipeRefresh extends FrameLayout {
public FrameLayoutForSwipeRefresh(Context context) {
super(context);
}
public FrameLayoutForSwipeRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FrameLayoutForSwipeRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public boolean canScrollVertically(int direction) {
if (super.canScrollVertically(direction)) {
return true;
}
int cc = getChildCount();
for (int i = 0; i < cc; i++) {
if (getChildAt(i).canScrollVertically(direction)) {
return true;
}
}
return false;
}
}