Re: [分享] 利用自定的ListView動態新增/刪除列

看板AndroidDev作者 (習慣壞習慣)時間13年前 (2011/04/21 22:25), 編輯推噓3(304)
留言7則, 4人參與, 最新討論串2/2 (看更多)
※ 引述《givemepass (〆)》之銘言: : 最近,我朋友問我怎麼用自訂的ListView動態增減列, : 剛好可以分享一下, : 如果對如何自訂ListView不了解, : 可以參考一下#1DbiQ5jJ, : 將代碼貼到板上任何一個地方,就可以找到我上一篇文章:) : 那麼如何利用自訂的ListView來動態增加或刪除呢? : 我們首先利用Menu讓使用者能夠動態的增加或刪除, : 因此先在Menu裡面加入兩個選項,分別是add item及remove item, : @Override : public boolean onCreateOptionsMenu(Menu menu) { : // TODO Auto-generated method stub : menu.add(0, Menu.FIRST, 0, "add item"); : menu.add(0, Menu.FIRST+1, 0, "remove item"); : return super.onCreateOptionsMenu(menu); : } : 就會看到這樣的一個畫面, : http://uploadingit.com/file/jrlg3a2bwwykwkyo/menu1.png
: 接著我們想要按下add item的時候,讓ListView多出一列, : 在加入public boolean onOptionsItemSelected(MenuItem item) , : 當你按下menu選項的處理事件, : @Override : public boolean onOptionsItemSelected(MenuItem item) { : // TODO Auto-generated method stub : switch(item.getItemId()){ : case Menu.FIRST: : myAdapter.addItem(myAdapter.getCount()+1); this.setSelection(myAdapter.getCount()+1); //上面這行是在增加新列之後,讓ListView順便移到新列 : break; : case Menu.FIRST+1: : break; : } : return super.onOptionsItemSelected(item); : } : 這時候,切換到MyAdapter.java的頁面,新增兩個方法,分別是: : public void addItem(int position) : public void removeItem(int position) : 當按下add item的時候,就會呼叫addItem(), : 而按下remove item的時候,就會呼叫removeItem(), : 這時候我們的MyAdapter需要作一下變動, : 還記得自訂的ListView裡面的getView()嗎? : 它是用來顯示ListView所有的列,但是我們要將每一列存成一個一個的物件, : 所以需要改變一下寫法, : 首先,宣告一個ArrayList來儲存每一個列的View, : private ArrayList<View> arrayList; 不好意思,我的做法跟你有點不一樣,因為我認為arrayList存的應該是資料 所以在這個例子裡我是private ArrayList<Integer> arrayList; : 並且在建構子初始化它, : arrayList = new ArrayList<View>(); arrayList = new ArrayList<Integer>(); : 這時候就可以開始使用它了, : 再來就是在getCount()的return變成arrayList的大小, : @Override : public int getCount() { : // TODO Auto-generated method stub : return arrayList.size(); : } : 接著將getView所有的內容搬到addItem()裡面, : public void addItem(int position){ : TagView tag; : View view = adapterLayoutInflater.inflate(R.layout.adapter, null); : tag = new TagView( : (Button)view.findViewById(R.id.AdapterButton), : (ImageView)view.findViewById(R.id.AdapterImage), : (TextView)view.findViewById(R.id.AdapterText)); : view.setTag(tag); : arrayList.add(view); : tag.image.setBackgroundResource(R.drawable.icon); : tag.button.setText("button"+arrayList.size()); : tag.text.setText("text"+arrayList.size()); : this.notifyDataSetChanged(); : } 我覺得addItem要做的事是,單純增加資料、及對系統說資料更新了 public void addItem(int position){ arrayList.add(position); this.notifyDataSetChanged(); } : 比較要注意的是arrayList.add(view); : 我們每新增一列,就必須把那一列的view加入到arrayList裡面, : 最後的this.notifyDataSetChanged()是通知baseAdapter我們已經將資料更新了, : 它就會執行getCount()取得列數並且重跑一次getView(), : 在getView()這邊我們只需要改變return值即可, : @Override : public View getView(int position, View view, ViewGroup parent) { : // TODO Auto-generated method stub : return arrayList.get(position); : } 在getView這裡反而要多做點事,關於顯示的部份 @Override public View getView(int position, View view, ViewGroup parent) { // TODO Auto-generated method stub final TagView tag; if (view == null) { view = adapterLayoutInflater.inflate(R.layout.adapter, null); tag = new TagView( (Button)view.findViewById(R.id.AdapterButton), (ImageView)view.findViewById(R.id.AdapterImage), (TextView)view.findViewById(R.id.AdapterText)); view.setTag(tag); } else { tag = (TagView) view.getTag(); } tag.image.setBackgroundResource(R.drawable.icon); tag.button.setText("button"+arrayList.get(position)); tag.text.setText("text"+arrayList.get(position)); return view; } : 現在你可以跑看看程式,一開始什麼都沒有,當按下Menu->add item, : 就會跑出一列我們自訂的ListView了, : 接著我們來寫remove item部份, : 回到onOptionsItemSelected()這個函式, : 在case Menu.FIRST+1:後面加入呼叫removeitem, : case Menu.FIRST+1: : myAdapter.removeItem(myAdapter.getCount()-1); : break; : 再到MyAdapter.java裡面修改removeItem() : public void removeItem(int position){ : if(!arrayList.isEmpty()){ : arrayList.remove(position); : this.notifyDataSetChanged(); : } : } : 到這裡為止,我們就可以操作新增/刪除的功能了, : 如果成功就會出現下面的畫面, : http://uploadingit.com/file/hkqtqu1qure25r4o/menu2.png
: http://uploadingit.com/file/cfbkdtpclgebrf3e/menu3.png
: 如果沒有出現預期的結果,沒關係, : http://uploadingit.com/file/d5cr1yp8l0i1ykay/MyListView.zip : 下載這個檔案就可以看到所有的程式碼, : 其實我覺得這樣的寫法有點粗糙, : 我比較偏向SimpleAdapter那樣寫, : 可能需要在研究一下怎麼寫比較好 : 如果有錯誤或有更好的寫法 : 請務必告訴小弟,避免誤導大家,謝謝。 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.list); myAdapter = new MyAdapter(this); setListAdapter(myAdapter); //↓這是測試用的 for (int i=0;i<1000;i++){ myAdapter.addItem(myAdapter.getCount()+1); } //↑這是測試用的 } 原本的作法是每新增一列view就把view存起來 當今天新增了1000筆view,佔了記憶體約7MB(9.8MB-2.8MB 沒資料時記憶體約2.8MB) 若將arrayList改成只存資料,並且在getView重覆利用view 假設你的螢幕能顯示n列,那它就會存n+1列 佔記憶體約0.3MB(3.1MB-2.8MB),這樣做可以省下很多資源 以上是小弟的拙見,敬請指教,謝謝^^ -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 218.160.210.180 ※ 編輯: badhabit 來自: 218.160.210.180 (04/21 22:27)

04/21 22:29, , 1F
感謝你的意見 受益良多^^ 我明天再把程式做修正
04/21 22:29, 1F

04/21 22:30, , 2F
我了解你的意思 真的沒考慮到記憶體狀況差很多...^^"
04/21 22:30, 2F

04/21 23:50, , 3F
一開始也是想到memory的問題,可參考android上的
04/21 23:50, 3F

04/21 23:50, , 4F
memory leak那篇文章:)
04/21 23:50, 4F

04/22 00:49, , 5F
好厲害,使用array list也可以存有圖片的list嗎
04/22 00:49, 5F

04/22 00:50, , 6F
還是只存它的文字,然後圖片再寫方法撈出
04/22 00:50, 6F

04/22 01:42, , 7F
關於圖片的問題請參考#1Di4dTki
04/22 01:42, 7F
忘記附這篇的完整程式碼了 http://uploadmirrors.com/download/1BQAI8BW/MyListView.zip ※ 編輯: badhabit 來自: 61.231.71.160 (04/22 05:06)
文章代碼(AID): #1Di3v3sc (AndroidDev)
文章代碼(AID): #1Di3v3sc (AndroidDev)