web-dev-qa-db-ja.com

リストビューにフラグメントを含めることはできますか

同様に、ListViewのELEMENTSをフラグメントにすることができます。 TextView XMLをListViewに割り当てて外観を変更できることは知っていますが、フラグメントをListViewに追加できます。

例えば、私にはフラグメントがあります。このフラグメントのXMLには、ImageView、いくつかの大きなスタイルのTextView、および小さなスタイルのTextViewが含まれています。 FragmentクラスのコードはBundleを受け取り、その内容に基づいてTextViewsとImageViewを適宜設定します。 Fragment XMLとFragmentコードの両方が問題なく機能します(個々のFragmentを問題なく表示できます)。前述のFragmentsのリストを表示したいFragmentActivityがあります。以下は、FragmentActivityのビュー内でListViewを作成するために使用しているコードです。

    ArrayList<Fragment> fragList = new ArrayList<Fragment>();
    Fragment fragment = Fragment.instantiate(this, TileItem.class.getName());
    Bundle bundle = new Bundle();
    bundle.putInt("key", 0);
    fragment.setArguments(bundle);
    fragList.add(fragment);

    ArrayAdapter<Fragment> adapter = new ArrayAdapter<Fragment>(this, R.layout.tile_item, fragList);
    listItems.setAdapter(adapter);

これについての私の考え方は次のとおりです。インスタンス化されたすべてのビューを保持するために、フラグメントのArrayListを作成します。次に、Fragmentを作成し、Bundleを作成し、Bundleにデータを追加して(Fragmentがデータをビューに正しくマーシャリングできるように)、BundleをFragmentに追加し、最後にFragmentをArrayListに追加します。その後、ArrayAdapterを作成し、使用する要素レイアウトと作成したフラグメントのリストを追加します。次に、アダプターから読み取るようにListViewを設定します。

このコードを実行しているユーザーは、おそらくArrayAdapterをインスタンス化するNPEを取得します。何が得られますか?これも可能ですか?これに頭を悩ませ続ける前に、誰かが私が自分の時間を無駄にしているのかどうか教えてもらえますか?もっと良い方法はありますか?私はScrollViewを使用することを考えていましたが、ListViewの機能の多くは再実装する必要があり、必要でないときにホイールを再発明することは大嫌いです。

読んでくれている人に感謝します。特にあなたがそれらを残すことに決めた場合、あなたの考えをありがとう。私はこれに対する確立された答えを探してみましたが、見つけることができるのは、フラグメント内のリストビューの使用に関する質問/ウェブページだけです。 ListViewの要素としてフラグメントを使用しない

編集:私は以下の提案を受け入れ、さらに調査を開始しました。物事の表示方法から、XMLから構築するだけでなく、プロセスを説明するより良い方法がないため、フラグメントを膨らませるカスタムアダプタを使用できるはずですが、現在の実装では、設定しようとするとNPEがスローされますアダプター。

これは私のカスタムアダプタコードです(簡潔にするために短縮されています)。

public class AdapterItem extends ArrayAdapter<Fragment> {

Context c;
List<Fragment> f;

public AdapterItem(Context c, List<Fragment> f) {
    super(c, R.layout.tile_item, f);
    this.c = c;
    this.f = f;
}

@Override
public View getView(int pos, View v, ViewGroup vg) {
    LayoutInflater i = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    return i.inflate(R.layout.tile_item, vg, false);
}

}

そして、ここに私がそれを実装する方法があります:

ArrayList<Fragment> fragList = new ArrayList<Fragment>();
    Fragment fragment = Fragment.instantiate(this, TileItem.class.getName());
    Bundle bundle = new Bundle();
    bundle.putInt("key", 0);
    fragment.setArguments(bundle);
    fragList.add(fragment);

    AdapterItem adapter = new AdapterItem(this, fragList);
    adapter.add(fragment);
    listItems.setAdapter(adapter);

それで数日経ちましたが、このスレッドは埋もれていると確信しています。しかし、誰かがこれを試してみたいと思って、グーグル検索でそれらをここに持ってきた場合のために、最後の更新を追加すると思いました。したがって、私の実装では、ListViewにアダプターが与えられたときにNPEを取得しています。それが間違いなくアダプターであり、エラーをスローするListViewではないことを理解するのにロケット外科医はかかりません。私の人生のために、私は理由を理解することはできません...

とにかく、私はいくつかのアイデアを持っていると思います。まず、少しバックストーリー:しばらく前に、FragmentDialog内でFragmentTransactionsを作成しようとしていました。私がそうしようとするたびに、私はNPEを取得します。最終的に、多くの研究を通じて、私はその理由がフラグメントのインスタンス化方法に関係していることを発見しました。フラグメントが呼び出されると、そのフラグメントのコンテキストが必要になります。ダイアログの親はそれを開始したアクティビティであるため、ダイアログ自体は必要な基準を満たしていませんでした。 ListViewにフラグメントを追加しようとすると、これも当てはまると思います。 ListViewはFragmentをインスタンス化することで合意に達していないため、NPEをスローし、その結果、私はぶら下がり、慣例に戻ります。 D @ mn ...私はこれができると本当に望んでいた。単純なXMLの代わりにフラグメントを使用すると、リスト全体の整理/検索が非常に簡単になります。まあ...誰かが不思議に思っている場合、それはできないと思います。

38
user1449018

フラグメントをListViewに入れると、フラグメントを複数のコンテナに掛けることができるため、これは不可能だと思います。 FragmentManagerを使用してフラグメントを作成すると、フラグメントが識別子でタグ付けされるため、向きやその他の構成の変更を簡単に再ロードおよび再配置できます。また、複数のデバイス構成での使用を推奨します。

フラグメントは、実際にはアクティビティのサブセットです。リストの一部としてアクティビティがありますか?間違いありません(答えになるはずです!)!!!

さらに、フラグメントがビューの内外に移動するときにセルを連続的にattach()およびdetach()することはあまり役に立ちません(セルはリサイクルされます)。これらはすべて、ListViewが処理すべきではない高価な操作です。リストはすばやくスクロールするはずです。

コメントに関する会話から、アクティビティ内のビューセットアップコードとアダプターを適切に分離して、ニースコードを達成したいことがわかります。次のいずれかで行います:

  1. Viewクラスをオーバーライドし、そこでカスタム描画とセットアップを行います。
  2. 新しいクラスを作成します。このクラスでは、リストに表示する必要のあるビューに戻るために必要なコンテキストとデータセットを提供します。これは私が通常行うことです。
  3. 他の場所(愚かな)でビデオを作成するUtilsクラスを用意します。

リストでフラグメントを使用しないでください。彼らが目指しているユースケースではありません。 HTH。

8
dineth

ListViewの各アイテムがListViewであるFragmentを作成できることがわかりました。トリックは、フラグメントをFrameLayoutでラップすることです。

2014年9月16日更新

ListViewを含むFragmentsを作成することはpossibleですが、良いアイデアのようには見えません。これは間違いなくAndroidワールドとドラゴンがいるケースのコーナーケースのようです。以下の例のような単純なフラグメントでは、すべてがうまく動作しますが、私の新しいアプローチは、GUI関連のすべてのコードをViewを拡張するFrameLayoutにプルし、それをに挿入することです。 ListView-これはかなり良く機能し、Androidの使用が期待されます。他の部分でFragmentの機能が必要な場合は、コードのこのViewも使用できます。

元の答えに戻る...

新しいManyFragmentsサンプルを AnDevCon 14 Fragmentsサンプルアプリ に追加しました。試してみたい場合。基本的に、それはBaseAdapterになります。これは、私の例では次のようになります。

    BaseAdapter adapter = new BaseAdapter() {
        @Override public int getCount() { return 10000; }
        @Override public Object getItem(int i) { return new Integer(i); }
        @Override public long getItemId(int i) { return i; }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {

            if (view!=null){
                ManyListItemFragment fragment = (ManyListItemFragment) view.getTag();
                fragment.setCount(i);
            } else {
                FrameLayout layout = new FrameLayout(getActivity());
                layout.setLayoutParams(frameLayoutParams);
                int id = generateViewId();
                layout.setId(id);
                ManyListItemFragment fragment = new ManyListItemFragment();
                fragment.setCount(i);
                getChildFragmentManager()
                        .beginTransaction()
                        .replace(id,fragment)
                        .commit();
                view = layout;
                view.setTag(fragment);
            }

            return view;
        }
    };

気になる場合は、generateViewId()を参照してください。

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static int generateViewId() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        for (;;) {
            final int result = sNextGeneratedId.get();
            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
            if (sNextGeneratedId.compareAndSet(result, newValue)) {
                return result;
            }
        }
    } else {
        return View.generateViewId();
    }
}
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
7
JohnnyLambada

フラグメントを使用する必要はありません。

カスタムViewAdapterを作成し、より複雑なレイアウト(または、本当に凝ったものにする必要がある場合は、いくつかのより複雑なレイアウト)を膨らませ、必要に応じてレイアウトのフィールドに入力します。

[脇に:コメントで答えた人に-実際に質問に答えている場合は、コメントではなく答えを使用してください!より多くの評判ポイントを獲得するという理由だけで!]

4
Dale Wilson