作者badhabit (习惯坏习惯)
看板AndroidDev
标题Re: [分享] 利用自定的ListView动态新增/删除列
时间Thu Apr 21 22:25:02 2011
※ 引述《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)
1F:推 givemepass:感谢你的意见 受益良多^^ 我明天再把程式做修正 04/21 22:29
2F:→ givemepass:我了解你的意思 真的没考虑到记忆体状况差很多...^^" 04/21 22:30
3F:推 tomap41017:一开始也是想到memory的问题,可参考android上的 04/21 23:50
4F:→ tomap41017:memory leak那篇文章:) 04/21 23:50
5F:推 sorrel20567:好厉害,使用array list也可以存有图片的list吗 04/22 00:49
6F:→ sorrel20567:还是只存它的文字,然後图片再写方法捞出 04/22 00:50
7F:→ badhabit:关於图片的问题请参考#1Di4dTki 04/22 01:42
忘记附这篇的完整程式码了
http://uploadmirrors.com/download/1BQAI8BW/MyListView.zip
※ 编辑: badhabit 来自: 61.231.71.160 (04/22 05:06)