web-dev-qa-db-ja.com

AndroidのSwiperefreshLayout

以下のレイアウトでSwipeRefreshLayoutを使用しています:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
  Android:layout_width="wrap_content"
  Android:layout_height="wrap_content"
  Android:background="@color/homePageBackground"
  Android:orientation="vertical" >


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

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical" >
<fragment
        Android:id="@+id/announcementHomefragment"
        Android:name="in.test.app.AnnouncementFragment"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content" />
        <ScrollView
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:background="@color/homePageBackground" >

            <RelativeLayout
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:layout_marginBottom="15dp"
                Android:background="@color/homePageBackground" >

                <TextView
                    Android:id="@+id/newsTitle"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_gravity="center"
                    Android:layout_marginLeft="15dp"
                    Android:layout_marginTop="5dp"
                    Android:gravity="center"
                    Android:text="@string/new_list"
                    Android:textAppearance="?android:attr/textAppearanceSmall"
                    Android:textColor="@color/white"
                    Android:textStyle="bold" />

                <fragment
                    Android:id="@+id/newshomefragment"
                    Android:name="in.test.app.NewsFragment"
                    Android:layout_width="wrap_content"
                    Android:layout_height="190dp"
                    Android:layout_below="@id/newsTitle"
                    Android:layout_marginTop="-15dp" />

                <TextView
                    Android:id="@+id/productTitle"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_below="@id/newshomefragment"
                    Android:layout_gravity="center"
                    Android:layout_marginLeft="15dp"
                    Android:layout_marginTop="5dp"
                    Android:gravity="center"
                    Android:text="@string/product_in_home"
                    Android:textAppearance="?android:attr/textAppearanceSmall"
                    Android:textColor="@color/white"
                    Android:textStyle="bold" />

                <fragment
                    Android:id="@+id/proCategoryhomefragment"
                    Android:name="in.test.app.CategoryFragment"
                    Android:layout_width="wrap_content"
                    Android:layout_height="170dp"
                    Android:layout_below="@id/productTitle"
                    Android:layout_marginTop="-15dp" />

                <TextView
                    Android:id="@+id/trainingTitle"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    Android:layout_below="@id/proCategoryhomefragment"
                    Android:layout_gravity="center"
                    Android:layout_marginLeft="15dp"
                    Android:layout_marginTop="2dp"
                    Android:gravity="center"
                    Android:text="@string/trainings_in_home"
                    Android:textAppearance="?android:attr/textAppearanceSmall"
                    Android:textColor="@color/white"
                    Android:textStyle="bold" />

                <fragment
                    Android:id="@+id/trainingfragment"
                    Android:name="in.test.app.TrainingFragment"
                    Android:layout_width="match_parent"
                    Android:layout_height="180dp"
                    Android:layout_below="@id/trainingTitle"
                    Android:layout_marginBottom="10dp"
                    Android:layout_marginTop="-15dp" />
            </RelativeLayout>
        </ScrollView>
    </LinearLayout>
</Android.support.v4.widget.SwipeRefreshLayout>

SwipeRefreshLayoutをプルダウンすると機能しますが、上記のコードを見るとわかるように、内部にスクロールビューがあります。したがって、スクロールビューをプルダウンすると、スクロールビューがダウンし、下に移動したために画像の半分が表示されません。もう一度プルアップしようとすると、スクロールビューが表示されません。代わりに、SwipeRefreshLayoutが呼び出されます。私は何をすべきか?

私を助けてください。

17
rupesh

このレイアウトを表示するクラスからさまざまな条件を追加できるようにするには、リスナー付きの拡張SwipeRefreshLayoutを使用する方がよいと思います。

次のようなもの:GeneralSwipeRefreshLayout.Java

public class GeneralSwipeRefreshLayout extends SwipeRefreshLayout {   
  private OnChildScrollUpListener mScrollListenerNeeded;

  public interface OnChildScrollUpListener {
    boolean canChildScrollUp();
  }

  public GeneralSwipeRefreshLayout(Context context) {
    super(context);   
  }
  public GeneralSwipeRefreshLayout(Context context, AttributeSet attrs) {
    super(context, attrs);   
  }

 /**
  * Listener that controls if scrolling up is allowed to child views or not
  */
  public void setOnChildScrollUpListener(OnChildScrollUpListener listener) {
    mScrollListenerNeeded = listener;   
  }

  @Override
  public boolean canChildScrollUp() {
    if (mScrollListenerNeeded == null) {
      Log.e(GeneralSwipeRefreshLayout.class.getSimpleName(), "listener is not defined!");
    }
    return mScrollListenerNeeded != null && mScrollListenerNeeded.canChildScrollUp();
  }
}

次に、ListViewまたはGridViewレイアウトを含むSwipeRefreshLayoutを表示するクラス内で、次のようなことができます。

mSwipeLayout.setOnChildScrollUpListener(new OnChildScrollUpListener() {
  @Override
  public boolean canChildScrollUp() {
    return mListView.getFirstVisiblePosition() > 0 || 
           mListView.getChildAt(0) == null || 
           mListView.getChildAt(0).getTop() < 0;
  }
});
29
goRGon

extendsSwipeRefreshLayoutおよびoverrideメソッドcanChildScrollUp()のクラスを作成するだけです。コントロールを下にスクロールする場合はtrueを返します。

たとえば、scrollviewの場合、これを試すことができます。

@override.
boolean canChildScrollUp()
{
   //your condition to check scrollview reached at top while scrolling
   if(scrollview.getScrollY() == 0.0)
      return true;
   else
      return false;
}
6
AndyN

他の人がすでに述べたように、SwipeRefreshLayoutの直接の子としてスクロール可能なビュー(つまり、リストビュー)がない場合、在庫のcanChildScrollUpは機能しません。

子ビューのスクロール機能のチェックでSwipeRefreshLayoutが使用する単純なロジックと関係があります。

私はActionbarActivity内でListViewを使用していて、リストビューが空のときは常に空のビューを含めたいと思っていました。 SwipeRefreshLayoutクラスは子を1つしか持つことができないため、これにより問題が発生しました。また、この子のscrollUp機能をチェックして、プルダウンによって子がscrollUpになるか、または子のコンテンツが更新されるかを判別します。

したがって、SwipeRefreshLayoutと同じロジックを使用する場合は、クラスを拡張し、スクロール可能なビューにハンドルを渡すことができるメソッドを作成します。ストックの実装ではcanScrollVertically()を使用していますが、これはまさに私たちが望むことを行いますが、SDK> = 14でのみ表示されます。

また、クラスを拡張するときは、パラメーター「AttributeSet」を含むコンストラクターを含めることを忘れないでください。そうしないと、レイアウトファイルでクラスを使用するときに問題が発生します。

したがって、リストビューを含むアクティビティ(この場合はActionBarActivity)のonCreateメソッドで、ListViewまたはスクロールに使用するビューを渡してsetMyScrollableViewを呼び出すだけです。

/*Constructor*/
public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}


 View mMyScrollableView = null;  //The content that get's pulled down.
 /*Method used to pass in my scrollable view*/
 public void setMyScrollableView(View view){
    mMyScrollableView = view;
 }

/**
 * @return Whether it is possible for the child view of this layout to
 * scroll up.  This was taken for the most part directly from SwipeRefreshLayout
 */
public boolean canChildScrollUp() {
    if(mMyScrollableView == null)
      return false;
    if (Android.os.Build.VERSION.SDK_INT < 14) {
        if (mMyScrollableView instanceof AbsListView) {
            final AbsListView absListView = (AbsListView) mMyScrollableView;
            return absListView.getChildCount() > 0
        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
        .getTop() < absListView.getPaddingTop());
        } else {
            return mMyScrollableView.getScrollY() > 0;
        }
    } else {
        return ViewCompat.canScrollVertically(mMyScrollableView, -1);
    }
}
5
guyland123

@ User22791のソリューションは完全に機能し、それに基づいて、githubで使用可能なライブラリを作成しました。これを使用して(そして変更して)、開発者がswipeRefreshLayoutを簡単に使用できるようにします。それはここにあります: https://github.com/dagova/referencedSwipeRefreshLayout

基本的には、canChildScrollUpメソッドでチェックするビューをレイアウトで参照する必要があります。お役に立てれば幸いです。

3
David Varela

より簡単な解決策は、onScrollListenerを使用して、ユーザーがfirstElementを表示できるかどうかを確認することです。

someView.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView absListView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (isViewAtTop()) {
                swipeLayout.setEnabled(true);
            } else {
                swipeLayout.setEnabled(false);
            }
        }

    }

    @Override
    public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == 0) {
            swipeLayout.setEnabled(true);
        } else {
            swipeLayout.setEnabled(false);
        }
    }
});

メソッドisViewAtTop()は他のいくつかのメソッドであり、このビューが最上部にスクロールされていることを確認します

2
c0rp

他の回答もうまくいかないこともわかりました。

彼らがメソッドgetScrollY()を使用していることを理解するために少し頭を悩ませました-これは this answer が説明しているように、これまでのViewメソッドですScrollコンテナがどれだけスクロールされたかを示す方法ではなく、コンテナ内でスクロールします。

他の回答と同じ手法を使用する場合(canChildScrollUp()メソッドをオーバーライド)、Scrollableがその最高点にあるかどうかを簡単に確認できます。

@Override
public boolean canChildScrollUp() {
    return !isListAtTop();
}

private boolean isListAtTop()   {   
    if(mGridView.getChildCount() == 0) return true;
    return mGridView.getChildAt(0).getTop() == 0;
}

(ご覧のとおり、私はGridViewを使用していますが、ListViewも使用できます)

2
Graeme

わかりました。 SwipeRefreshLayoutがレイアウトのルートであり、ScrollViewが階層の深い場所にある場合(私はScrollViewRelativeLayoutの中に入れました)、 SwipeRefreshLayoutの直接の子である場合、ScrollViewのスワイプが適切に検出されません。

SwipeRefreshLayoutを拡張するカスタムクラスを作成し、SwipRefreshLayoutcanChildScrollUp()メソッドをオーバーライドする必要があります

次に例を示します。

 public class CustomSwipeRefreshLayout extends SwipeRefreshLayout {

    private ScrollView scrollview;

    public CustomSwipeRefreshLayout(Context context) {
        super(context);
    }

    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setView(ScrollView view) {
        this.scrollview = view;
    }

    @Override
    public boolean canChildScrollUp() {
        return scrollview.getScrollY() != 0;
    }

}
1
nitesh goel