Android 带有切换按钮的 ListView

Android ListView with toggle button

当我的 ListView 有更多的元素可以出现在屏幕上时,我遇到了问题;换句话说,当它滚动时。问题是,当我单击其中一个切换按钮时,它会更改 ImageView 的可见性。然而,当我点击它时,它改变了比各自点击的更多的可见性。

我正在使用适配器来显示列表项目。

我添加了下面的代码:

public class CriteriosAdapter extends ArrayAdapter<Criterio> {

private Context context;

public CriteriosAdapter(Context context, List<Criterio> objects) {
    super(context, 0, objects);
    this.context = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final Criterio criterio = getItem(position);
    final CriterioViewHolder viewHolder;

    if (convertView == null) {
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.fragment_row, parent, false);

        viewHolder = new CriterioViewHolder();
        viewHolder.txtCriterio = (TextView)convertView.findViewById(R.id.txtCriterio);
        viewHolder.tgIrregular = (ToggleButton)convertView.findViewById(R.id.tgIrregular);
        viewHolder.btnCam = (ImageView) convertView.findViewById(R.id.btnCam);

        convertView.setTag(viewHolder);
    }
    else {
        viewHolder = (CriterioViewHolder)convertView.getTag();
    }

    viewHolder.txtCriterio.setText(criterio.nome);
    viewHolder.txtCriterio.setTextColor(context.getColor(R.color.white));
    viewHolder.tgIrregular.setChecked(false);

    viewHolder.tgIrregular.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (viewHolder.tgIrregular.isChecked()) {
                viewHolder.btnCam.setVisibility(View.VISIBLE);
            } else {
                viewHolder.btnCam.setVisibility(View.INVISIBLE);
            }
        }
    });

    viewHolder.btnCam.setOnClickListener(new View.OnClickListener() {
        public void onClick(View arg0) {
            FragmentActivity activity = (FragmentActivity)(context);
            android.support.v4.app.FragmentManager fm = activity.getSupportFragmentManager();
            FotosFragment alertDialog = new FotosFragment();
            alertDialog.show(fm, "fragment_alert");
        }
    });

    return convertView;
}

class CriterioViewHolder {

    TextView txtCriterio;
    ToggleButton tgIrregular;

    ImageView btnCam;

}

}

有人可以帮我吗?

谢谢。

编辑

我按照您的描述添加了所有内容。但是,我在 5 个片段中使用该适配器,如果我转到另一个片段,然后返回或滚动列表,它仍然会丢失值。

我用的是criterio.getHash,因为它对所有人来说都是独一无二的。还有位置,可以在其他fragment中重复,搞得怪怪的。

public class CriteriosAdapter extends ArrayAdapter<Criterio> {

private Context context;
public static Map<String, Criterio> irregularidades = new HashMap<String, Criterio>();
HashMap<String, Boolean> toggleButtonStateTracker = new HashMap<>();

public CriteriosAdapter(Context context, List<Criterio> objects) {
    super(context, 0, objects);
    this.context = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final Criterio criterio = getItem(position);
    final CriterioViewHolder viewHolder;

    if (!toggleButtonStateTracker.containsKey(criterio.getHash())){
        toggleButtonStateTracker.put(criterio.getHash(),false);
    }

    Log.e("Toggle Track:", toggleButtonStateTracker.toString());

    if (convertView == null) {
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.fragment_row, parent, false);

        viewHolder = new CriterioViewHolder();
        viewHolder.txtCriterio = (TextView)convertView.findViewById(R.id.txtCriterio);
        viewHolder.tgIrregular = (ToggleButton)convertView.findViewById(R.id.tgIrregular);
        viewHolder.btnCam = (ImageView) convertView.findViewById(R.id.btnCam);

        convertView.setTag(viewHolder);
    }
    else {
        viewHolder = (CriterioViewHolder)convertView.getTag();
    }

    viewHolder.txtCriterio.setText(criterio.nome);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        viewHolder.txtCriterio.setTextColor(context.getColor(R.color.white));
    } else {
        viewHolder.txtCriterio.setTextColor(context.getResources().getColor(R.color.white));
    }

    viewHolder.tgIrregular.setId(criterio.id);

    final boolean isChecked = toggleButtonStateTracker.get(criterio.getHash());
    viewHolder.tgIrregular.setChecked(isChecked);

    viewHolder.btnCam.setTag(criterio.hash);

    if (isChecked) {
        viewHolder.btnCam.setVisibility(View.VISIBLE);
    } else {
        viewHolder.btnCam.setVisibility(View.INVISIBLE);
    }

    viewHolder.tgIrregular.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            toggleButtonStateTracker.put(criterio.getHash(), isChecked);
            if (isChecked) {
                viewHolder.btnCam.setVisibility(View.VISIBLE);
                irregularidades.put(criterio.getHash(), criterio);
            } else {
                viewHolder.btnCam.setVisibility(View.INVISIBLE);
                irregularidades.remove(criterio.getHash());
            }
        }
    });

    viewHolder.btnCam.setOnClickListener(new View.OnClickListener() {
        public void onClick(View arg0) {
            FragmentActivity activity = (FragmentActivity) (context);
            android.support.v4.app.FragmentManager fm = activity.getSupportFragmentManager();
            FotosFragment alertDialog = new FotosFragment();

            Bundle args = new Bundle();
            args.putString("criterioTag", criterio.getHash());
            alertDialog.setArguments(args);

            alertDialog.setCancelable(false);
            alertDialog.show(fm, "fragment_alert");
        }
    });

    return convertView;
}

class CriterioViewHolder {

    TextView txtCriterio;
    ToggleButton tgIrregular;
    ImageView btnCam;

}

}

您的问题是由于 ListView(和 RecyclerView)中的视图回收引起的 您遇到了以下情况:

  1. 您使用 ToggleButton
  2. 将一行中 ImageView 的可见性设置为不可见
  3. 您的行被滚动到看不见的地方,因此被回收。
  4. 回收视图仍然有一个 ImageView,可见性设置为 View.INVISIBLE
  5. 您将新值分配给该行但不更改可见性

要解决这个问题,您应该有一个 ListHashMap 或类似的东西,并跟踪哪些 ToggleButton 被选中,哪些 ImageView 可见。 (你可以用位置来做到这一点)

然后在您的 public View getView(int position, View convertView, ViewGroup parent) 方法中检查此位置的(行)图像是否应该可见,并相应地使用 viewHolder.btnCam.setVisibility()ToggleButton 进行设置。

编辑

将此成员变量添加到您的适配器
HashMap<Integer,Boolean> toggleButtonStateTracker = new HashMap<>;

在你的 getView 添加这个

if (! toggleButtonStateTracker.containsKey(position)){
  // Now the HashMap definitely contains the key
  toggleButtonStateTracker.put(position,false);
}

boolean isChecked = toggleButtonStateTracker.get(position);
viewHolder.tgIrregular.setChecked(isChecked);
if (isChecked){
  // if your toggle Button is checked, the btnCam should be invisible 
  viewHolder.btnCam.setVisibility(View.INVISIBLE);
} else {
  viewHolder.btnCam.setVisibility(View.VISIBLE);
}

最后添加这个 tgIrregular

viewHolder.tgIrregular.setOnCheckedChangedListener(new CompoundButton.OnCheckedChangeListener() {
  @Override
  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    toggleButtonStateTracker.put(getAdapterPosition, isChecked);
  }
});