40

如中,ListView 的 ELEMENTS 可以是 Fragments。我知道您可以将 TextView XML 分配给 ListView 以更改其外观,但是您可以将 Fragments 添加到 ListView 中。

例如:我有一个片段。所述片段的 XML 包含一个 ImageView、几个大样式的 TextView 和一个小样式的 TextView。Fragment 类代码接收一个 Bundle,然后根据内容相应地填充 TextViews 和 ImageView。片段 XML 和片段代码都可以正常工作(我可以很好地显示单个片段)。我有一个 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 of Fragments 来保存我所有的实例化视图。然后我创建一个 Fragment,创建一个 Bundle,将数据添加到 Bundle(以便 Fragment 可以正确地将数据编组到它的视图中),将 Bundle 添加到 Fragment,最后将 Fragment 添加到 ArrayList。之后,我制作了一个 ArrayAdapter,添加了我想要使用的元素布局,以及我制作的片段列表;然后将 ListView 设置为从我的适配器中读取。

运行此代码的任何人都可能会得到 NPE @ 实例化 ArrayAdapter。是什么赋予了?这甚至可能吗?在我一直为此绞尽脑汁之前,有人能告诉我我是不是在浪费时间吗?有没有更好的办法?我一直在考虑使用 ScrollView,但是 ListView 的很多功能都需要重新实现,而且我讨厌-讨厌-讨厌在没有必要时重新发明轮子。

感谢任何阅读的人,特别是如果您决定离开他们,请特别感谢您的想法。我已经尝试过寻找一个既定的答案,但我似乎找到的只是关于在片段内部使用 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。最终,通过大量研究,我发现原因与 Fragments 的实例化方式有关。调用 Fragment 时,它需要来自其父级的上下文。由于 Dialog 的父级是启动它的 Activity,因此 Dialog 本身不符合必要的条件。我相信,在尝试将片段添加到 ListView 时,情况也是如此。由于 ListView 不符合实例化 Fragment 的协议,它会抛出 NPE,因此让我挂起并回到约定。D@mn...我真的希望我能够做到这一点。使用片段而不是简单的 XML 会使组织/搜索列表变得更加容易。哦,好吧......如果有人想知道,我猜它不能完成。

4

3 回答 3

8

我想说这是不可能的,因为将片段放入 ListView 意味着片段可以在多个容器中相乘。当您使用 FragmentManager 创建片段时,会使用标识符对其进行标记,从而可以轻松地重新加载和重新排列方向和其他配置更改。它还鼓励跨多个设备配置使用。

片段实际上是 Activity 的子集。您是否将 Activity 作为列表的一部分?绝对不是(应该是答案!)!!!

此外,在片段移入和移出视图时连续附加()和分离()片段并不是很有用(单元格被回收)。这些都是 ListView 不应该处理的昂贵操作。列表应该快速滚动。

从评论的对话中,我可以看出您希望通过在 Activity 中很好地分离视图设置代码和适配器来实现漂亮的代码。这样做:

  1. 覆盖View该类并在那里进行自定义绘图和设置。
  2. 创建一个新类,在其中提供所需的上下文和数据集,以使您返回列表需要显示的视图——这是我通常做的。
  3. 有一个 Utils 类在其他地方构建您的视频(愚蠢)。

只是不要在列表中使用片段。不是他们的目标用例。HTH。

于 2013-01-16T23:53:23.053 回答
7

事实证明,您可以创建一个ListViewlistView 中的每个项目都是一个Fragment. 诀窍是将 Fragment 包装在FrameLayout.

2014 年 9 月 16 日更新

即使可以创建一个ListViewcontains Fragments,它看起来也不是一个好主意。这似乎绝对是 Android 世界中的一个角落案例,并且有龙。对于像下面示例中的一个简单片段,一切都很好,但如果你有一个复杂的项目,其中有很多事情发生,那么这可能不是要走的路。我的新方法是将所有与 GUI 相关的代码拉入到View扩展FrameLayout中,然后将其插入到中ListView——这工作得更好,更符合 Android 的预期使用方式。如果您Fragment在代码的其他部分需要 a 的功能,您也可以简单地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);
于 2014-09-15T19:16:56.770 回答
4

您不需要使用片段。

编写一个自定义 ViewAdapter 并让它膨胀一个更复杂的布局(或者如果你需要真正花哨,可能会增加几个更复杂的布局),然后根据需要填充布局的字段。

[旁白:对于在评论中回答的人-如果您实际上是在回答问题,请使用答案而不是评论!如果只是因为你这样获得更多的声望点!]

于 2013-03-19T20:46:00.940 回答