这两天用到了ListView,写下遇到的一些问题。首先是ListView本身与子控件的焦点问题,比如我这里子控件用到了Button,在需要ListView中的根布局属性上加上下面的这一个属性:
android:descendantFocusability="blocksDescendants"用于屏蔽子控件抢夺ListView的焦点,也可在Button本身设置焦点属性为false。其它的一些控件的点击问题就不说了,网上有很多。
然后是需要点击Button进行网络操作,返回正确结果后设置Button的test为"XXX",我这里不需要设置其它控件状态改变了,处理方法除了下面我的方法外,也可以用selector。此外还需要保存每个item的position位置用来保存Button的状态(应该这么说:记录此Item(position)上Button的状态,因为是在getView方法里去判断Button状态来设置的,所以叫记录比较好吧),这个问题需要细心的处理,不然就会出现只点击第一个Button后,后面position的Button也被设置成了“XXX”,还有Button的设置的setClickable也会有问题。
好吧,不说了,下面是写的代码, 代码里我应该写的挺清楚的了。这里只是ListView的布局,还有Adapter的代码。要用的话自己在一个Activity的布局里加上个ListView控件,再在代码里设置listview的adapter就可以用了。
ListView的布局
android:layout_
android:layout_
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal" >
android:layout_
android:layout_
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
android:id="@+id/txt_pre_entry_class"
android:layout_
android:layout_
android:singleLine="true"
android:text="test" />
android:layout_
android:layout_
android:layout_weight="2"
android:gravity="center"
android:orientation="vertical" >
android:id="@+id/txt_pre_entry_teacher"
android:layout_
android:layout_
android:singleLine="true"
android:text="Txt1" />
android:id="@+id/txt_pre_entry_course"
android:layout_
android:layout_
android:singleLine="true"
android:text="Txt2" />
android:id="@+id/txt_pre_entry_class_name"
android:layout_
android:layout_
android:singleLine="true"
android:text="Txt3" />
android:layout_
android:layout_
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
ListView的Adapter
public class PreEntryAdapter extends BaseAdapter
{
private LayoutInflater inflater;
private Context context;
private Dialog orderDialog;
private String summitUrl;
private Handler orderHandler;
private viewHolder holder;
OrderAsyncTask orderAsyncTask;
ListlistSize, listList;
TextView txtClass, teacherName, className, courseName;
//当前的位置,这个很重要,Button的状态记录就靠它了
private int currentPosition = 0;
//这个Button用于在重网络返回数据后设置其显示的内容,如成功、失败等。
private Button currentBtn;
//这个数组参数是记录每个position上的Button的请求是否成功
private boolean[] ORDER_SUCCESS;
//这是我用来填充假数据的
private String[] classes;
/**
* 这里后面两个参数是我要填充的数据,子控件的显示内容就由listList得到
*/
public PreEntryAdapter(Context context, ListlistSize, List
listList)
{
this.cOntext= context;
this.listSize = listSize;
this.listList = listList;
ORDER_SUCCESS = new boolean[30];// int[listSize.get(0).get(0)];
classes = new String[30];
for (int i = 0; i <30; i++)
{
classes[i] = "教2-" + i;
}
initView();
}
private void initView()
{
inflater = LayoutInflater.from(context);
orderDialog = new Dialog(context);
View view = inflater.inflate(R.layout.dialog_evaluate_order_preentry, null);
orderDialog.setContentView(view);
orderDialog.setCancelable(false);
orderDialog.setTitle("提交");
}
@Override
public int getCount()
{
//这里先设有30条Item数据
return 30;// listSize.get(0).get(0);
}
@Override
public Object getItem(int position)
{
return position;
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent)
{
Log.v("log", "--->getView()-" + position);
if (cOnvertView== null)
{
holder = new viewHolder();
cOnvertView= inflater.inflate(R.layout.adapter_preentry, null);
holder.btn_order = (Button) convertView.findViewById(R.id.btn_pre_entry_order);
holder.txt_class = (TextView) convertView.findViewById(R.id.txt_pre_entry_class);
holder.txt_class_name = (TextView) convertView.findViewById(R.id.txt_pre_entry_class_name);
holder.txt_course = (TextView) convertView.findViewById(R.id.txt_pre_entry_course);
holder.txt_teacher = (TextView) convertView.findViewById(R.id.txt_pre_entry_teacher);
convertView.setTag(holder);
}
else
{
holder = (viewHolder) convertView.getTag();
}
Log.v("log", "-->getView()--ORDER_SUCCESS[" + position + "]-" + ORDER_SUCCESS[position]);
// 判断保存的position位置上的Butoon是否已预约成功
if (ORDER_SUCCESS[position])
{
holder.btn_order.setText("已预约");
// 这里不设的话返回来时还会可点击,因为向下拉时,Holder里的btn被设置成可点击了
// holder.btn_order.setEnabled(false);
holder.btn_order.setClickable(false);
}
else
{
// 这里要写上默认的显示内容,要不然后面的子控件会出现显示已预订的情况。因为不设置的话btn还是Holder中的btn,而此时holder中的btn是已经设置了已预约的
holder.btn_order.setText("未预约");
// 要设置为可点击,不然是Holder里的状态
// holder.btn_order.setEnabled(true);
holder.btn_order.setClickable(true);
// 这个也要放这里判断
holder.btn_order.setOnClickListener(new btnListener(position, holder.btn_order));
}
// 课室假数据
holder.txt_class.setText(classes[position]);
/*
* holder.txt_class.setText((CharSequence)
* listList.get(position).get(4)); //
* holder.txt_class_name.setText(listList.get(position).get()); //
* holder.txt_course.setText((CharSequence)
* listList.get(position).get(2)); //
* holder.txt_teacher.setText((CharSequence)
* listList.get(position).get(3));
*/
return convertView;
}
/**
* 要传入当前点击的Button,用于设置currentBtn为当前点击的Button,这样点击后的setText就不会错位了。
*/
class btnListener implements OnClickListener
{
private int position;
private Button Btn;
public btnListener(int position, Button currentBtn)
{
this.position = position;
this.Btn = currentBtn;
}
@Override
public void onClick(View v)
{
currentPosition = position;
currentBtn = Btn;
Toast.makeText(context, "点击第 " + (position + 1) + "个Button", 0).show();
orderAsyncTask = new OrderAsyncTask();
orderAsyncTask.execute("");
orderDialog.show();
}
}
private static class viewHolder
{
private Button btn_order;
private Button btn_temp;
private TextView txt_class, txt_teacher, txt_course, txt_class_name;
}
/**
* 异步AsyncTask
*/
private class OrderAsyncTask extends AsyncTask
{
@Override
protected void onPreExecute()
{
super.onPreExecute();
}
// 异步处理
@Override
protected Integer doInBackground(String... nullNow)
{
Log.v("log", "-->doInBackground()--params-" + nullNow[0]);
try
{
Thread.sleep(2500);
return SubmitHandler.submitOrder((String) listList.get(currentPosition).get(0), (String) listList
.get(currentPosition).get(1), (String) listList.get(currentPosition).get(5),
Edu_Survey_OrderInfo.ORDER_WEEK);
}
catch (Exception e)
{
e.printStackTrace();
Log.v("log", "-->doInBackground() ERROR!");
}
return 0;
}
@Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Integer responseCode)
{
Log.v("log", "-->responseCode-" + responseCode);
//先假设已经请求成功了
respOnseCode= 200;
switch (responseCode)
{
case 200:
ORDER_SUCCESS[currentPosition] = true;
currentBtn.setText("已预约");
// 这里不设的话在当前页面下currentBtn一直可点击,因为getView里设的话是要调用getView时才能起作用的。
// currentBtn.setEnabled(false);
currentBtn.setClickable(false);
break;
case 404:
break;
default:
break;
}
Log.v("log", "-->onPostExecute()--currentPosition-" + currentPosition);
Log.v("log", "-->onPostExecute()--ORDER_SUCCESS[" + currentPosition + "]-"
+ ORDER_SUCCESS[currentPosition]);
orderDialog.dismiss();
super.onPostExecute(responseCode);
}
}
}
效果图:
补充:
Button可以设置tag来唯一标记它,之后就可以通过listview.findViewWithTag(tag)找到了。不需要上面这么麻烦。