2012-07-06 61 views
36

如同在ListView中的ELEMENTS可以是碎片。我知道你可以将一个TextView XML分配给一个ListView来改变它的外观,但是你可以将Fragments添加到一个ListView中。ListView是否可以包含碎片

例如:我有一个片段。该Fragment的XML包含一个ImageView,一对大型文本视图和一个小型文本视图。 Fragment类代码接收一个Bundle,然后根据内容填充TextViews和ImageView。 Fragment XML和Fragment代码都可以正常工作 (我可以单独显示一个单独的Fragment)。我有一个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可以正确地将数据封装到其Views中),将Bundle添加到Fragment中,最后将该Fragment添加到ArrayList中。之后,我制作了一个ArrayAdapter,添加了我想要使用的元素布局以及我制作的碎片列表;然后设置ListView从我的适配器读取。

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

感谢任何人阅读,特别是感谢你的想法,如果你决定离开他们。我试过寻找一个既定的答案,但我似乎找到的是有关使用片段的Lis​​tView INSIDE的问题/网页;不使用片段作为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被赋予适配器时,我得到了一个N​​PE。它并不需要火箭医生弄清楚它确实是适配器,而不是ListView抛出错误。对于我的生活,我不知道为什么,但...

无论如何,我认为我有一些想法,但。首先,一个小故事:一段时间后,我试图在FragmentDialog中创建FragmentTransactions。每次我试图这样做,我都会得到一个NPE。最后,通过大量研究,我发现原因与碎片实例相关。当一个片段被调用时,它需要它的父对象的上下文。由于对话框的父母是启动它的活动,因此对话框本身不符合必要的标准。我相信,当试图将碎片添加到ListView时,情况也是如此。由于ListView不符合实例化片段的协议,它会抛出NPE,从而让我挂起并回到惯例。 D @ mn ......我真的希望我能够做到这一点。使用Fragments而不是简单的XML将使组织/搜索整个列表变得更容易。哦,好吧......猜猜这不可能在任何人想知道的情况下完成。

+2

为什么你连*想*片段是“ListView的元素”?开发人员多年来一直在创建'ListView',而不必将其元素变成碎片。你期望通过使它们成为碎片而获得什么? – CommonsWare 2012-07-06 13:45:25

+1

那么,我希望能够展示不仅仅是一个简单的TextView里面的列表(实际上,我将能够显示图像,以及一些额外的文本行)。此外,我将能够重复使用来自不同活动的片段代码,而无需复制代码。我还看到了比仅仅是简单的TextView更动态的项目滚动列表(就像Google Play中的列表一样,它们比TextView更复杂)。这是如何实现的?使用Fragment会不会有相同的效果(更容易)? – user1449018 2012-07-06 13:51:32

+3

您可以使用自定义适配器和从XML充填的视图来处理您的行。 – 2012-07-06 13:58:22

回答

8

我说这是不可能做到的将片段在ListView将意味着片段可以跨多个容器相乘。当您使用FragmentManager创建一个片段时,它会用一个标识符进行标记,使得重新加载和重新排列方向和其他配置更改变得很简单。它还鼓励在多个设备配置中使用。

片段实际上是活动的一个子集。你会有一个活动作为列表的一部分吗?绝对不是(应该是答案!)!!!

此外,它不是非常有用的连续连接()和分离()的片段,因为它们在移动和移出视野(细胞得到回收)。这些都是ListView不应该处理的昂贵操作。列表应该快速滚动。

从上注释的谈话中,我可以看到你想达到好的代码的视图设置代码和适配器在活动的良好分离。无论使用哪种这样做:

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

只是不要在列表中使用的片段。不是他们正在瞄准的用例。 HTH。

3

你不需要使用片段。

编写自定义ViewAdapter并使其膨胀更复杂的布局(或者几个复杂的布局,如果你需要得到真正看中的),那么布局的领域需要填充。

[旁白:到谁在评论回答人 - 请使用回答,而不是评论,如果你实际上是回答这个问题!如果只是因为你获得更多的信誉点!]

+0

PS:如果您试图在另一个布局中重用部分布局,请看一下元素 – 2013-03-19 20:49:50

7

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

UPDATE 2014年9月16日

即使是可能创建包含Fragments一个ListView,它看起来并不像它是一个好主意。这似乎绝对是Android世界的一个角落案例,并有龙。对于像下面这个例子那样简单的片段,一切都很好,但是如果你有一个复杂的项目,那么这可能不是一个好的方法。我的新方法是将所有与GUI相关的代码放入一个View,它扩展了FrameLayout,并将其插入到ListView中 - 这种方法运行得更好,更符合Android预期的使用方式。如果您需要在代码的其他部分使用Fragment的功能,那么您也可以简单地在此处使用此新的View

回到原来的答案...

,如果你想尝试一下,我添加了一个新的ManyFragments例如我AnDevCon 14 Fragments example app。本质上,它归结在了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); 
+0

您能指导我如何为每个列表创建不同的布局项目 – Shadow 2017-05-20 14:29:20

相关问题