在ExpandableListView孩子不由自主地重叠导致的复选框在不同的组检查 [英] Overlap of children in ExpandableListView involuntarily causes checkboxes to check in separate groups

查看:899
本文介绍了在ExpandableListView孩子不由自主地重叠导致的复选框在不同的组检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是抽屉式导航与ExpandableListView包含进去。该ExpandableListView具有与旁边有每个孩子的复选框儿童群体。当某些检查,检查,扩大集团下面一个折叠组内的检查检查为好。

I am using a Navigation Drawer with an ExpandableListView contained inside. The ExpandableListView has groups with children that have checkboxes next to each child. When certain checks are checked, the checks within a collapsed group below the expanded group are checked as well.

有人能解释的为什么的这种情况正在发生,什么可能的解决方法(ES)有我的情况?

Can someone explain why this is happening, and what potential fix(es) there is for my situation?

我将提供的图片和我的code,以更好地解释这个问题。

I'll provide images and my code to better explain this issue.

下面是我的团体。

Here are my groups.

这里是'分配'扩展(无任何选择)。

And here is 'Assignments' expanded (without anything chosen).

这里是已归档扩展(不带任何选择)。

And here is 'Archived' expanded (without anything chosen).

所以,现在我检查主题4'下'分配'...

So, now that I check 'Subject 4' under 'Assignments'...

身不由己,逾期倒塌存档内被选为好。

Involuntarily, 'Overdue' inside of collapsed 'Archived' was chosen as well.

同样的,当我自愿检查已完成下的已归档......

Likewise, when I voluntarily check 'Completed' under 'Archived'...

科目三是不由自主地选择内崩溃分配为好。

'Subject 3' is chosen involuntarily inside collapsed 'Assignments' as well.

这是我的code:

    <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout2"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_commentary_behind_nav"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|top"
            android:text="Swipe from left, and eventually this \nframe will hold fragments that change depending on which checkboxes are selected" />
    </FrameLayout>
    <!-- The navigation drawer -->
        <ExpandableListView
            android:id="@+id/left_drawer2"
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="@color/white"
            android:choiceMode="multipleChoice"
            android:dividerHeight="0dp"
            />

</android.support.v4.widget.DrawerLayout>

这是我的源:

 public class MainNavigationActivity extends ActionBarActivity implements OnChildClickListener {

private DrawerLayout drawer;
private ExpandableListView drawerList;
private CheckBox checkBox;
private ActionBarDrawerToggle actionBarDrawerToggle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_drawer_layout_test);

    setGroupData();
    setChildGroupData();

    initDrawer();
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.drawer_layout_test, menu);
    return true;
}

private void initDrawer() {
    drawer = (DrawerLayout) findViewById(R.id.drawer_layout2);
    drawerList = (ExpandableListView) findViewById(R.id.left_drawer2);
    drawerList.setAdapter(new NewAdapter(this, groupItem, childItem));
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
        drawerList.setIndicatorBounds(310, 350);
    } else {
        drawerList.setIndicatorBoundsRelative(310, 350);
    }


    drawerList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v,
                                    int groupPosition, long id){
            Fragment fragment;
            FragmentManager fragmentManager;
            Bundle args;
            switch (groupPosition) {
                case 0:
                    fragment = new AssignmentManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(AssignmentManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_LONG).show();
                    break;

                case 1:
                    fragment = new AssignmentManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(AssignmentManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_LONG).show();
                    break;

                case 2:
                    fragment = new SubjectManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(SubjectManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_SHORT).show();
                    drawer.closeDrawer(drawerList);
                    break;

                // for now, just SubjectManager, but soon they will lead to Settings then H/Feedback
                case 3:
                    fragment = new SubjectManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(SubjectManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_LONG).show();
                    break;

                case 4:
                    fragment = new SubjectManagerFragment();
                    fragmentManager = getFragmentManager();
                    args = new Bundle();
                    args.putString(SubjectManagerFragment.ARG_PARAM1, "" + groupPosition);
                    fragment.setArguments(args);
                    fragmentManager.beginTransaction().replace(R.id.content_frame2, fragment).commit();
                    if (drawerList.isGroupExpanded(groupPosition)) {
                        drawerList.collapseGroup(groupPosition);
                    } else {
                        drawerList.expandGroup(groupPosition, false);
                    }
                    Toast.makeText(getBaseContext(), "Clicked On grooop: " + v.getTag() + "|" + groupPosition,
                            Toast.LENGTH_LONG).show();
                    break;
            }
            return true;
        }

    });

    drawerList.setOnChildClickListener(this);


    actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, R.string.drawer_open,
            R.string.drawer_close) {
        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);
            getSupportActionBar().setTitle("open");
            invalidateOptionsMenu();
        }

         // Called when a drawer has settled in a completely open state.

        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);
            getSupportActionBar().setTitle("close");
            invalidateOptionsMenu();
        }
    };

    drawer.setDrawerListener(actionBarDrawerToggle);
    actionBarDrawerToggle.setDrawerIndicatorEnabled(true);
    actionBarDrawerToggle.syncState();

}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    // Sync the toggle state after onRestoreInstanceState has occurred.
    actionBarDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    actionBarDrawerToggle.onConfigurationChanged(newConfig);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Pass the event to ActionBarDrawerToggle, if it returns
    // true, then it has handled the app icon touch event
    if (actionBarDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle your other action bar items...

    return super.onOptionsItemSelected(item);
}

public void setGroupData() {
    groupItem.add("Assignments");
    groupItem.add("Archived");
    groupItem.add("Subjects");
    groupItem.add("Settings");
    groupItem.add("Help / Feedback");

}

ArrayList<String> groupItem = new ArrayList<String>();
ArrayList<Object> childItem = new ArrayList<Object>();

public void setChildGroupData() {
    /**
     * Add Data For Assignments
     */
    ArrayList<String> child = new ArrayList<String>();

    ArrayList<SubjectInfo> sial = new ArrayList<SubjectInfo>();
    List<SubjectInfo> sil = SubjectInfo.listAll(SubjectInfo.class);
    sial.addAll(sil);
    for (int go = 0; go < sial.size(); go++) {
        child.add(sial.get(go).subjectName);
    }
    childItem.add(child);

    /**
     * Add Data For Archived
     */
    child = new ArrayList<String>();
    child.add("Archived");
    child.add("Completed");
    child.add("Overdue");
    childItem.add(child);

    /**
     * Add empty children for Subjects, Settings, and H/Feedback
     */
    child = new ArrayList<String>();
    childItem.add(child);
    childItem.add(child);
    childItem.add(child);
}

@Override
public boolean onChildClick(ExpandableListView parent, View v,
                            int groupPosition, int childPosition, long id) {
    Toast.makeText(this, "Clicked On Child: " + v.getTag() + childPosition + "|" + groupPosition,
            Toast.LENGTH_SHORT).show();
    checkBox = (CheckBox) v.findViewById(R.id.show_child_subject_checkBox);
    checkBox.setChecked(!checkBox.isChecked());
    //Update SugarRecord value for SubjectInfo
    SubjectInfo si = SubjectInfo.findById(SubjectInfo.class, (long) (childPosition+1));
    si.subjectChecked = checkBox.isChecked();
    si.save();
    return true;
}
}

下面是我的适配器:

@SuppressWarnings("unchecked")
public class NewAdapter extends BaseExpandableListAdapter {
public ArrayList<String> groupItem, tempChild;
public ArrayList<Object> Childtem = new ArrayList<Object>();
public LayoutInflater minflater;
public Activity activity;
private final Context context;

public NewAdapter(Context context,ArrayList<String> grList, ArrayList<Object> childItem) {
    this.context = context;
    groupItem = grList;
    this.Childtem = childItem;
}

public void setInflater(LayoutInflater mInflater, Activity act) {
    this.minflater = mInflater;
    activity = act;
}

@Override
public Object getChild(int groupPosition, int childPosition) {
    return null;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return 0;
}

@Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
    tempChild = (ArrayList<String>) Childtem.get(groupPosition);
    TextView text = null;

    if (convertView == null)
    {   LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.drawer_submenu_item,parent,false);
    }
    text = (TextView) convertView.findViewById(R.id.submenu_textView);
    text.setText(tempChild.get(childPosition));

    convertView.setTag(tempChild.get(childPosition));
    return convertView;
}


@Override
public int getChildrenCount(int groupPosition) {
    switch (groupPosition) {
        case 0:
            //Expands with the size of the cereal array
            return ((ArrayList<String>) Childtem.get(groupPosition)).size();
        case 1:
            //Expands with the size of the Archived Cereal Array
            return ((ArrayList<String>) Childtem.get(groupPosition)).size();
        default:
            //List does not expand
            return 0;
    }
}

@Override
public Object getGroup(int groupPosition) {
    return null;
}

@Override
public int getGroupCount() {
    return groupItem.size();
}

@Override
public void onGroupCollapsed(int groupPosition) {
    super.onGroupCollapsed(groupPosition);
}

@Override
public void onGroupExpanded(int groupPosition) {
    super.onGroupExpanded(groupPosition);
}

@Override
public long getGroupId(int groupPosition) {
    return 0;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
    if (convertView == null)
    {
        LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.drawer_group_item,parent,false);

    }

    ((TextView) convertView).setText(groupItem.get(groupPosition));
    convertView.setTag(groupItem.get(groupPosition));

    return convertView;
}

@Override
public boolean hasStableIds() {
    return false;
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true; //was false, and was why toast wasn't presenting. Now that True, it does.
}

}

和我SubjectInfo code(包括布尔选中):

And my SubjectInfo code (including boolean checked):

public class SubjectInfo extends SugarRecord<SubjectInfo> {

public String subjectName;
public int subjectGrade;
public boolean subjectArchived;
public boolean subjectChecked;

// still deciding on whether subjects can be archived or not... if they can then all assignments
// should be archived with them (and can be restored the same way an assignment can.)
// otherwise, deleting a subject would mean (deleting/archiving all assignments) > (user option)

public SubjectInfo () {}

public SubjectInfo (String name, int grade, boolean isArchived, boolean isChecked) {
    subjectName = name;
    subjectGrade = grade;
    subjectArchived = isArchived;
    subjectChecked = isChecked;
}

}

和这里分别是我对drawer_group_item和drawer_submenu_item布局:

And here are my layouts for drawer_group_item and drawer_submenu_item, respectively:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:background="@color/white"
android:text="hello, fix?"
android:minHeight="?android:attr/listPreferredItemHeightLarge"
/>

子...

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<TextView
    android:id="@+id/submenu_textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:gravity="center_vertical"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:paddingLeft="32dp"
    android:paddingRight="16dp"
    android:textAppearance="?android:attr/textAppearanceListItemSmall" />

<CheckBox
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/show_child_subject_checkBox"
    android:checked="false"
    android:paddingRight="20dp"
    android:layout_centerVertical="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:focusable="false"/>

推荐答案

编辑:

现在,我可以看到你的code,马上我注意到三个主要问题:

Now that I can see your code, right off I notice three major problems:


  • 您没有设置复选框在初始状态getChildView()。现在来设置复选框正常,你需要访问 SubjectInfo ,其中的复选框值存储。但是,您的适配器甚至没有进入 SubjectInfo 对象!你剥离名称关闭并发送的到适配器。你可以创建另一个的ArrayList 布尔为复选框,但为什么复制?你已经在 SubjectInfo 中的数据,只是让这些物体插入适配器,使您可以使用自己的数据来创建子视图。

  • You don't set the initial state of the checkbox in getChildView(). Now to set that checkbox properly you need access to the SubjectInfo where the checkbox value is stored. However, your adapter doesn't even have access to the SubjectInfo object! You stripped the name off and sent that to the adapter. You could create another ArrayList of booleans for the checkboxes, but why duplicate? You already have the data in SubjectInfo, just get those objects into the adapter so you can use their data to create the child views.

onChildClick()不考虑孩子是哪一组。所以,如果用户归档下的孩子点击,这甚至没有 SubjectInfo ,你正在服用的子指数,找到自己的 SubjectInfo 。换句话说,你的 onChildClick()被对待每一个孩子,如果它是一个主题的孩子。你需要检查 groupPosition 的值,以确保用户点击一个主题的孩子。

Your onChildClick() doesn't take into account which group the child was in. So if the user clicked on a child under "Archived", which doesn't even have SubjectInfo, you are taking the child index and finding its SubjectInfo. In other words, your onChildClick() is treating every child as if it was a Subject child. You need to check the value of groupPosition to make sure the user clicked on a Subject child.

在你的 setChildGroupData(),你有这样的code:

In your setChildGroupData(), you have this code:

child = new ArrayList<String>();
childItem.add(child);
childItem.add(child);
childItem.add(child);

这意味着,每个组正在访问的相同的列表的。所以,当你去把一个子项的科目组中,同样的子项也将设置组中显示出来。

That means that each group is accessing the same list. So when you go to put an child item in the Subjects group, that same child item is also going to show up in the Settings group.

我可以给你最好的建议是要尝试启动的思维 ExpandableListView 更像是一个抽象的层次列表的数据结构,而不是像一个可视化的/可触摸元素。 A 的TextView 映射到字符串。 A 复选框映射到布尔单选按钮映射到枚举您定义。然后确保这些方法来获取视图使用这些数据,并有来自更新数据的看法回调方法。适配器接口是为了与这样的数据交互,所以如果你能钉该数据结构中,将解决很多问题。

The best advice I can give you is to try to start thinking of the ExpandableListView more like an abstract hierarchical list data structure and less like a visual/touchable element. A TextView maps to a String. A CheckBox maps to a boolean. RadioButtons map to an enum that you define. Then make sure that the methods to get the views use this data, and that there are callback methods from the views that update the data. The adapter interface is meant to interact with data like this, so if you can nail that data structure, you will solve a lot of problems.

您没有提供code为你的 NewAdapter 类,但我敢打赌,我知道发生了什么:你可能显示与垃圾视图数据的回收视图

You didn't provide the code for your NewAdapter class, but I bet I know what's happening: You are probably displaying a recycled view with garbage view data.

适配器类的观点回收机制意味着,当你得到一个循环视图,你必须初始化的所有的视图,因为你不知道它是什么状态下,它被回收之前

The view recycling mechanism of the adapter classes means that when you get a recycled view, you have to initialize everything in the view because you don't know what state it was in before it was recycled.

的必然结果是,适配器具有提供的当前和最新的模型,以使适配器视图可以在任何给定时刻显示正确的数据的 。这意味着你的是:

The corollary to this is that the adapter has to provide a current and up-to-date model so that the adapter view can display the correct data at any given time. What this means to you is:


  • 您的适配器的数据模型(即 SubjectInfo )必须有一个布尔标志跟踪复选框的状态。此布尔标志将在使用getView()来设置初始复选框显示为选中或未选中。你不发表您的 SubjectInfo 类两种,但你的code是不是指在类中的任何布尔值,因此我假设你没有这样的。

  • your adapter data model (i.e. SubjectInfo) has to have a boolean flag to track the state of the checkbox. This boolean flag will be used in getView() to set the initial checkbox display as checked or unchecked. You didn't post your SubjectInfo class either, but your code isn't referring to any boolean in that class, so I assume you don't have that.

您的复选框需要有一个 OnCheckedChangedListener 将更新适配器的数据模型对应的布尔标志,并调用 notifyDataSetChanged()来让适配器察看知道它需要被刷新。

your checkbox needs to have an OnCheckedChangedListener that will update the corresponding boolean flag in the adapter's data model and call notifyDataSetChanged() to let the adapter view know that it needs to be refreshed.

如果你已经这样做,然后发布 NewAdapter SubjectInfo code,我们可以揣摩还有什么可能去错了。

If you're already doing that, then post your NewAdapter and SubjectInfo code and we can try to figure out what else may be going wrong.

P.S。在code线

P.S. The code line

checkBox.setChecked(!checkBox.isChecked());

可以替换

checkBox.toggle();

这篇关于在ExpandableListView孩子不由自主地重叠导致的复选框在不同的组检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆