如何让android ListView项选择器使用state_checked

撕毁我的头发试图让Android ListView做我想要的。

我希望在单选模式下有一个ListView,其自定义行布局具有不同的背景颜色,用于选择,按下和检查(即选择以颜色而不是复选标记显示 – 这就是我通常所说的“选择”,但在我按下它之前选择在android中似乎是我要选择的行

我想到了尝试一个背景选择器,里面有三个状态。 它适用于state_selected和state_pressed,但不适用于state_checked。 所以我创建了一个CheckableRelativeLayout,它扩展了RelativeLayout并实现了Checkable并用于每一行的视图。

这里显示的是简化版本:

 >   

bkg_selector看起来像

        

颜色在别处定义。

这仍然无效。 所以在自定义ListAdapter中我跟踪了“已检查”行并尝试了(在getView中)

if(position == checkedPosition)ret.getBackground()。setState(CHECKED_STATE_SET);

它仍然不起作用。 我怎样才能做到我想要的呢?

您需要覆盖CheckableRelativeLayout中的onCreateDrawableState并为其设置Clickable =“true”。 我对LinearLayout的代码:

 public class CheckableLinearLayout extends LinearLayout implements Checkable { private boolean checked = false; public CheckableLinearLayout(Context context) { super(context, null); } public CheckableLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } private static final int[] CheckedStateSet = { R.attr.state_checked }; public void setChecked(boolean b) { checked = b; } public boolean isChecked() { return checked; } public void toggle() { checked = !checked; } @Override protected int[] onCreateDrawableState(int extraSpace) { final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); if (isChecked()) { mergeDrawableStates(drawableState, CheckedStateSet); } return drawableState; } @Override public boolean performClick() { toggle(); return super.performClick(); } 

更好的是,不要设置clickable = true并重写CheckableLinearLayout的performClick(),保持Pavel的建议覆盖onCreateDrawableState并用以下内容替换CheckableLinearLayout的setChecked():

 private final List mCheckableViews = new ArrayList(); @Override protected void onFinishInflate() { super.onFinishInflate(); final int childCount = getChildCount(); findCheckableChildren(this); } private void findCheckableChildren(View v) { if (v instanceof Checkable && v instanceof ViewGroup) { mCheckableViews.add((Checkable) v); } if (v instanceof ViewGroup) { final ViewGroup vg = (ViewGroup) v; final int childCount = vg.getChildCount(); for (int i = 0; i < childCount; ++i) { findCheckableChildren(vg.getChildAt(i)); } } } @Override public void setChecked(boolean checked) { mChecked = checked; for (Checkable c : mCheckableViews) { c.setChecked(checked); } refreshDrawableState(); } 

它可以避免点击和长按回调问题。

恕我直言,使用自定义适配器更容易:

 class CustomAdapter extends ArrayAdapter { Context context; public CustomAdapter(Context context, int resourceId, List items) { super(context, resourceId, items); this.context = context; } private class ViewHolder { TextView txt; View layout; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; CustomRowItem rowItem = getItem(position); LayoutInflater mInflater = (LayoutInflater) context .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); if (convertView == null) { convertView = mInflater.inflate(R.layout.сustom_list, null); holder = new ViewHolder(); holder.txt = (TextView) convertView.findViewById(R.id.сustom_list_txt); holder.layout = convertView.findViewById(R.id.сustom_list_layout); convertView.setTag(holder); } else holder = (ViewHolder) convertView.getTag(); holder.txt.setText(rowItem.getText()); if(rowItem.isChecked()) holder.layout.setBackgroundColor(-16720999); //color for checked else holder.layout.setBackgroundColor(0); //color for unchecked return convertView; } } class CustomRowItem { private boolean value; private String text; public CustomRowItem(String text, boolean value) { this.text = text; this.value = value; } public boolean isChecked() { return value; } public void setChecked(boolean checked) { value = checked; } public String getText() { return text; } void setText(String text) { this.text = text; } } 

сustom_list.xml:

 < ?xml version="1.0" encoding="utf-8"?>    

怎么用:

 public class ExampleAct extends Activity { final List list = new ArrayList(); CustomAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.example); ListView listView=(ListView)findViewById(R.id.listView); adapter = new CustomAdapter(this, R.layout.сustom_list, list); listView.setAdapter(adapter); list.add(new CustomRowItem("unchecked item",false)); list.add(new CustomRowItem("checked item",true)); adapter.notifyDataSetChanged(); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { //unchecked on click @Override public void onItemClick(AdapterView< ?> parent, View itemClicked, int index, long id) { if(list.get(index).isChecked()) { list.get(index).setChecked(false); //uncheck adapter.notifyDataSetChanged(); } else { // other actions } }); listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { //checked on long click @Override public boolean onItemLongClick(AdapterView< ?> parent, View itemClicked, int index, long id) { list.get(index).setChecked(true); //check adapter.notifyDataSetChanged(); return true; // or false for calling context menu } }); }