Re: [问题] ListView如何动态改变item的属性

楼主: givemepass (λ)   2014-10-23 00:44:21
※ 引述《bengohard (我的歌声里)》之铭言:
: 问题:我有一个ListView,我想做到按一个Button后,把此ListView里某item的属性改变,
: 请问该怎么做(不使用onItemClick)? 此ListView使用了一个SimpleAdapter.
: 我试过以下的方法无效,虽然取的到属性值,但无法改变属性值,为何?
: View view = Adapter.getView(0, ListView.getChildAt(0), ListView);
: ImageView img = (ImageView)view.findViewById(R.id.ID_Image);
: int vis = img.getVisibility(); //值正确
: img.setVisibility(View.INVISIBLE); //改变此值但无作用
: Adapter.notifyDataSetChanged();
: //再抓一次值结果还是原本的值 >"<
: View view = Adapter.getView(0, ListView.getChildAt(0), ListView);
: ImageView img = (ImageView)view.findViewById(R.id.ID_Image);
: int v = img.getVisibility();
BaseAdapter的特性就是可以重用View来节省资源,
ListView的重用结构会长这样,
http://www.b2creativedesigns.com/Tutorials/CustomListView/recycle.png
这张图可以很清楚看到 item 9 一开始在recycle pool,
当使用者手滑动, item 1被滑出去item 9就进来listview可视范围
item 1进入recycle pool, 照这个逻辑,
如果使用者继续往上滑, 那么item 2, 3...就会进入回收区,
item 9, 1, 2 ...就会出现在画面上。
这代表什么意思? 代表着就算你资料有一百笔, 一千笔,
画面呈现的也只有9个item, 这边代表着view也只生成9个,
就不会占用太多的资源。
那我怎么知道他是第几笔资料?
这个不用担心 BaseAdapter帮你处理好这件事情了。
只要你资料顺序塞好, 不管你是丢在怎样的资料结构,
不管是ArrayList, Array, HashMap...等等。
只要你资料设定好, 就可以开始使用这个有趣的设计了。
程式怎么做呢?
一开始宣告一个MyAdapter继承BaseAdapter
public class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
// TODO Auto-generated method stub
return null;
}
}
上面你会看到四个方法, 基本上只要处理两个方法
getCount跟getView即可,
剩下的两个方法暂时不会用到, 有兴趣的可以研究看看。
getCount就是跟adapter说你有几笔资料要呈现,
假设现在你有100笔资料, 塞在arraylist内,
那么我们来模拟一下
private ArrayList<Integer> mList;
public MyAdapter(){
mList = new ArrayList<Integer>();
for(int i = 0; i < 100; i++){
mList.add(i);
}
}
首先在建构子上建立一个arraylist并且塞值到这个阵列内,
@Override
public int getCount() {
// TODO Auto-generated method stub
return mList.size();
}
接着把资料结构的长度塞给getCount方法,
让listview知道你的资料有多长。
接着到重头戏getView
这个方法就是listView会不断的来存取, 是一个callback function,
而不是由你自己去存取,
在看一次这个方法 我把参数改成英文名称比较好认
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
return null;
}
第一个是我们的item到哪一个位置?
第二个是我们这个item所使用的view
第三个是我们item的parent
一开始会先把目前的view抓出来 判断他是不是被初始化过
如果有被初始化过 代表着他之前就被使用过了
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(null == view){
} else{
}
return view;
}
这样一来我们就可以把这个实体化过的view传回去给listview了。
接着如果他是空的 则对他进行初始化
要初始化之前 先取得inflate
回到建构子补上
private LayoutInflater mLayoutInflater;
public MyAdapter(Context mContext){
mLayoutInflater = LayoutInflater.from(mContext);
...
}
再回到getView
if(null == view){
view = mLayoutInflater.inflate(R.layout.listview_item, null);
} else{
...
}
那个layout就是我们item view所装的xml布局
透过LayoutInflater可以实体化成为一个view的物件
这样一来就可以使用程式做很多灵活的操作了。
那layout里面长怎样呢?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/item_text"
/>
</RelativeLayout>
因为是范例所以写得很简单 只放入一个textview
接着就要把这个textview存在holder里面
什么是holder?
就是帮我们记住item内所有元件的内容
先宣告一个类别来存放
class Holder{
TextView itemText;
}
因为我们item layout很简单 所以这样就完成一个宣告
接着回到getView
Holder holder;
if(null == view){
view = mLayoutInflater.inflate(R.layout.listview_item, null);
holder = new Holder();
holder.itemText = (TextView) view.findViewById(R.id.item_text);
view.setTag(holder);
}
由上面可以看到 当view是空的时候
就把holder new出来 然后把itemText装进去
在透过view设定tag 装进holder
那么下次view不是空的条件下 就可以直接把holder拿出来用
就完成了reuse了功效了
else{
holder = (Holder) view.getTag();
}
这个adapter基本型态已经完成,
然后把资料结构内的资料塞进每一个item
holder.itemText.setText(mList.get(position) + "");
就会出现这样的画面
http://ppt.cc/qgYw
现在要来说明怎么透过改变资料 来更新view
假设我们要改变某一列
假设是第2笔资料出现的地方背景就显示红色
那么只要在retun view;之前加入
if(position == 2){
view.setBackgroundColor(Color.RED);
}
就会出现第二列是红色的
http://ppt.cc/9HSk
但是很奇怪 你往上滑动 居然第24列也是红色的
http://ppt.cc/WD2r
这个就是reuse要注意的地方
因为listview就是把滑出去的item拿过来重用
所以那个重用的item背景还是红色的
因此每一个item一开始都要先初始化
view.setBackgroundColor(Color.WHITE);
if(position == 2){
view.setBackgroundColor(Color.RED);
}
这样就正常了
http://ppt.cc/PBHX
至于你的问题 想要让一个Button按下去 某一个值进行变化
其实很简单 只要开一个方法
public void setRowColor(int pos, int value){
mList.set(pos, value);
notifyDataSetChanged();
}
notifyDataSetChanged是用来刷新listview的画面
也就是会再去读取一圈getview
假设刚刚变化背景的判断式改成
if(mList.get(position) == 200){
view.setBackgroundColor(Color.RED);
}
外面设定一个button 按下的时候 将arraylist的值改变
那么你就会看到listview有一列变红色的
这就是用值去改变view
而不是用view去修正值
程式码
http://uploadingit.com/file/ffokgjkq0kjer5tq/TestAndroid.zip
作者: laiair (大头)   2014-10-23 01:37:00
想请问 simpleAdapter 和 baseAdapter 的差异是?
楼主: givemepass (λ)   2014-10-23 08:53:00
baseadapter比较弹性, 可操作的地方没有限制, 假设现在每列背景颜色不同, 或者复杂一点的view就挂了, 例如line的聊天室, fb的涂鸦墙
作者: laiair (大头)   2014-10-23 09:36:00
^^ 谢谢解惑
作者: JULONE780701 (亚)   2014-10-23 09:41:00
太用心!可是这程式在我的Nikia 3310跑不起来
作者: bengohard (我的歌声里)   2014-10-23 11:41:00
详细的讲解+程式码,马上修改看看,太感谢你囉!!:D
作者: zerofinal (人生~)   2014-10-24 10:07:00
推一个
作者: xisland (窄宅)   2014-10-24 11:09:00
我想每个item放不同背景图耶,最好是由程式来画,不用png档半夜12点起来试到现在还没成功
楼主: givemepass (λ)   2014-10-24 12:56:00
设条件就可以完成了, 还是你可以把程式码贴上来看看
作者: xisland (窄宅)   2014-10-24 14:20:00
OK了holder.bmp =Bitmap.createBitmap( //下略view.setImageBitmap(holder.bmp);加这二行就可以了
作者: baobomb (baobomb)   2014-10-27 16:01:00
建议还是先弄懂oo 不然这类客制化的view你都会写的很痛苦尤其是很容易不知道自己在写什么

Links booklink

Contact Us: admin [ a t ] ucptt.com