第一个问题:
今天做listView困惑了好久,开始一直是不能点击,只能显示,发现:
convertView = LayoutInflater.from(context).inflate(R.layout.setting_net1, null);
原来我setting_net1用了ScrollLayout,肯定是不行的了,所以用LinearLayout。
第二个问题:
ListView的Item能被选中的基础是它能获取Focus,也就是说我们可以通过将ListView中Item中包含的所有控件的focusable属性设置为false,这样的话ListView的Item自动获得了Focus的权限,也就可以被选中了,也就会响应onItemClickListener中的onItemClick()方法
解决办法就是将Button的Focus设置为非默认获取
方法一:将ListView的Item Layout的子控件focusable属性设置为false
方法二:对Item Layout的根控件android:descendantFocusability="blocksDescendant"
方法三:在实现ListView的Adapter的getView方法时,将button.setFocusable(false);
第三个问题:
第三个问题是我认为最麻烦的,这里我一点点的分析。单击item中的选项时候,只有最后一个item响应。如下面所列:
有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。效果如下:
代码为:
public class setNetAdapter extends BaseAdapter { private Context context; private List<setNet> Messages; //关联数据 private boolean btn_Flag = false; public setNetAdapter(Context context, List<setNet> messages) { super(); this.context = context; this.Messages = messages; } @Override public int getCount() { return Messages.size(); } @Override public Object getItem(int position) { return Messages.get(position); } @Override public long getItemId(int position) { return position; } private ViewHolder holder; @Override public View getView(int position, View convertView, ViewGroup parent) { holder = null; setNet message = Messages.get(position); if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(R.layout.setting_net1, null); holder.id = (TextView) convertView.findViewById(R.id.set_net1_id); holder.catorgy = (TextView) convertView.findViewById(R.id.set_net1_txt); holder.name = (EditText) convertView.findViewById(R.id.set_net1_et1); holder.ip = (EditText) convertView.findViewById(R.id.set_net1_et2); holder.btn = (ImageView) convertView.findViewById(R.id.set_net1_imgBtn1); convertView.setTag(holder); }else{ holder = (ViewHolder)convertView.getTag(); } holder.id.setText(message.getId()+""); holder.catorgy.setText(message.getCatorgy().toString()); holder.name.setText(message.getName().toString()); holder.ip.setText(message.getIp().toString()); holder.btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(btn_Flag == true){ holder.name.setEnabled(false); holder.ip.setEnabled(false); if("".equalsIgnoreCase(holder.name.getText().toString()) || holder.ip.length()<11){ Toast.makeText(context, "输入有误,请重新输入", Toast.LENGTH_SHORT).show(); }else{ holder.btn.setImageDrawable(context.getResources().getDrawable(R.drawable.btn2)); //数据更新到数据库 btn_Flag = false; } }else{ holder.btn.setImageDrawable(context.getResources().getDrawable(R.drawable.btn3)); btn_Flag = true; } } }); return convertView; } static class ViewHolder { TextView id; TextView catorgy; EditText name; EditText ip; ImageView btn; } }
系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的vlist2.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。在实际的运行过程中会发现listView的每一行没有焦点了,这是因为Button或ImageView抢夺了listView的焦点,只要布局文件中将Button或ImageView设置为没有焦点就OK了。
问题出来了,为什么每次单击button的时候,只有最后一个item的ImageView去响应这个时间,也只有最后一个Item变化。有点小麻烦,只能仔细分析了。
if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(R.layout.setting_net1, null); holder.id = (TextView) convertView.findViewById(R.id.set_net1_id); holder.catorgy = (TextView) convertView.findViewById(R.id.set_net1_txt); holder.name = (EditText) convertView.findViewById(R.id.set_net1_et1); holder.ip = (EditText) convertView.findViewById(R.id.set_net1_et2); holder.btn = (ImageView) convertView.findViewById(R.id.set_net1_imgBtn1); convertView.setTag(holder); }else{ holder = (ViewHolder)convertView.getTag(); }
看这里,每次我们的holder都是更新的,完后我们采用了:
holder.btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(btn_Flag == true){
holder.name.setEnabled(false);
holder.ip.setEnabled(false);
if("".equalsIgnoreCase(holder.name.getText().toString()) ||
holder.ip.length()<11){
Toast.makeText(context, "输入有误,请重新输入", Toast.LENGTH_SHORT).show();
}else{
holder.btn.setImageDrawable(context.getResources().getDrawable(R.drawable.btn2));
//数据更新到数据库
btn_Flag = false;
}
}else{
holder.btn.setImageDrawable(context.getResources().getDrawable(R.drawable.btn3));
btn_Flag = true;
}
}
});
这里可以看出虽然每个ImageView都在监听,也会做出响应,但是holder停留在了最后一个Item对象中,响应的当然只是最后一个Item了。
这里我需要做出修改:public void onClick(View v)这里的View对应ImageView和你单击的还是对应的,需要设置flag。这里我做出的修改:
private List<ViewHolder> holders = new ArrayList<ViewHolder>();
private ViewHolder holder;
@Override //获取要展示的项目View对象
public View getView(int position, View convertView, ViewGroup parent) {
holder = null;
setNet message = Messages.get(position);
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.setting_net1, null);
holder.id = (TextView) convertView.findViewById(R.id.set_net1_id);
holder.catorgy = (TextView) convertView.findViewById(R.id.set_net1_txt);
holder.name = (EditText) convertView.findViewById(R.id.set_net1_et1);
holder.ip = (EditText) convertView.findViewById(R.id.set_net1_et2);
holder.btn = (ImageView) convertView.findViewById(R.id.set_net1_imgBtn1);
holder.btn.setTag(position+"");
holders.add(holder);
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
holder.id.setText(message.getId()+"");
holder.catorgy.setText(message.getCatorgy().toString());
holder.name.setText(message.getName().toString());
holder.ip.setText(message.getIp().toString());
holder.btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("adapter", v.getTag().toString());
int index = Integer.parseInt(v.getTag().toString());
holder = holders.get(index);
if(btn_Flag == true){
holder.name.setEnabled(false);
holder.ip.setEnabled(false);
if("".equalsIgnoreCase(holder.name.getText().toString()) ||
holder.ip.length()<11){
Toast.makeText(context, "输入有误,请重新输入", Toast.LENGTH_SHORT).show();
}else{
holder.btn.setImageDrawable(context.getResources().getDrawable(R.drawable.btn2));
//数据更新到数据库
btn_Flag = false;
}
}else{
holder.btn.setImageDrawable(context.getResources().getDrawable(R.drawable.btn3));
btn_Flag = true;
}
}
});
return convertView;
}
这里使用private List<ViewHolder> holders = new ArrayList<ViewHolder>();这样每次根据public void onClick(View v)中v.getTag来寻找单击的Item,选出对应的holders对应的holder,这里在做出响应即可。