2012-07-06 138 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

相關問題