[英]How to check/uncheck CheckedTextView (child items) items inside ExpandableListView?
My design: I have created a custom adapter( SignalsExpandableListAdapter)
with a CheckedTextView for my ExpandableListView.我的设计:我为我的 ExpandableListView 创建了一个带有 CheckedTextView 的自定义适配器( SignalsExpandableListAdapter)
。
public class SignalsExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> listDataHandler;
private HashMap<String,List<String>> listHashMap;
public SignalsExpandableListAdapter(Context context, List<String> listDataHandler, HashMap<String, List<String>> listHashMap) {
this.context = context;
this.listDataHandler = listDataHandler;
this.listHashMap = listHashMap;
}
Then data is filled inside a fragment with HashMap and List as below.然后将数据填充到带有 HashMap 和 List 的片段中,如下所示。 This works well.这很好用。 I can see children and parent elements inside my ExpandableListView.我可以在我的 ExpandableListView 中看到子元素和父元素。
ArrayList<List<String[]>> deviceMList = new ArrayList<>();
final List<String[]> mList = new ArrayList<>();
deviceMList.add(mList);
What I'm looking for I: When I select any child (can be multiple) I want to indicate that selection with a tick using CheckedTextView.我在找什么我:当我 select 任何孩子(可以是多个)时,我想使用 CheckedTextView 用勾号表示该选择。 And also I want to uncheck when I select any checked child item.而且我想在我 select 任何检查的子项目时取消选中。 (A simple check/uncheck design ). (一个简单的检查/取消检查设计)。 As well when any child is selected another function is called for plotting. As well when any child is selected another function is called for plotting. This is where I got stuck.这就是我卡住的地方。 Every time when I select one child, random multiple children checkedTextViews are also indicated as checked not only the one I select.每次我 select 一个孩子时,随机多个孩子的checkTextViews 也显示为checked 不仅我select 一个。
After some searching I tried 3 attempts to overcome this and to check only the child I select.经过一番搜索,我尝试了 3 次尝试来克服这个问题,并只检查孩子 I select。 But it seems like neither of my attempts is working.但似乎我的任何尝试都没有奏效。 I'm not sure what is going on.我不确定发生了什么。 My attempts are mentioned below.我的尝试如下所述。 I would really appreciate any suggestions on this.我真的很感激对此的任何建议。
I tried Attempt 4 (Described below in section II.) but still seems like check/unchecks is not happening in real-time.我尝试了尝试 4(在下面的第 II 节中描述),但似乎仍然没有实时进行检查/取消检查。
Attempt 1: Trying to make checked true inside Fragment尝试 1:尝试在 Fragment 中使检查为真
listAdapter = new SignalsExpandableListAdapter(context,signalsListDataHeader,signalsListHash);
signalsExpandableListView.setAdapter(listAdapter);
signalsExpandableListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
//tickCheckboxes();
signalsExpandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
CheckedTextView sensorCheckedView = (CheckedTextView) v.findViewById(R.id.sensorsCheckedTextView);
if(!mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))) {
sensorCheckedView.setChecked(true);
try {
if(Plot==null) {
Log.e(LOG_TAG, "Plot is null!");
}
mService.mPlotManager.addSignal(deviceMList.get(groupPosition).get(childPosition), Plot);
} catch (Exception e) {
Log.e(LOG_TAG, "Error! + e);
e.printStackTrace();
}
} else {
mService.mPlotManager.removeSignal(deviceMList.get(groupPosition).get(childPosition));
//signalsExpandableListView.setItemChecked(childPosition,false);
sensorCheckedView.setChecked(false);
}
return true;
}
});
Attempt 2: Creating a different function and call it inside Fragment.尝试 2:创建一个不同的 function 并在 Fragment 中调用它。 Created function is as below and function calling is commented above Attempt 1.创建的 function 如下, function 调用在尝试 1 上方注释。
//loop through groups and then children
public void tickCheckboxes() {
//CheckedTextView sensorCheckedView = (CheckedTextView) signalsExpandableListView.findViewById(R.id.sensorsCheckedTextView);
for (int i = 0; i < deviceMList.size(); i++) {
for (int j = 0; j < deviceMList.get(i).size(); j++) {
if (mService.mPlotManager.ifPropertyExist(deviceMList.get(i).get(j))) {
signalsExpandableListView.setItemChecked(j, true);
//sensorCheckedView.setChecked(true);
} else {
signalsExpandableListView.setItemChecked(j, false);
//sensorCheckedView.setChecked(false);
}
}
}
}
Attempt 3: Accessing child element with ExpandableListView Adapter.尝试 3:使用 ExpandableListView 适配器访问子元素。 I updated the getChildView()
method as below.我更新了getChildView()
方法,如下所示。
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup parent) {
final String childText = (String) getChild(groupPosition,childPosition);
if(view == null){
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.sensors_list_items,null);
}
CheckedTextView txtListChild = (CheckedTextView) view.findViewById((R.id.sensorsCheckedTextView));
txtListChild.setText(childText);
txtListChild.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (txtListChild.isChecked()) {
txtListChild.setChecked(false);
} else {
txtListChild.setChecked(true);
}
}
});
return view;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
List Items xml:列表项目 xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckedTextView
android:id="@+id/sensorsCheckedTextView"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
android:textColor="@color/black"
android:paddingTop="5dp"
android:paddingBottom="5dp"/>
</LinearLayout>
Group xml: xml 组:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/deviceNameTextView"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:text="Device Name"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:background="@color/colorAccent"
android:textColor="@color/colorPrimary"
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"/>
</LinearLayout>
What I'm looking for II: For check/uncheck I modified Adapter as in Attempt 4 with the help of the answer mentioned below.我在寻找什么 II:对于检查/取消检查,我在下面提到的答案的帮助下修改了适配器,如尝试 4 中所述。 I cannot see the checked
mark in real-time.我无法实时看到checked
的标记。 When I click a child then I want to scroll up/down to visually see the checkmark.当我单击一个孩子时,我想向上/向下滚动以直观地看到复选标记。 Same as with the uncheck.与取消选中相同。 It is strange.它很奇怪。 It seems like a kind of "refreshing" is required to see the check/uncheck state in real-time.似乎需要一种“刷新”才能实时查看选中/取消选中 state。 I would appreciate any suggestions on how to get rid of this.我将不胜感激有关如何摆脱这种情况的任何建议。
Thank you.谢谢你。
Attempt 4: Modified adapter.尝试 4:修改适配器。 This works for a check/uncheck but can not visually see it in real-time.这适用于选中/取消选中,但无法实时直观地看到它。
public class SignalsExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> listDataHandler;
private HashMap<String,List<String>> listHashMap;
private MService mService;
private ArrayList<List<String[]>> deviceMList ;
public SignalsExpandableListAdapter(Context context, List<String> listDataHandler, HashMap<String, List<String>> listHashMap,mService service, ArrayList<List<String[]>> dMList ) {
this.context = context;
this.listDataHandler = listDataHandler;
this.listHashMap = listHashMap;
this.mService = service;
this.deviceMList =dMList;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup parent) {
final String childText = (String) getChild(groupPosition,childPosition);
if(view == null){
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.sensors_list_items,null);
}
CheckedTextView txtListChild = (CheckedTextView) view.findViewById((R.id.sensorsCheckedTextView));
txtListChild.setText(childText);
if(mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))) {
txtListChild.setChecked(true);
} else {
txtListChild.setChecked(false);
}
return view;
}
I assume that your mService with a class named PlottingService, then try following changes to the adapter:我假设您的mService带有一个名为 PlottingService 的 class,然后尝试对适配器进行以下更改:
public class SignalsExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> listDataHandler;
private HashMap<String,List<String>> listHashMap;
private PlottingService mService;
public SignalsExpandableListAdapter(Context context, List<String> listDataHandler, HashMap<String, List<String>> listHashMap, PlottingService ps) {
this.context = context;
this.listDataHandler = listDataHandler;
this.listHashMap = listHashMap;
this.mService = ps;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup parent) {
final String childText = (String) getChild(groupPosition,childPosition);
if(view == null){
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.sensors_list_items,null);
}
CheckedTextView txtListChild = (CheckedTextView) view.findViewById((R.id.sensorsCheckedTextView));
txtListChild.setText(childText);
// Always set check state according to data.
if(mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))) {
txtListChild.setChecked(true);
} else {
txtListChild.setChecked(false);
}
return view;
}
Inside Fragment, do Attempt 1, only change: listAdapter = new SignalsExpandableListAdapter(context,signalsListDataHeader,signalsListHash);
在 Fragment 内部,尝试 1,只更改: listAdapter = new SignalsExpandableListAdapter(context,signalsListDataHeader,signalsListHash);
to listAdapter = new SignalsExpandableListAdapter(context,signalsListDataHeader,signalsListHash, mService);
to listAdapter = new SignalsExpandableListAdapter(context,signalsListDataHeader,signalsListHash, mService);
Hope that helps!希望有帮助!
Updated:- In Fragment, comment out the OnChildClickListener and in the adapter, use the following getChildView:更新:-在 Fragment 中,注释掉 OnChildClickListener 并在适配器中,使用以下 getChildView:
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View view, ViewGroup parent) {
String childText = (String) getChild(groupPosition,childPosition);
if(view == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.sensors_list_items,null);
}
CheckedTextView txtListChild = (CheckedTextView) view.findViewById((R.id.sensorsCheckedTextView));
txtListChild.setText(childText);
// Always set check state according to data.
if(mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))) {
txtListChild.setChecked(true);
} else {
txtListChild.setChecked(false);
}
txtListChild.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CheckedTextView sensorCheckedView = (CheckedTextView)v;
if(!sensorCheckedView.isChecked()) {
sensorCheckedView.setChecked(true);
try {
if(Plot==null) {
Log.e(LOG_TAG, "Plot is null!");
}
mService.mPlotManager.addSignal(deviceMList.get(groupPosition).get(childPosition), Plot);
} catch (Exception e) {
Log.e(LOG_TAG, "Error!" + e);
e.printStackTrace();
}
} else {
mService.mPlotManager.removeSignal(deviceMList.get(groupPosition).get(childPosition));
sensorCheckedView.setChecked(false);
}
}
});
return view;
}
Updated 2:- In Fragment, comment out the OnChildClickListener and in the adapter, add a inner class and use the following getChildView:更新 2:-在 Fragment 中,注释掉 OnChildClickListener 并在适配器中,添加一个内部 class 并使用以下 getChildView:
class Position {
int group, child;
Position(int group, int child) {
this.group = group;
this.child = child;
}
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup parent) {
String childText = (String) getChild(groupPosition,childPosition);
if(view == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.sensors_list_items,null);
}
CheckedTextView txtListChild = (CheckedTextView) view.findViewById((R.id.sensorsCheckedTextView));
txtListChild.setText(childText);
// Always set check state according to data.
if(mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))) {
txtListChild.setChecked(true);
} else {
txtListChild.setChecked(false);
}
txtListChild.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CheckedTextView sensorCheckedView = (CheckedTextView)v;
int groupPosition = ((Position)v.getTag()).group;
int childPosition = ((Position)v.getTag()).child;
if(!sensorCheckedView.isChecked()) {
sensorCheckedView.setChecked(true);
try {
if(Plot==null) {
Log.e(LOG_TAG, "Plot is null!");
}
mService.mPlotManager.addSignal(deviceMList.get(groupPosition).get(childPosition), Plot);
} catch (Exception e) {
Log.e(LOG_TAG, "Error!" + e);
e.printStackTrace();
}
} else {
mService.mPlotManager.removeSignal(deviceMList.get(groupPosition).get(childPosition));
sensorCheckedView.setChecked(false);
}
}
});
txtListChild.setTag(new Position(groupPosition, childPosition));
return view;
}
If Updated 2 still have the issue of multiple checked items, then the possible cause is mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))
.如果Updated 2仍然存在多个checked item的问题,那么可能的原因是mService.mPlotManager.ifPropertyExist(deviceMList.get(groupPosition).get(childPosition))
。 Instead of using mService to verify if an item is selected or not, it may be a better idea to change listHashMap from HashMap<String, List<String>>
to HashMap<String, List<ChildItem>>
[The accepted answer in Values of counter changes after scrolling ExpendableListView , you need a boolean field instead of the integer field, quantity].与其使用mService来验证是否选择了某个项目,不如将listHashMap从HashMap<String, List<String>>
更改为HashMap<String, List<ChildItem>>
[The accepted answer in Values of滚动 ExpendableListView 后计数器发生变化,您需要一个 boolean 字段而不是 integer 字段,数量]。 Then when a child item is clicked, check and update with the list.然后,当单击子项时,检查并更新列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.