安卓 - 可扩展列表视图

9
我正在尝试构建一个包含以下内容的视图(其中有很多):
  • PARENT1(可选中,可展开)
  • CHILD1(单选按钮)
  • CHILD2(单选按钮)

...

  • PARENT2(可选中,可展开)
  • CHILD1(可选中)
  • CHILD2(可选中)

...

关键是父项必须是可选中的,基于此,子项的图标会发生变化。有人能指点一下我正确的方向吗?因为我找到的东西似乎对我没有用。
1个回答

17

假设您已经以某种方式结构化了数据,如下所示:

ArrayList where 
Parent {name:String, checked:boolean, children:ArrayList} and
Child {name:String}

如果是这样,您只需要完成以下两个步骤:

  1. 为父项渲染器和子项渲染器创建适当的布局
  2. 扩展BaseExpandableListAdapter来自行构建列表。

这里是我心中的一个小例子:
layout/grouprow.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:orientation="horizontal"
    android:gravity="fill" android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- PARENT -->
    <TextView android:id="@+id/parentname" android:paddingLeft="5px"
        android:paddingRight="5px" android:paddingTop="3px"
        android:paddingBottom="3px" android:textStyle="bold" android:textSize="18px"
        android:layout_gravity="fill_horizontal" android:gravity="left"
        android:layout_height="wrap_content" android:layout_width="wrap_content" />
    <CheckBox android:id="@+id/checkbox" android:focusable="false" 
        android:layout_alignParentRight="true" android:freezesText="false"
        android:layout_width="wrap_content" android:layout_height="wrap_content" 
        android:layout_marginTop="5px" />
</RelativeLayout>

layout/childrow.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent" 
    android:layout_height="wrap_content" android:padding="0px">
    <!-- CHILD -->
    <TextView android:id="@+id/childname" android:paddingLeft="15px" 
        android:paddingRight="5px" android:focusable="false" android:textSize="14px"
        android:layout_marginLeft="10px" android:layout_marginRight="3px" 
        android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>

MyELAdapter类: 我将其声明为MyExpandableList的内部类,这样我就可以直接访问父列表,而无需将其作为参数传递。

private class MyELAdapter extends BaseExpandableListAdapter
{
    private LayoutInflater inflater;

    public MyELAdapter()
    {
        inflater = LayoutInflater.from(MyExpandableList.this);
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, 
            View convertView, ViewGroup parentView)
    {
        final Parent parent = parents.get(groupPosition);
        convertView = inflater.inflate(R.layout.grouprow, parentView, false);
        ((TextView) convertView.findViewById(R.id.parentname)).setText(parent.getName());
        CheckBox checkbox = (CheckBox) convertView.findViewById(R.id.checkbox);
        checkbox.setChecked(parent.isChecked());
        checkbox.setOnCheckedChangeListener(new CheckUpdateListener(parent));
        if (parent.isChecked())
            convertView.setBackgroundResource(R.color.red);
        else
            convertView.setBackgroundResource(R.color.blue);
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, 
            View convertView, ViewGroup parentView)
    {
        final Parent parent = parents.get(groupPosition);
        final Child child = parent.getChildren().get(childPosition);
        convertView = inflater.inflate(R.layout.childrow, parentView, false);
        ((TextView) convertView.findViewById(R.id.childname)).setText(child.getName());
        return convertView;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition)
    {
        return parents.get(groupPosition).getChildren().get(childPosition);
    }

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

    @Override
    public int getChildrenCount(int groupPosition)
    {
        return parents.get(groupPosition).getChildren().size();
    }

    @Override
    public Object getGroup(int groupPosition)
    {
        return parents.get(groupPosition);
    }

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

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

    @Override
    public void notifyDataSetChanged()
    {
        super.notifyDataSetChanged();
    }

    @Override
    public boolean isEmpty()
    {
        return ((parents == null) || parents.isEmpty());
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition)
    {
        return true;
    }

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

    @Override
    public boolean areAllItemsEnabled()
    {
        return true;
    }
}

你必须已经有一个公共类 MyExpandableList extends ExpandableListActivity,它具有成员:

private ArrayList<Parent> parents;

在给该成员变量赋值/加载其父级列表后,您还应该将适配器附加到此视图:

this.setListAdapter(new MyELAdapter());

就是这样了。你现在有一个可勾选、可展开的列表,而在CheckUpdateListeneronCheckedChanged(CompoundButton buttonView, boolean isChecked)方法中,你可以更新父对象的选中状态。

请注意,在getGroupView方法中确定了背景颜色,所以你不必在任何地方更改它,只需在需要时调用适配器的notifyDataSetChanged()方法即可。

更新

你可以从此链接下载示例源代码。这是一个eclipse项目,但如果你使用其他开发环境,只需简单地复制必要的源文件(java + xml)即可。


谢谢rekaszeru。由于我是初学者,您能分享一个可用的示例吗? - no9
1
当然,我只需要几分钟来构建一个。不过,如果我知道你从哪里获取数据(服务器还是本地),那会很有用。 - rekaszeru
如果可以的话,请创建一个非常简单的示例(只有一些带有大量数组的测试数据)。我正在通过为紧凑框架树形视图设计的XML服务获取数据。我将必须自己格式化数据,但在这个阶段我还不确定如何操作。现在我对可扩展列表本身的结构感兴趣。复选框,单选按钮等 - no9
非常感谢你,rekaszeru!如果我可以再问一个问题...如果您想要我在问题中提出的模式,您将如何自定义子项。在一个父级下,我希望子项进行多选(复选框),在另一个父级下,我希望子项进行单选(单选按钮)。尽管如此,我接受您的答案,因为您花费了时间和知识来帮助新手! - no9
您可以扩展适配器的getChildView方法,并检查父项是否需要单选或多选子项。还需要创建两个childrow.xml文件,一个用于radiobuttons,另一个用于复选框。在数据结构层面上实现这一点最清晰的方式可能是拥有一个抽象的AParent类(具有当前Parent的功能),并基于它创建SingleSelectParent和MultiSelectParent扩展类。其中一个将有一个新成员:selectedIndex:int,而MultiSelectParent将有一个selectedIndices:ArrayList<int>... - rekaszeru
确定你正在处理哪种类型的 AParent 后,你需要填充相应的 childrow.xml,并根据 Child 实例的 selected 成员设置 checked/selected 值。 - rekaszeru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接