0

问题:当我清除并重新填充我的 ListView 时,如果以前检查过某个项目,那么也会检查同一索引处的项目。如果添加到适配器的元素数量 < 先前检查项目的索引,则不检查任何内容。

我已经尝试阻止使用 convertView 即使它存在但没有效果。奇怪的是,当我逐步通过调试器查看发生了什么时,我看到重新填充适配器会导致在 CheckableLinearLayout 中调用一次或多次 setChecked(true)。(我在下面包含了该堆栈跟踪)查看这些调用的调用堆栈表明它不是我编写的任何发起这些调用的代码。就好像 ListView 正在记住先前选择的索引并自行恢复它。

我的实现:我将 ListView 设置为 singleSelection 模式。我使用具有 getView(...) 的自定义 ArrayAdapter,它返回我的 CheckableListView 实现的实例:

public class CheckableLinearLayout extends LinearLayout implements Checkable {

   private boolean isChecked;

   public CheckableLinearLayout(Context context) {
      super(context);
   }

   public CheckableLinearLayout(Context context, AttributeSet attrs) {
      super(context, attrs);
   }

   @Override
   public void setChecked(boolean isChecked) {
      this.isChecked = isChecked;
      if(isChecked) {
         setBackgroundColor(Color.DKGRAY);
      } else {
         setBackgroundColor(Color.BLACK);
      }
   }

   @Override
   public boolean isChecked() {
      return isChecked;
   }

   @Override
   public void toggle() {
      setChecked(!isChecked);
   }
}

我的 ArrayAdapter 的 getView 实现:

@Override
public View getView(int pos, View convertView, ViewGroup parent) {

         LayoutInflater inf = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

         CheckableLinearLayout row = (CheckableLinearLayout) convertView;
         if (row == null) {
            row = (CheckableLinearLayout) inf.inflate(R.layout.file_explorer_item, parent, false);
         }

         // I explicitly set checked to false, in case this was a convertView:
         row.setChecked(false);

         // population various elements of the view is done here

         return row;
      }
   }

有任何想法吗?

PS。这是对 setChecked(true) 的一个神秘调用的堆栈跟踪:

<1> main@830013232224, prio=5, in group 'main', status: 'RUNNING'
      at my.package.CheckableLinearLayout.setChecked(CheckableLinearLayout.java:25)
      at android.widget.ListView.setupChild(ListView.java:1834)
      at android.widget.ListView.makeAndAddView(ListView.java:1765)
      at android.widget.ListView.fillSpecific(ListView.java:1318)
      at android.widget.ListView.layoutChildren(ListView.java:1636)
      at android.widget.AbsListView.onLayout(AbsListView.java:1863)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
      at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1617)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1401)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
      at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
      at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
      at android.view.View.layout(View.java:11278)
      at android.view.ViewGroup.layout(ViewGroup.java:4224)
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1489)
      at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
      at android.os.Handler.dispatchMessage(Handler.java:99)
      at android.os.Looper.loop(Looper.java:137)
      at android.app.ActivityThread.main(ActivityThread.java:4424)
      at java.lang.reflect.Method.invokeNative(Method.java:-1)
      at java.lang.reflect.Method.invoke(Method.java:511)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
      at dalvik.system.NativeStart.main(NativeStart.java:-1)

<10> Binder Thread #2@830019920808, prio=5, in group 'main', status: 'RUNNING'
      at dalvik.system.NativeStart.run(NativeStart.java:-1)

<9> Binder Thread #1@830019917952, prio=5, in group 'main', status: 'RUNNING'
      at dalvik.system.NativeStart.run(NativeStart.java:-1)

<8> FinalizerWatchdogDaemon@830019904352 daemon, prio=5, in group 'main', status: 'SLEEPING'
      at java.lang.VMThread.sleep(VMThread.java:-1)
      at java.lang.Thread.sleep(Thread.java:1031)
      at java.lang.Thread.sleep(Thread.java:1013)
      at java.lang.Daemons$FinalizerWatchdogDaemon.run(Daemons.java:213)
      at java.lang.Thread.run(Thread.java:856)

<7> FinalizerDaemon@830019904008 daemon, prio=5, in group 'main', status: 'WAIT'
      at java.lang.Object.wait(Object.java:-1)
      at java.lang.Object.wait(Object.java:401)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:102)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:73)
      at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:168)
      at java.lang.Thread.run(Thread.java:856)

<6> ReferenceQueueDaemon@830019903648 daemon, prio=5, in group 'main', status: 'WAIT'
      at java.lang.Object.wait(Object.java:-1)
      at java.lang.Object.wait(Object.java:364)
      at java.lang.Daemons$ReferenceQueueDaemon.run(Daemons.java:128)
      at java.lang.Thread.run(Thread.java:856)

<5> Compiler@830019903408 daemon, prio=5, in group 'system', status: 'WAIT'
      at dalvik.system.NativeStart.run(NativeStart.java:-1)

<3> Signal Catcher@830019902928 daemon, prio=5, in group 'system', status: 'WAIT'
      at dalvik.system.NativeStart.run(NativeStart.java:-1)

<2> GC@830019902704 daemon, prio=5, in group 'system', status: 'WAIT'
      at dalvik.system.NativeStart.run(NativeStart.java:-1)
4

4 回答 4

5

你可以使用这个 CheckableLinearLayout

public class CheckableLinearLayout extends LinearLayout implements Checkable {
boolean mChecked = false;

private static final int[] CHECKED_STATE_SET = {
        R.attr.state_checked
};

public CheckableLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean isChecked() {
    return mChecked;
}

@Override
public void setChecked(boolean checked) {
    if (mChecked != checked) {
        mChecked = checked;
        refreshDrawableState();
    }
}

@Override
public void toggle() {
    mChecked = !mChecked;
    refreshDrawableState();
}

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
    if (isChecked()) {
        mergeDrawableStates(drawableState, CHECKED_STATE_SET);
    }
    return drawableState;
}

@Override
public boolean performClick() {
    toggle();
    return super.performClick();
}

}

performClick 被覆盖 - 所以它会在点击时改变它的状态;如果您不需要它,请将其删除

对于背景颜色,您可以使用以下内容:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true">
        <shape android:shape="rectangle">
            <solid android:color="#e13f2e"/>
        </shape>
    </item>
    <item android:state_checked="false">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"/>
        </shape>
    </item>
</selector>
于 2012-12-07T17:18:27.963 回答
0

setChecked 将由 ListView 调用(如果有 Checkable 接口),其值来自 getCheckedItemPosition(s)(使用 ListView setItemChecked 设置)在 getView 之后。清除或更改适配器时,可能未清除内部容器。需要时取消选中该项目。

我建议也使用可绘制的状态列表。onCreateDrawableState、mergeDrawableState、refreshDrawableState、state_checked。只是谷歌。

于 2012-04-25T06:43:47.037 回答
0

这是因为每次在列表视图中移动项目时,它都会重新创建其每一行,但由于您尚未保存状态,因此在重新创建时它会删除其状态并将其设置为默认状态。我已经发布了一个相关的答案,您可以查看希望它会有所帮助。

如何实现一个获取所有复选框状态并将选中项的值添加到arraylist的按钮?

于 2012-04-25T05:20:56.957 回答
0

这是 CheckableRelativeLayout 的一个很好的实现:链接

此外,在 layout/xml 中设置 listView SINGLE_CHOICE(或多个)对我不起作用,在设置适配器后使用它

    myListView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
于 2014-10-02T18:56:30.790 回答