Android ListView 可以包含片段吗

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11363309/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:10:44  来源:igfitidea点击:

Can a ListView contain Fragments

androidlistviewandroid-arrayadapterfragment

提问by user1449018

As in, can the ELEMENTS of a ListView be Fragments. I know that you can assign a TextView XML to a ListView to change the way it looks, but can you add Fragments into a ListView.

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

For instance: I have a Fragment. The XML for said Fragment contains an ImageView, a couple of large-style TextViews, and a small-style TextView. The Fragment class code receives a Bundle, then based on the contents populates the TextViews and ImageView accordingly. Both the Fragment XML and the Fragment code work without issue (I can display an individual Fragment just fine). I have a FragmentActivity in which I want to display the aforementioned list of Fragments. Here is the code I'm using to try to populate the ListView inside of the FragmentActivity's View:

例如:我有一个片段。所述片段的 XML 包含一个 ImageView、几个大样式的 TextView 和一个小样式的 TextView。Fragment 类代码接收一个 Bundle,然后根据内容相应地填充 TextViews 和 ImageView。Fragment XML 和 Fragment 代码都可以正常工作(我可以很好地显示单个 Fragment)。我有一个 FragmentActivity,我想在其中显示上述 Fragment 列表。这是我用来尝试在 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);

Here's my mode of thinking on this. I make an ArrayList of Fragments to hold all of my instantiated Views. I then create a Fragment, create a Bundle, add data to the Bundle (so that the Fragment can marshal data into it's Views correctly), add the Bundle to the Fragment, then finally add the Fragment to the ArrayList. After that, I make an ArrayAdapter, add the element layout I want to use, and the list of Fragments I've made; then set the ListView to read from my adapter.

这是我对此的思考方式。我创建了一个 Fragment ArrayList 来保存我所有的实例化视图。然后我创建一个 Fragment,创建一个 Bundle,将数据添加到 Bundle(这样 Fragment 可以将数据正确编组到它的 Views 中),将 Bundle 添加到 Fragment,最后将 Fragment 添加到 ArrayList。之后,我制作了一个 ArrayAdapter,添加了我想要使用的元素布局,以及我制作的 Fragment 列表;然后将 ListView 设置为从我的适配器读取。

Anyone running this code will likely get the NPE @ instantiating the ArrayAdapter. What gives? Is this even possible? Before I keep racking my brain on this can someone tell me if I'm just wasting my time? Is there a better way? I've been thinking of using a ScrollView, but so much of the functionality of a ListView would need to re-implemented and I hate-hate-hate reinventing the wheel when it's not necessary.

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

Thanks to anyone reading, and especially thank you for your thoughts if you decide to leave them. I've tried searching around for an established answer to this but all I seem to find are questions/web pages concerning using a ListView INSIDE of a Fragment; not using Fragments AS THE ELEMENTS of a ListView

感谢所有阅读的人,尤其感谢您决定离开他们的想法。我试过四处寻找一个既定的答案,但我似乎找到的只是关于使用片段的 ListView INSIDE 的问题/网页;不使用片段作为 ListView 的元素

Edit: I took the suggestions below and started investigating more. From the way things appear I should be able to use a custom adapter that inflates fragments instead of just flat out building from XML (for lack of a better way to describe the process) However, my current implementation is throwing an NPE when trying to set the adapter.

编辑:我接受了以下建议并开始进行更多调查。从事情出现的方式来看,我应该能够使用一个自定义适配器来扩展片段,而不仅仅是从 XML 构建(因为缺乏更好的方法来描述这个过程)但是,我当前的实现在尝试设置时抛出了一个 NPE适配器。

Here is my custom adapter code (shortened for brevity):

这是我的自定义适配器代码(为简洁起见缩短):

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);
}

}

}

and here is how I'm implementing it:

这是我如何实施它:

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);

So it's been a few days and I'm pretty sure this thread has been buried. However, I thought I would add one last update just in case someone wants to try this and a google search brings them here. So in my implementation I'm getting an NPE when the ListView is given the adapter. It doesn't take a rocket surgeon to figure out that it's certainly the adapter and not the ListView throwing the error. For the life of me I can't figure out why though...

所以已经过了几天,我很确定这个线程已经被埋没了。但是,我想我会添加最后一个更新,以防万一有人想尝试这个并且谷歌搜索将他们带到这里。所以在我的实现中,当 ListView 被赋予适配器时,我得到了一个 NPE。不需要火箭外科医生就可以确定是适配器而不是 ListView 引发了错误。对于我的生活,我无法弄清楚为什么......

At any rate, I think I have some idea though. First, a little back story: A while back I was trying to make FragmentTransactions inside of a FragmentDialog. Everytime I attempted to do so, I would get an NPE. Eventually, through much research, I discovered that the reason pertained to the way that Fragments are instanced. When a Fragment is called it needs the context from it's parent. Since a Dialog's parent is the Activity that started it, the Dialog itself didn't meet the criteria necessary. I believe, that when attempting to add fragments to a ListView, this is also the case. Since the ListView doesn't meet the agreement with instancing a Fragment it throws the NPE and thus, leaves me hanging and going back to conventions. [email protected] had really hoped I would be able to do this. Using Fragments instead of simple XML would have made it so much easier to organize/search through the list. Oh well... guess it can't be done in case anyone is wondering.

无论如何,我想我有一些想法。首先,有一个小故事:前阵子我试图在 FragmentDialog 中创建 FragmentTransactions。每次我尝试这样做时,我都会得到一个 NPE。最终,通过大量研究,我发现原因与 Fragments 的实例化方式有关。当一个 Fragment 被调用时,它需要来自它的父级的上下文。由于 Dialog 的父级是启动它的 Activity,因此 Dialog 本身不符合必要的标准。我相信,当尝试将片段添加到 ListView 时,情况也是如此。由于 ListView 不符合实例化 Fragment 的协议,它会抛出 NPE,因此,让我悬而未决并回到约定。D@mn...我真的希望我能做到这一点。使用 Fragments 而不是简单的 XML 会使组织/搜索列表变得更加容易。哦,好吧......我猜这是不可能的,以防万一有人想知道。

回答by dineth

I'd say this is not possible to do as putting a fragment in a ListView would mean the fragment can be multiplied across multiple containers. When you use the FragmentManager to create a fragment, it is tagged with an identifier, making it simple to reload and rearrange on orientation and other configuration changes. It also encourages uses across multiple device configs.

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

A Fragment is really a subset of an Activity. Would you ever have an Activity as part of a list? Definitely not (should be the answer!)!!!

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

Moreover, it is not very useful to attach() and detach() a fragment continuously as they move in and out of view (cells get recycled). These are all expensive operations that a ListView shouldn't deal with. Lists should scroll quickly.

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

From the conversation on the comments, I can see you want to achieve nice code with a good separation of view setup code and adapter in the Activity. Do so with either:

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

  1. Override the Viewclass and do your custom drawing and setup there.
  2. Create a new class, in which you supply a context and data set required for it to get you back the view a list needs to show - this is what I usually do.
  3. Have a Utils class to build your video elsewhere (silly).
  1. 覆盖View该类并在那里进行自定义绘图和设置。
  2. 创建一个新类,在其中提供所需的上下文和数据集,以使您返回列表需要显示的视图 - 这就是我通常所做的。
  3. 有一个 Utils 类来在别处构建你的视频(愚蠢)。

Just don't use Fragments in Lists. Not the use case they are aiming for. HTH.

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

回答by JohnnyLambada

It turns out that you can create a ListViewwhere each item in the listView is a Fragment. The trick is wrapping the Fragment in a FrameLayout.

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

UPDATE 9/16/2014

更新 9/16/2014

Even though it is possibleto create a ListViewthat contain Fragments, it doesn't look like it's a good idea. This seems to definitely be a corner case in the Android world and there be dragons. For a simple fragment like the one in the example below everything works beautifully, but if you have a complex project with a lot going on in it then this is probably not the way to go. My new approach is to pull all of the GUI related code into a Viewthat extends FrameLayout, and insert that into a the ListView-- this works MUCH BETTER and is more in line with how Android expects to be used. If you need the functionality of a Fragmentin other parts of your code, you can simply use this new Viewthere too.

尽管可以创建一个ListView包含Fragments,但它看起来并不是一个好主意。这似乎绝对是 Android 世界中的一个角落案例,并且有龙。对于像下面示例中的一个简单片段,一切都很好,但是如果您有一个复杂的项目,其中有很多事情要做,那么这可能不是要走的路。我的新方法是将所有与 GUI 相关的代码拉到一个View扩展中FrameLayout,然后将其插入到ListView- 这工作得更好,并且更符合 Android 的预期使用方式。如果您Fragment在代码的其他部分需要 a 的功能,您也可以简单地View在那里使用这个新功能。

Back to the original answer...

回到原来的答案...

I've added a new ManyFragmentsexample to my AnDevCon 14 Fragments example appif you want to try it out. Essentially it comes down the the BaseAdapter, which in my example looks like this:

如果您想尝试一下,我已经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;
        }
    };

In case you're curious here's generateViewId():

如果您对这里的 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);

回答by Dale Wilson

You don't need to use Fragments.

您不需要使用片段。

Write a custom ViewAdapter and have it inflate a more complex layout (or maybe several more complex layouts if you need to get really fancy) then populate the fields of the layout as necessary.

编写一个自定义的 ViewAdapter 并让它膨胀一个更复杂的布局(或者,如果你真的需要一些更复杂的布局),然后根据需要填充布局的字段。

[Aside: to the people who answered in comments -- please use answers rather than comments if you are actually answering the question! If only because you get more reputation points that way!]

[旁白:对于在评论中回答的人——如果你真的在回答问题,请使用答案而不是评论!如果只是因为您通过这种方式获得更多声望点就好了!]