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

MrP*_*eak 22 android listview

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

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

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

这里显示的是简化版本:

<my.package.CheckableRelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="@drawable/bkg_selector">  
  >

     <ImageView android:id="@+id/animage"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
     />
 </my.package.CheckableRelativeLayout>
Run Code Online (Sandbox Code Playgroud)

bkg_selector看起来像

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/purple" />
    <item android:state_checked="true" android:drawable="@drawable/red" />
    <item android:state_selected="true" android:drawable="@drawable/darkpurple" />
    <item android:drawable="@drawable/black" />
</selector>
Run Code Online (Sandbox Code Playgroud)

颜色在别处定义.

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

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

它仍然不起作用.我怎样才能让它做我想做的事情?

Pav*_*shy 44

您需要覆盖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();
}
Run Code Online (Sandbox Code Playgroud)

  • 更好的是,不是设置clickable = true并重写CheckableLinearLayout的performClick(),而是覆盖它:@Override public void setChecked(boolean checked){mChecked = checked; for(Checkable c:mCheckableViews){c.setChecked(checked); } refreshDrawableState(); } (2认同)
  • @ pavel-bakshy:你忘了在`setChecked`和`toggle`中调用`refreshDrawableState`. (2认同)

Flá*_*ria 10

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

private final List<Checkable> mCheckableViews = new ArrayList<Checkable>();

@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();
    }
Run Code Online (Sandbox Code Playgroud)

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