web-dev-qa-db-ja.com

リストビューのSwipeRefreshLayoutで上にスクロールできない

ListViewで機能を更新するためにスクロールを実装します。また、同じレイアウトファイルには、リストが空の場合に表示される他のビュー要素があります。これが私のレイアウトファイルです。問題は、一番下までスクロールしてから更新するのではなく、下にスクロールしてから上にスクロールしようとすると、そこで更新されるだけで、上にスクロールできないことです。

<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>

これが私の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;
    }
}
34
user3773337

SwipeRefreshLayoutが機能するためには、ListViewがListViewの直接の親であり、ListViewがSwipeRefreshLayoutの最初のアクティブな子ビューである必要があります。

SwipeRefreshLayoutのドキュメントには、ListViewが唯一の子である必要があると記載されていますが、ListViewが最初である限り、複数の子がある場合でも問題ありません。これは、たとえば、「空」のビューを持つアダプターを使用している場合、SwipeRefreshLayoutが正常に機能することを意味します。例えば:

_<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>
_

この種のレイアウトを管理できる場合、SwipeRefreshLayoutは正常に機能し、他の回答に記載されている回避策は必要ありません。

私自身の問題は、リストビューをフラグメントとしてロードしていたことでした。そのため、実際には次のようになりました。

_<SwipeRefreshLayout>

    <FrameLayout>           )
         <ListView/>        \ fragment
         <TextView/>        /
    </FrameLayout>          )

</SwipeRefreshLayout>
_

そのため、SwipeRefreshLayoutは「ターゲット」としてFrameLayoutを選択し、そのデフォルトのcanChildScrollUp()実装は常にfalseを返していました。 SwipeRefreshLayoutをFragment内に移動すると、すべてが正常に機能し始めました。

_<FrameLayout>

    <SwipeRefreshLayout>    )
         <ListView/>        \ fragment
         <TextView/>        /
    </SwipeRefreshLayout>   )

</FrameLayout>
_
53
Paul LeBeau

私は同じ問題を抱えて解決しました:

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);
        }
    }
});
30
the_dani

このようなレイアウトを作成します。

<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>

これをそのまま使用すると、そのビューで上にスクロールするたびにSwipeRefreshLayoutが起動および更新され、アプリがリスト内で上にスクロールできなくなります。

ここでのコツは、リストビューからOnScrollListenerを手動で配線することです。表示されている最初の行が最初の一番上の位置に一致するかどうかを確認し、SwipeRefreshLayoutを有効にします。それ以外の場合は、無効にします。

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);
    }
});

この小さなスニペットを使用すると、完全に機能します。

ハッピーコーディング!

ソース- http://nlopez.io/swiperefreshlayout-with-listview-done-right/

28

SwipeRefreshLayoutの独自の実装を作成し、この方法でcanChildScrollUpをオーバーライドします。

@Override
public boolean canChildScrollUp() {
if (scrollView != null)
    return scrollView.canScrollVertically(-1);

return false;
}

scrollViewのサブクラスに置き換えるだけです。

10
Rishabh

私のSwipeRefreshLayoutの子がFrameLayoutTextViewを子として持つListViewであり、ListView更新を試みます。

canScrollVertically()メソッドをオーバーライドするカスタムFrameLayoutを使用して修正しました

パッケージ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;
    }
}
5
dg428

さらに簡単にSwipeRefreshLayoutを有効に設定するだけですiffirstVisibleItemまたはそうでない場合は無効になります:

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);
    }
});
3
Kevin Crain

GridviewがSwipefreshlayoutの使用を開始します

gridView.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 (gridView.getChildAt(0) != null) {
                mrefreshlayout.setEnabled(gridView.getFirstVisiblePosition() == 0 && gridView.getChildAt(0).getTop() == 0);
            }

         }


       });

xmlのレイアウト

<Android.support.v4.widget.SwipeRefreshLayout
    Android:id="@+id/swiperefreshlayout"
    Android:layout_height="match_parent"
    Android:layout_width="match_parent">

    <LinearLayout
        Android:background="#ffffff"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:orientation="vertical">

        <GridView
            Android:background="#ffffff"
            Android:gravity="center"
            Android:verticalSpacing="2dp"
            Android:horizontalSpacing="2dp"
            Android:numColumns="2"
            Android:id="@+id/grid_view"
            Android:animateLayoutChanges="true"
            Android:overScrollMode="always"
            Android:scrollbars="vertical"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"/>

        <TextView
            Android:id="@+id/nofieldtv"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:layout_above="@+id/adlayout"
            Android:textColor="#000000"
            Android:gravity="center"
            Android:visibility="gone"
            Android:textSize="16sp"
            Android:layout_below="@+id/headerLayout"
            Android:layout_marginTop="2dp">

        </TextView>

    </LinearLayout>


</Android.support.v4.widget.SwipeRefreshLayout>
0
Najaf Ali

基本的に、スクロール可能なものをスクロールする必要があります。すべてのビューをScrollViewに配置できます。

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content">

        <LinearLayout
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:orientation="vertical">

        </LinearLayout>
    </ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

ただし、ListViewのスクロールにはいくつかの変更が必要になる場合があります- wrap_content ListView

0
Adrian Grygutis