我正在创建一种 DataSet_Collector 应用程序,该应用程序在ListView
中向用户显示其对话线程。用户选择垃圾邮件线程。这些线程将被发送到Excel工作表。然后显示其余的线程(非垃圾邮件),用户选择他要发送的那些线程。
到目前为止,我已经使用扩展的LinkedHashMap<String, String>
(即 ListView
)显示了存储在SimpleAdapter
和ThreadsAdapter
中的线程。 Key
中的LinkedHashMap<>
是发件人,而Value
处的Key
是线程。我创建了一个名为listView_layout_item.xml
的布局,其中包含两个TextView
和一个ImageButton
。 item
中的每个ListView
在listView_layout_item.xml
中用getView()
进行膨胀,如下所示。
ThreadsAdapter.java
public class ThreadsAdapter extends SimpleAdapter {
private Context context;
/**
* Constructor
*
* @param context The context where the View associated with this SimpleAdapter is running
* @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
* Maps contain the data for each row, and should include all the entries specified in
* "from"
* @param resource Resource identifier of a view layout that defines the views for this list
* item. The layout file should include at least those named views defined in "to"
* @param from A list of column names that will be added to the Map associated with each
* item.
* @param to The views that should display column in the "from" parameter. These should all be
* TextViews. The first N views in this list are given the values of the first N columns
*/
ThreadsAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
//This 'data' is an ArrayList() of LinkedHashMap<String, String>
//first String for sender of the thread, second String for the thread
//ListView will list sender as item and thread as subitem in
//every getView() instance
this.context = context;
}
private class ViewHolder{
private ImageButton threadCheck;
private boolean isTChecked;
}
@SuppressLint("InflateParams")
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder view;
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck =(ImageButton) convertView.findViewById(R.id.threadChecker);
view.isTChecked = false; // in the start of the app.
final ViewHolder finalView = view;
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(finalView.isTChecked)
finalView.threadCheck.setImageResource(R.drawable.circle_unchecked);
else
finalView.threadCheck.setImageResource(R.drawable.circle_checked);
finalView.isTChecked = !finalView.isTChecked;
}
});
convertView.setTag(view);
} else {
view = (ViewHolder) convertView.getTag();
}
super.getView(position, convertView, parent);
return convertView;
}
}
super.getView()
在getView()
的末尾被调用,因为我想使用 Text
和 Subtext
SimpleAdapter
的{{1}}格式。
使用给定的代码
当我单击ListView
项目中的一个ImageButton
来更改其状态时,ListView
中其他项目中的其他ImageButtons
也将更改其状态。 为什么?!以及如何解决?
当我向上或向下滚动时,任何ListView
的状态都会随机变化。 为什么?!以及如何解决?
我是ImageButton
和ListView
适配器的新手。当前的答案没有意义,所以我发布了自己的特殊问题。
答案 0 :(得分:0)
在ListViews中,行(在您的情况下为ViewHolders)被回收再利用,这意味着您看到的东西在上下移动,但是相同的行又一次又一次地重复。
请记住,将任何状态存储在行中是不正确的,因为当重新使用东西时,它们将使用以前拥有的状态,乍一看似乎是随机的。
您应该做的是在数据中存储isTChecked
状态。为此,我建议您将LinkedHashMap
切换为ArrayList
并使用简单的Java对象。您可以拥有这样的课程:
public class ConversationThread {
public String sender;
public String thread;
public Boolean isChecked = false; /* Initially false, to match your scenario. */
}
您的适配器的getView
替代将变成这样:
public View getView(final int position, View convertView, ViewGroup parent) {
/* 'getItem' would bring you the data for the provided position, once you
* switch from a LinkedHashMap to an ArrayList. */
final ConversationThread conversationThread = getItem(position);
ViewHolder view;
if (convertView == null) {
/* Here, the row is created for the first time, hence why you inflate
* the XML layout. */
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.listView_layout_item, null);
view = new ViewHolder();
view.threadCheck = (ImageButton) convertView.findViewById(R.id.threadChecker);
/* You save the ViewHolder as the View's tag, to be able to reuse it. */
convertView.setTag(view);
} else {
/* Here, the row exists, so you fetch the ViewHolder to actually reuse it. */
view = (ViewHolder) convertView.getTag();
}
/* Once you have your ViewHolder, old or new, you can then update it.
* That means updating the image and using a new click listener as well. */
if (conversationThread.isChecked)
view.threadCheck.setImageResource(R.drawable.circle_checked);
else
view.threadCheck.setImageResource(R.drawable.circle_unchecked);
view.threadCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v /* This is the actual view clicked (view.threadCheck) */) {
/* On click, toggle the flag and then update the View. */
conversationThread.isChecked = !conversationThread.isChecked;
if (conversationThread.isChecked)
v.setImageResource(R.drawable.circle_checked);
else
v.setImageResource(R.drawable.circle_unchecked);
}
});
/* If you also need to call super, you can do so. */
super.getView(position, convertView, parent);
return convertView;
}
这绝不是最佳选择,我只是试图通过尽可能少地移动代码来使事情变得清晰。