Android Pull-to-Refreshの実装方法


433

Twitter(公式アプリ)などのAndroidアプリケーションでは、ListViewに遭遇したときに、それをプルダウンして(解放するとバウンスして)、コンテンツを更新できます。

あなたの意見では、それを実装するための最良の方法は何ですか?

私が考えることができるいくつかの可能性:

  1. ListViewの上の項目-ただし、ListViewのアニメーションを使用して項目の位置1(0から始まる)にスクロールして戻るのは簡単な作業ではないと思います。
  2. ListViewの外にある別のビュー-しかし、プルされたときにListViewの位置を下に移動する必要があるので、ListViewへのドラッグタッチが実際にListViewのアイテムをスクロールしているかどうかを検出できるかどうかはわかりません。

何かお勧めですか?

PS公式Twitterアプリのソースコードがいつリリースされるのかしら。発売されるとのことですが、6ヶ月が経ち、それ以来、そのことは聞いていません。


この機能は、動的に作成されたTableLayoutに実装できますか?助けてください.....
アルンバドール

github.com/fruitranger/PulltorefreshListViewは、私のもう1つの実装です。スムーズでマルチタッチのサポート。
Changwei Yao

6
関連:「Pull-to-refresh」:AndroidのアンチUIパターンは、このUI Androidで使用する必要があるものではなく、その適切性について多くの議論を巻き起こしたものであると主張する記事です。
blahdiblah 2013年

29
Android向けGmailの最新バージョンはこの「アンチパターン」を使用しているため、誰かにGoogleに知らせる必要があります。
Nick

4
プルトゥリフレッシュは、iOSとAndroidで標準的に採用されているパターンであり(しばらくの間)、非常に自然なため、このアンチパターンディスカッションは時代遅れです。ユーザーはそれが表示されることを期待し、そのように動作します。
Martin Marconcini、2014

回答:


311

最後に、Googleはpull-to-refreshライブラリの公式バージョンをリリースしました!

これはSwipeRefreshLayout、サポートライブラリ内で呼び出され、ドキュメントは次のとおりです

  1. SwipeRefreshLayoutレイアウトを更新するプルとして扱われるビューの親として追加します。(私が取ったListView例として、それはどんなことができるViewようにLinearLayoutScrollViewなど)

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pullToRefresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </android.support.v4.widget.SwipeRefreshLayout>
  2. クラスにリスナーを追加する

    protected void onCreate(Bundle savedInstanceState) {
        final SwipeRefreshLayout pullToRefresh = findViewById(R.id.pullToRefresh);
        pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshData(); // your code
                pullToRefresh.setRefreshing(false);
            }
        });
    }

pullToRefresh.setRefreshing(true/false);必要に応じて呼び出すこともできます。

更新

Androidサポートライブラリは非推奨になり、AndroidXに置き換えられました。新しいライブラリへのリンクはここにあります

また、次の依存関係をプロジェクトに追加する必要があります。

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

または

Refactor >> Migrate to AndroidXに移動すると、Android Studioが依存関係を処理します。


3
SwipeRefreshLayoutでカラースキームの代わりにProgressBarを使用できますか?
pablobaldez 2014年

54
144月1日 -そしてそれは冗談ではなかった
aeracode

2
サンプルコードガイド.codepath.com
android

80

私はプルトゥリフレッシュコンポーネントを実装しようとしましたが、完全とはほど遠いですが、可能な実装を示していますhttps://github.com/johannilsson/android-pulltorefresh

メインロジックはPullToRefreshListViewその拡張に実装されていますListView内部的には、smoothScrollBy(APIレベル8)を使用してヘッダービューのスクロールを制御します。ウィジェットは1.5以降のサポートで更新されましたが、1.5サポートのREADMEを読んでください。

レイアウトでは、次のように追加するだけです。

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />

3
こんにちは、ヨハン、サンプルコードをダウンロードしました。Android 2.2デバイスでは機能しますが、2.1デバイスでは機能しません。2.2以降でしか利用できないsmoothScrollByメソッドを使っていたので正しいと思いますか?また、この効果を2.1以前のバージョンに実装するアイデアはありますか?ありがとう

はい、それは正解です。smoothScrollByはAPIレベル8(2.2)で導入された回答で述べたとおりです。他のバージョン用に適切に実装する方法はまだわかりませんが、smoothScrollByの実装を移植することは可能だと思いますが、スタックオーバーフローではなくプロジェクトサイトで議論を続ける必要があると思いますか?
Johan Berg Nilsson

IDが@ + id / android:listであり、@ android:id / listではないのは意図的なものですか?プロジェクトはここでインフレエラーをスローします。私は現在それをチェックしています...
Mathias Conradt

12
これは、私が見つけたプルトゥリフレッシュに最適なライブラリです。github.com/chrisbanes/Android-PullToRefresh。ListViews、GridViews、Webviewsで動作します。Pull up to refreshパターンも実装されています。
rOrlig

1
Intellij Ideaで作業中にプロジェクトをライブラリフォルダーに追加するにはどうすればよいですか?誰かが私を助けてくれますか?
MustafaGüven2013年

55

また、Android用の堅牢でオープンソースで使いやすく高度にカスタマイズ可能なPullToRefreshライブラリを実装しました。プロジェクトページのドキュメントで説明されているように、ListViewをPullToRefreshListViewに置き換えることができます。

https://github.com/erikwt/PullToRefresh-ListView


私はここにリストされているすべての実装を試しましたが、実装を更新するためのシンプル/純粋/スムーズなプル(Johanのような奇妙さを更新するためのタップはありません)に関しては、あなたの実装が最善です。ありがとう!
Gady

1
これは、ListActivity、ListFragmentなどで動作するように標準のListViewを置き換えることができますか?
davidcesarino 2012

はい、PullToRefreshListViewに正しいIDを指定するだけです。XML:android:id = "@ android:id / list"
Erik

1
これは本当に素晴らしいです!グーグルは私をここに連れて来て、そして例を通して見ると、あなたのものは実装するのが最も簡単に見えます。ブラボー、ありがとうございます!
エヴァンR.

非常に賢明に設計されたコンポーネント、素晴らしくシンプル。これは間違いなく受け入れられる答えになるはずです。
アダム

41

私が考える最も簡単な方法は、Androidサポートライブラリによって提供されるものです。

android.support.v4.widget.SwipeRefreshLayout;

インポートしたら、次のようにレイアウトを定義できます。

  <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    <android.support.v7.widget.RecyclerView
        xmlns:recycler_view="http://schemas.android.com/apk/res-auto"
        android:id="@android:id/list"
        android:theme="@style/Theme.AppCompat.Light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/button_material_light"
        >

    </android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>

リストビューの代わりにリサイクラービューを使用していると思います。ただし、リストビューは引き続き機能するため、recyclerviewをリストビューに置き換えて、Javaコード(フラグメント)の参照を更新するだけです。

アクティビティフラグメントでは、最初に次のインターフェイスを実装しますSwipeRefreshLayout.OnRefreshListener:i、e

public class MySwipeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
private SwipeRefreshLayout swipeRefreshLayout;

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_item, container, false);
        swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh);
        swipeRefreshLayout.setOnRefreshListener(this);
}


 @Override
  public void onRefresh(){
     swipeRefreshLayout.setRefreshing(true);
     refreshList();
  }
  refreshList(){
    //do processing to get new data and set your listview's adapter, maybe  reinitialise the loaders you may be using or so
   //when your data has finished loading, cset the refresh state of the view to false
   swipeRefreshLayout.setRefreshing(false);

   }
}

これが大衆を助けることを願っています


うまくいきます。しかし、一つのことについてはsetRefreshing:で説明したように「リフレッシュがスワイプジェスチャーによってトリガされたとき、これを呼び出さないでください」developer.android.com/reference/android/support/v4/widget/...
gabriel14

よくやった!ありがとう。
technik 2017

22

このリンクでは、有名なのフォーク見つけることができPullToRefresh、新たな面白いような実装があるビューPullTorRefreshWebViewまたはPullToRefreshGridViewまたは追加する可能性がPullToRefreshリストの下端にします。

https://github.com/chrisbanes/Android-PullToRefresh

そして、その最高のものはAndroid 4.1で完璧に機能することです(通常PullToRefreshは機能しません)


3
READMEの上部にある大きなコメントは、次のことを示しています。このプロジェクトは維持されていません。とにかく、このlibは私が今まで見た中で最高のものです!すごい仕事!
ミルトン

3
それがもはや維持されていないからといって、それが良くないという意味ではありません。それでも、私のプルを更新する必要がある場合はすべてそれを使用してください:)
Muz

18

これを行うには非常に簡単な方法がありますが、今では間違いなく確実な方法です。コードPullDownListView.javaがあります。

package com.myproject.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

/**
 * @author Pushpan
 * @date Nov 27, 2012
 **/
public class PullDownListView extends ListView implements OnScrollListener {

    private ListViewTouchEventListener mTouchListener;
    private boolean pulledDown;

    public PullDownListView(Context context) {
        super(context);
        init();
    }

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

    public PullDownListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        setOnScrollListener(this);
    }

    private float lastY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            lastY = ev.getRawY();
        } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            float newY = ev.getRawY();
            setPulledDown((newY - lastY) > 0);
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (isPulledDown()) {
                        if (mTouchListener != null) {
                            mTouchListener.onListViewPulledDown();
                            setPulledDown(false);
                        }
                    }
                }
            }, 400);
            lastY = newY;
        } else if (ev.getAction() == MotionEvent.ACTION_UP) {
            lastY = 0;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        setPulledDown(false);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    public interface ListViewTouchEventListener {
        public void onListViewPulledDown();
    }

    public void setListViewTouchListener(
            ListViewTouchEventListener touchListener) {
        this.mTouchListener = touchListener;
    }

    public ListViewTouchEventListener getListViewTouchListener() {
        return mTouchListener;
    }

    public boolean isPulledDown() {
        return pulledDown;
    }

    public void setPulledDown(boolean pulledDown) {
        this.pulledDown = pulledDown;
    }
}

このListViewを使用してリスナーを設定するアクティビティにListViewTouchEventListenerを実装するだけです

PullDownListViewActivityに実装しています

package com.myproject.activities;

import android.app.Activity;
import android.os.Bundle;

/**
 * @author Pushpan
 *
 */
public class PullDownListViewActivity extends Activity implements ListViewTouchEventListener {

    private PullDownListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        listView = new PullDownListView(this);
        setContentView(listView);
        listView.setListViewTouchListener(this);

        //setItems in listview
    }

    public void onListViewPulledDown(){
        Log.("PullDownListViewActivity", "ListView pulled down");
    }
}

わたしにはできる :)


18

AndroidのPull-to-Refreshを実装するには、次のコードを試してください。

<android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pullToRefresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

</android.support.v4.widget.SwipeRefreshLayout>

活動クラス:

ListView lv = (ListView) findViewById(R.id.lv);
SwipeRefreshLayout pullToRefresh = (SwipeRefreshLayout) findViewById(R.id.pullToRefresh);


lv.setAdapter(mAdapter);

pullToRefresh.setOnRefreshListener(new OnRefreshListener() {

        @Override
        public void onRefresh() {
            // TODO Auto-generated method stub

            refreshContent();

        }
    });



private void refreshContent(){ 

     new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                pullToRefresh.setRefreshing(false);
            }
        }, 5000);

 }

1
Thanks.itは本当に役に立ちました
Arpan Sharma

9

Google NowやGmailアプリケーションのようにアクションバーの上に表示される新しいタイプの「プルトゥリフレッシュ」については誰も触れていません。

まったく同じように機能するライブラリActionBar-PullToRefreshがあります。


7

AndroidおよびWPに実装する場合は、UXの問題に対処する必要があります。

「デザイナ/開発者がiOSアプリのスタイルでプルトゥリフレッシュを実装してはならない理由の優れた指標は、GoogleとそのチームがAndroidでプルトゥリフレッシュをiOSで使用しているときに使用しないことです。」

https://plus.google.com/109453683460749241197/posts/eqYxXR8L4eb


3
これは1年以上前のものですが、Gmailアプリはプルトゥリフレッシュを使用しています。ただし、UIの点ではまったく同じではありません。リストは下にスクロールされず、画面の上部に新しいビューが表示されます。
ashishduh 2013

4

プログラムをAndroidに強制的に組み込まれたiPhoneプログラムのように見せたくない場合は、よりネイティブなルックアンドフィールを目指し、Gingerbreadと同様のことを行います。

代替テキスト


2
@Rob:iPhoneのようにリストを跳ね返すのではなく、引っ張ったときにリストの上部にオレンジ色の影を付けることを意味しました。これはコメント(回答ではない)ですが、コメントに画像を含めることはできません。
リーライアン

ああ、申し訳ありませんが、素晴らしいアイデアです。私はまだジンジャーブレッドで遊んだことがないので、効果を見ていませんでした。グーグルがネクサスにロールするのをまだ待っています。
Rob

9
私はジンジャーブレッドを持っていて、リストが静的である場合、オレンジ色の輝きはうまく機能します。しかし、pull-down-refreshは、動的リストを更新するための優れたUIメカニズムです。これはiOSの世界で流行していますが、Androidエコシステムでは奇妙に感じられないUIトリックです。公式Twitterアプリでぜひチェックしてみてください。:)
ティエリー・ディミトリ・ロイ

ここでのネイティブの動作は、リストの最後に到達したことを示すことです。これを実行して更新を実行することは、プラットフォームが行うことをしていないのと同じようにネイティブではありません。つまり、ユーザーを驚かせる可能性が高くなります。リストの最後に達したからといって、更新を期待したり、更新したりすることはありません。プルダウンして更新すると、より直感的で明確になります。そして、ネイティブのTwitterアプリがそれを使用しているので、多くの人々が精通しているUIコンセプトであると言っても差し支えないと思います。
ステップローブ

4

私はここにプルトゥリフレッシュコンポーネントを作成しました:https : //github.com/guillep/PullToRefresh リストにアイテムがない場合、これは動作するイベントであり、> = 1.6のAndroidフォンでテストしました。

提案や改善はありがたいです:)



1

最新のLollipop Pull-To Refreshを入手するには:

  1. 最新のLollipop SDKとExtras / Androidサポートライブラリをダウンロード
  2. プロジェクトのビルドターゲットをAndroid 5.0に設定します(そうしないと、サポートパッケージでリソースにエラーが発生する可能性があります)
  3. libs / android-support-v4.jarを21番目のバージョンに更新します
  4. android.support.v4.widget.SwipeRefreshLayoutプラスを使用android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

詳細なガイドはここで見つけることができます:http : //antonioleiva.com/swiperefreshlayout/

さらに、ListViewについてcanChildScrollUp()は、コメントで読むことをお勧めします;)


さらに、canChildScrollUp()について言及するための1つ。とても重要です!
Petro

1

Yalantisによる非常に興味深いPull-to-Refresh。iOS用のGIFですが、あなたはそれをチェックすることができます:)

<com.yalantis.pulltorefresh.library.PullToRefreshView
android:id="@+id/pull_to_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
    android:id="@+id/list_view"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />


0

まず、Androidでレイアウトを更新するためのプルとは何かを知っておく必要があります。Androidでは、pullを呼び出してスワイプして更新することで更新できます。画面を上から下にスワイプすると、setOnRefreshListenerに基づいてアクションが実行されます。

ここでのチュートリアルリフレッシュするには、Androidプルを実装する方法について示しています。これがお役に立てば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.