我正在尝试基于自定义可检查列表实现多选列表。当只需要一个列表时,这很简单,但是当你应该能够在多个列表之间切换时会变得复杂。
在我的情况下,活动顶部有许多代表类别的按钮。在它们下面有一个列表,其中包含当前所选类别中的项目。
项目列表视图基于ListAdapter
扩展BaseAdapter
:
public class ListAdapter extends BaseAdapter {
private static LayoutInflater layoutInflater = null;
private ArrayList<String> data;
public ListAdapter(Activity activity, ArrayList<String> data) {
layoutInflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.data = data;
}
public void setData(ArrayList<String> data) {
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return Long.valueOf(position);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
CheckableRelativeLayout view = (CheckableRelativeLayout) convertView;
if (view == null) {
view = (CheckableRelativeLayout) layoutInflater.inflate(
R.layout.checkable_relative_layout, null);
}
TextView number = (TextView) view.findViewById(R.id.number);
TextView name = (TextView) view.findViewById(R.id.name);
number.setText(Integer.toString(position));
name.setText(data.get(position));
return view;
}
}
每个项目的观点都是虚高的CheckableRelativeLayout
:
public class CheckableRelativeLayout extends RelativeLayout implements
Checkable {
private static final int[] CheckedStateSet = { android.R.attr.state_checked };
private boolean isChecked = false;
public CheckableRelativeLayout(Context context) {
super(context);
}
public CheckableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CheckableRelativeLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean isChecked() {
return isChecked;
}
@Override
public void setChecked(boolean checked) {
isChecked = checked;
refreshDrawableState();
}
@Override
public void toggle() {
isChecked = !isChecked;
refreshDrawableState();
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CheckedStateSet);
}
return drawableState;
}
}
UI中的选择表示在selection.xml
:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/gradient_bg_checked" android:state_checked="true"/>
<item android:drawable="@drawable/gradient_bg"/>
</selector>
主要活动如下:
public class MultipleCheckList extends Activity {
private ListView listView;
private ListAdapter adapter;
private SparseArray<ArrayList<String>> data = new SparseArray<ArrayList<String>>();
private class ButtonClickListner implements OnClickListener {
@Override
public void onClick(View buttonView) {
Integer tag = (Integer) buttonView.getTag();
adapter.setData(data.get(tag));
adapter.notifyDataSetChanged();
listView.refreshDrawableState();
// How to save user's selections?
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_multiple_check);
Button button1 = (Button) findViewById(R.id.button_1);
Button button2 = (Button) findViewById(R.id.button_2);
button1.setTag(1);
button2.setTag(2);
button1.setOnClickListener(new ButtonClickListner());
button2.setOnClickListener(new ButtonClickListner());
button1.setText("First category");
button2.setText("Second category");
ArrayList<String> data1 = new ArrayList<String>();
data1.add("John");
data1.add("Bob");
data1.add("Ted");
ArrayList<String> data2 = new ArrayList<String>();
data2.add("Summer");
data2.add("Winter");
data2.add("Spring");
data.append(1, data1);
data.append(2, data2);
adapter = new ListAdapter(this, data1);
listView = (ListView) findViewById(R.id.list);
listView.setAdapter(adapter);
listView.setItemsCanFocus(false);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
}
我的问题是,保存用户选择的最佳方式是什么?
我已尝试在ListAdapter
中为每个类别存储HashMap
个实例,并通过为setAdapter()
中的每个onClick()
调用ButtonClickListner
来重复使用该实例。它不仅似乎不起作用(选择的状态没有恢复),而且由于不必要的垃圾收集它也不是很有效。
然后我尝试使用setData()
,notifyDataSetChanged()
和refreshDrawableState()
调用(如上面的代码中所示),并将它们与一些HashMap
结合使用以进行选择存储。问题是,即使调用refreshDrawableState()
,所有选择都在类别之间共享:
我也看过Parcelable
,但这似乎只对交叉活动资源交换有用。也许单独夸大每个列表可能被视为一个很好的解决方案?那么效率又如何呢? setData()
方法可能会更经济。
感谢您的帮助。
答案 0 :(得分:0)
在ListAdapter()中,您可以存储一个存储名称的自定义类,以及是否选择了项目。
public class ListAdapter extends BaseAdapter {
private static LayoutInflater layoutInflater = null;
private ArrayList<Object E> data; // Here E will your customize Class.
...
}
答案 1 :(得分:0)
我不确定你的目标是什么。
ListAdapter的一个实例:
您同意我的上述回答以及getView
中的一个小变化,以下内容不存在任何问题:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(data.selected) {
// Make item selected.
}
}
ListAdapter的多个实例:
应该用不同的指针访问它们。
答案 2 :(得分:0)
我终于解决了我的问题。
首先,我在ListAdapter
课程中添加了新方法。特别是restoreCheckStatesIfNeeded()
:
private SparseArray<SparseBooleanArray> setsCheckStates = new SparseArray<SparseBooleanArray>();
private void restoreCheckStatesIfNeeded(ListView listView, int position) {
if (getCheckStates() == null) {
setsCheckStates.put(currentCollection, new SparseBooleanArray());
}
if (stillSwitchingCollection) {
Boolean itemLatestState = getCheckStates().get(position, false);
listView.setItemChecked(position, itemLatestState);
}
if (position == getCount() - 1) {
stillSwitchingCollection = false;
}
}
public void setCurrentCollection(int currentCollection) {
this.currentCollection = currentCollection;
stillSwitchingCollection = true;
}
public SparseBooleanArray getCheckStates() {
return setsCheckStates.get(currentCollection);
}
stillSwitchingCollection
字段表示我们是否刚刚更改了集合,其列表的项目仍在绘制中。它有助于我们判断是否需要恢复先前列表的项目检查状态。
另外,重要的是要注意我们无法在getView()
中保存列表项目的检查状态,否则会发生许多奇怪的事情(例如,某些项目甚至会被选中)如果我们没有点击它们等)。这是因为在getView()
通话后,ListView.setupChild()
中仍有一些正在进行的选择设置。
因此,更好的选择是在ButtonClickListner.onClick()
中保存检查状态:
for (int i = 0; i < listView.getChildCount(); i++) {
CheckableRelativeLayout listItem = (CheckableRelativeLayout) listView.getChildAt(i);
adapter.getCheckStates().put(i, listItem.isChecked());
}
幸运的是,这种方法解决了这个问题。