Pull to Refreshツールの選択

最近、プロジェクトにリストを更新するためのPull To Refreshメカニズム導入する問題に遭遇しました。 利用可能なリスト(0から100までのさまざまな長さのリスト、オンデマンドでアイテムをロードする、リストのセットは自己記述コンポーネントala ViewPagerにある )の特異性により、これは本当に問題があることが判明しました。 カットの下でこの方向に私のすべての研究について読んでください。



Pull To Refresh-チップは、私が知る限り、iPhoneからAndroidに移行しました。 リストを更新する便利な方法。

ニュースアプリケーションの例として考えてみてください(実際、この機能を実装する必要がありました)。ニュースサーバーを介して更新されるニュースのリストがあります。 更新は手動で行われるため、更新ボタンが下部に突き出ており、画面上のスペースを占有します。 また、プルトゥリフレッシュテクニックを使用できる場合、あまり使用されないボタンの貴重な画面スペースを無駄にするのはなぜですか。リストの一番上にある間にリストを下にドラッグし、それを離してリストを更新します。 新しいニュース(意図したしゃれ)がアップロードされ、表示されます。 これは例のように見えます:







このアイデアは非常に成功しているため、人気のFacebookやTwitterクライアントを含む多くのアプリケーションで使用されています。 そこで、このような機能をニュースプロジェクトに導入することにしました。

しかし、なぜ既製のものをゼロから書くのでしょうか? Googleの簡単な検索、すばらしい強力なStackOverFlow-そして、これがJohan Nielsonの最も人気のあるandroid-pulltorefreshツールです 。 GitHubから最新バージョンを取得し、自分で入手しました。 あった! このプロジェクトはほぼ1年間開発されているようですが、...これは小さなリストの場合に見られるものです。



そして、そのような質問がすぐに発生します: WTF? このプロジェクトは418人を監視し、71人が分岐しました。ここでは、このような不適切な行動が見られます。 そして、なぜですか? これは「タップして更新...」がListViewヘッダーだからです。 そして彼はJohanの実装で、ありふれたListViewを隠しています。 setSelection(1) そして、短いリストの場合、このsetSelection(1) はfeckに丁寧に送信しません。

しかし、プロジェクトにはさらに2つのブランチがあることがわかりました。EnhancedPull(メインブランチに既に隣接していた)と、最終的にscrollfix_for_short_list :)

scrollfix_for_short_listブランチの最新バージョンをプルして、プロジェクトにねじ込みます。短いリストはうまく見えますが、なぜUIの速度が低下し始めたのですか? しかし、問題はこれです:私のリストは単純ではありませんが、オンデマンドの読み込み、つまり 最初の10個のアイテムが最初に表示され、最後までスクロールすると、次の部分がリストにロードされます。 そして、ヨハンによると短いリストの修正は何ですか?

「そして、正確にそのような高さの空のビューをフッターListViewに追加して、 setSelection(1)が再びヘッダーを非表示にできるようにします 」とJohanが言って、フッターの高さを減算しました。 その高さを計算するには、リスト内のすべての要素の合計高さを知る必要があります(もちろん、ヘッダーを除く)。 次に、この高さをListViewの高さから減算し、フッターの高さを取得します。 そして、リストの各要素の高さを見つけるために、どこかから 、アダプタですべての要素を反復処理しgetView()を使用)、それぞれを測定 する 「邪魔な」決定が行われました。 基本的にそれらを描画します(たとえ非表示であっても)。 その結果、私のリストは誰もがそれを転がし、転がしていると考えました-そして、要素が完了するまで新しい部分をロードしてロードします。 そして、通常、リストには50を超える要素があり、いくつかのリスト(最近登場したViewPagerのようにスクロールします)。 一般に、リストアイテムの合計の高さを計算する実装は次のとおりです。

private int getTotalItemHeight() { ListAdapter adapter = getAdapter(); int listviewElementsheight = 0; for(int i = 0; i < adapter.getCount(); i++) { View mView = adapter.getView(i, null, this); // wtf? mView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); listviewElementsheight += mView.getMeasuredHeight(); } return listviewElementsheight; }
      
      





オンデマンドリストには絶対に適していません。 とにかく、 getView()をアダプターから手動でプルすることは避けください。 誰がどのようなロジックがそこに置かれているのか知っていますか?

その結果、より適切なツールを探してインターネットをサーフィンしました。 ここに私が見つけたものがあります:



OOPの最高の伝統であるGuillermoは、 状態パターンを介してPull To Refreshを実装しました。 結果は13クラスで、プルダウンからリフレッシュまでの機能だけでなく、プルアップからリフレッシュまでの機能がありました。 理由はわかりませんが、実装はそれほど速くありませんでした。まあ、リストの端が軽快な指に追いつかなかったのです。 はい、そして操作はヘッダーの出現を引き起こすためにかなり鋭い下向きの動きを必要としました。 そして、アニメーションは観察されません...私たちはさらに行きました。

ティム・マホニーはだれもだましませんでしたが、すぐにREADMEに次のように書いています。 「現在の状況:バギー」 しかし、バージョングラフを見ました。ある種のDaniel Wangがプロジェクトを分岐させ、バグを修正しました。 取って、留めて。 使いやすさが悪い。 以前の実装で、onRefreshイベントでリストを更新してからonRefreshComplete()を呼び出すだけで十分だった場合:

 ((PullToRefreshListView) getListView()).setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { new GetDataTask().execute(); } });
      
      



 private class GetDataTask extends AsyncTask { ... @Override protected void onPostExecute(Void result) { ... ((PullToRefreshListView) getListView()).onRefreshComplete(); } }
      
      





次に、ここでヘッダーを手動で作成し、イベントの到着時にテキストを変更する必要があります。もちろん、リストを更新します。

 mRefreshHeader = new TextView(this); mRefreshHeader.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mRefreshHeader.setGravity(Gravity.CENTER); mRefreshHeader.setText("Pull to refresh..."); mContainerView = (PullRefreshContainerView) findViewById(R.id.container); mContainerView.setRefreshHeader(mRefreshHeader); mContainerView.setOnChangeStateListener(new OnChangeStateListener() { @Override public void onChangeState(PullRefreshContainerView container, int state) { switch(state) { case PullRefreshContainerView.STATE_IDLE: case PullRefreshContainerView.STATE_PULL: mRefreshHeader.setText("Pull to refresh..."); break; case PullRefreshContainerView.STATE_RELEASE: mRefreshHeader.setText("Release to refresh..."); break; case PullRefreshContainerView.STATE_LOADING: mRefreshHeader.setText("Loading..."); new GetDataTask().execute(); //  onPostExecute() - mContainerView.completeRefresh(); break; } } });
      
      





わからない、もっと柔軟かもしれないけど…不便。 さらに、この実装はPagerであまりうまく機能しないことが判明しました。リストを垂直にスクロールすると同時に、Pagerを水平に同時にスクロールすることが可能になりました。

その結果、涙を流しながら、私は松葉杖にscrollfix_for_short_list ブランチからJohanのバージョンを置き始めました。これにより、リストが無期限にロードされないようにしました。 どういうわけかそれは行われたが、それは機能し、穏やかに、不安定にした。 地平線上で、自分でコンポーネントを書くという見通しが迫っていたので、私はもう一度インターネットを再サーフィンすることにしました。 そして、見よ、私はクリス・ベインズから別の実装に出くわしました。 プロジェクトはJohanのバージョンに基づいていましたが、その後大幅に改善されました(著者が書いているように)。 テストによると、この実装にはJohanのバージョンに固有のすべてのバグがなく、より見栄えがよい(アニメーションが追加されているため)。



だから、なぜ私はここにそんなに広がっているのですか? そして、 道徳を与えるために:

プロジェクトでPull To Refreshメカニズムを使用する場合は、Chris Bainesの実装を使用します。 私の意見では、現時点ではこれがPull To Refreshの最高品質の実装です。


PS少し後に、Habréで同様の記事を見つけました。また、上記のプロジェクトを批判し、 Pull To Refreshの実装のバージョンを宣伝しました 。 しかし... ...何らかの理由で、このコンポーネントを使用しているときに、アプリケーションをクラッシュさせ始めました。リストに新しい部分をロードしようとすると、カーソルに問題が発生します。 したがって、このオプションは私には向いていません。 しかし、デモは見栄えがよく、ヨハンよりも優れています。



All Articles