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
)中的视图回收引起的 您遇到了以下情况:
- 您使用
ToggleButton
将一行中 ImageView
的可见性设置为不可见
- 您的行被滚动到看不见的地方,因此被回收。
- 回收视图仍然有一个
ImageView
,可见性设置为 View.INVISIBLE
- 您将新值分配给该行但不更改可见性
要解决这个问题,您应该有一个 List
、HashMap
或类似的东西,并跟踪哪些 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);
}
});
当我的 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
)中的视图回收引起的 您遇到了以下情况:
- 您使用
ToggleButton
将一行中 - 您的行被滚动到看不见的地方,因此被回收。
- 回收视图仍然有一个
ImageView
,可见性设置为View.INVISIBLE
- 您将新值分配给该行但不更改可见性
ImageView
的可见性设置为不可见
要解决这个问题,您应该有一个 List
、HashMap
或类似的东西,并跟踪哪些 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);
}
});