ViewPager のコンテンツを更新できません。
FragmentPagerAdapter クラスのメソッド instanceiateItem() と getItem() の正しい使い方は何ですか?
フラグメントをインスタンス化して返すために getItem() のみを使用していました。
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
これはうまくいきました。ただし、コンテンツを変更することはできません。
そこで私はこれを見つけました:ViewPager PagerAdapter がビューを更新しない
「私のアプローチは、instantiateItem() メソッドでインスタンス化されたビューに対して setTag() メソッドを使用することです」
今、それを実行するために、instantiateItem() を実装したいと思います。しかし、何を返す必要があるのか (型は Object)、また getItem(int position) との関係は何かがわかりません。
私は読んだ参照:
パブリック抽象フラグメント getItem (int 位置)
指定された位置に関連付けられたフラグメントを返します。
パブリック オブジェクト インスタンス化アイテム (ViewGroup コンテナー、int 位置)
指定された位置のページを作成します。アダプターは、ここで指定されたコンテナーにビューを追加する責任がありますが、finishUpdate(ViewGroup) から戻るまでにこれが完了していることを確認する必要があります。パラメーター
container ページが表示されるビュー。 position インスタンス化されるページの位置。
戻り値
新しいページを表すオブジェクトを返します。これはビューである必要はなく、ページの他のコンテナーにすることもできます。
しかし、まだ理解できません。
これが私のコードです。サポート パッケージ v4 を使用しています。
ページャーテストの表示
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
マイフラグメントアダプタ
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
マイフラグメント
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
同じような問題を抱えている人がいますが、答えはありませんhttp://www.mail-archive.com/ [email protected] /msg200477.html
ベストアンサー1
FragmentPagerAdapter または FragmentStatePagerAdapter を使用する場合は、まったくgetItem()
触れずに、単独で処理するのが最適です。PagerAdapter の- -インターフェイスは、FragmentPagerAdapter がより単純なインターフェイスを実装するために使用する低レベルのインターフェイスです。instantiateItem()
instantiateItem()
destroyItem()
isViewFromObject()
getItem()
この話に入る前に、明確にしておきたいのは
表示されている実際のフラグメントを切り替える場合は、FragmentPagerAdapter を使用せず、FragmentStatePagerAdapter を使用する必要があります。
この回答の以前のバージョンでは、例として FragmentPagerAdapter を使用するという間違いがありましたが、これは機能しません。なぜなら、FragmentPagerAdapter は、フラグメントが最初に表示された後はフラグメントを破棄しないからです。
setTag()
リンク先の投稿で提供されているおよび の回避策はお勧めしませんfindViewWithTag()
。ご存知のとおり、 および の使用はsetTag()
フラグメントfindViewWithTag()
では機能しないため、適切な組み合わせではありません。
正しい解決策は、 をオーバーライドすることですgetItemPosition()
。notifyDataSetChanged()
が呼び出されると、ViewPager はgetItemPosition()
アダプタ内のすべての項目を呼び出し、それらを別の位置に移動するか削除する必要があるかどうかを確認します。
デフォルトでは、getItemPosition()
は を返しますPOSITION_UNCHANGED
。これは、「このオブジェクトはそのままで問題ありません。破棄したり削除したりしないでください」という意味です。 を返すと、POSITION_NONE
代わりに「このオブジェクトは表示しているアイテムではなくなったので、削除してください」と表示して問題を修正します。つまり、アダプタ内のすべてのアイテムを削除して再作成する効果があります。
これは完全に正当な修正です。この修正により、notifyDataSetChanged はビューのリサイクルなしで通常の Adapter のように動作します。この修正を実装してパフォーマンスが満足できるものであれば、すぐに作業を開始できます。これで完了です。
より良いパフォーマンスが必要な場合は、より洗練された実装を使用できますgetItemPosition()
。以下は、文字列のリストからフラグメントを作成するページャの例です。
ViewPager pager = /* get my ViewPager */;
// assume this actually has stuff in it
final ArrayList<String> titles = new ArrayList<String>();
FragmentManager fm = getSupportFragmentManager();
pager.setAdapter(new FragmentStatePagerAdapter(fm) {
public int getCount() {
return titles.size();
}
public Fragment getItem(int position) {
MyFragment fragment = new MyFragment();
fragment.setTitle(titles.get(position));
return fragment;
}
public int getItemPosition(Object item) {
MyFragment fragment = (MyFragment)item;
String title = fragment.getTitle();
int position = titles.indexOf(title);
if (position >= 0) {
return position;
} else {
return POSITION_NONE;
}
}
});
この実装では、新しいタイトルを表示するフラグメントのみが表示されます。リストにまだあるタイトルを表示するフラグメントは、リスト内の新しい位置に移動され、リストにまったくないタイトルを持つフラグメントは破棄されます。
フラグメントが再作成されていないが、とにかく更新する必要がある場合はどうでしょうか。 ライブフラグメントの更新は、フラグメント自体によって最も適切に処理されます。 フラグメントを持つことの利点は、フラグメントが独自のコントローラーであることです。 フラグメントは、 内の別のオブジェクトにリスナーまたはオブザーバーを追加しonCreate()
、 内でそれを削除することで、更新をフラグメント自体で管理できます。 ListView やその他の AdapterView タイプのアダプターで行うように、onDestroy()
更新コードをすべて 内に配置する必要がありません。getItem()
最後にもう 1 つ、FragmentPagerAdapter がフラグメントを破棄しないからといって、getItemPosition が FragmentPagerAdapter でまったく役に立たないというわけではありません。このコールバックを使用して、ViewPager 内のフラグメントを並べ替えることはできます。ただし、フラグメントが FragmentManager から完全に削除されることはありません。