ExpandableListView的自定义布局以及注意事项
2015-11-25 23:50
323 查看
android开发中常常需要使用到ExpandableListView来对一组数据进行分组, 使用ExpandableListView能够达到类似QQ分组的效果,类似于下面两张效果图:
要达到这种效果其实并不难,因为ExpandableListView跟ListView很相似,如果你对ListView很熟悉的话,很快就能掌握它,如果对ListView不熟悉的话,建议 先看看之前的博文 android学习之ListView的基本使用
首先定义一个主布局:activity_main.xml
然后自定义ExpandableListView中的组名显示布局:item_group.xml
接着定义每个组下子项的布局:item_child.xml
为了方便,可以建立一个类为每个布局的组件创建一个字段,如给子项定义一个Child类:
如果需要,也可以为群组建立类。
然后到了关键部分,为ExpandableListView创建一个适配器,适配器是连接视图与数据的桥梁。负责将数据送到视图中。这里自定义MyAdapter适配器继承BaseExpandableListAdapter,并重写其所有方法。
最后一步,在MainActivity中获取ExpandableListView实例并调用其setAdapter方法将自定义的MyAdapter对象传进去即可。
这里有几点值得注意:
1、与ListView不同,在ExpandableListView中使用ViewHolder的话会出问题,因为ExpandableListView中的每一个组下子项数目并不是相同的,重用之前的convertView会崩溃。
2、如果是从外部读入数据到列表项中,如数据库等,要特别注意列表项数据为null的情形,否则会有空指针异常并崩溃。
要达到这种效果其实并不难,因为ExpandableListView跟ListView很相似,如果你对ListView很熟悉的话,很快就能掌握它,如果对ListView不熟悉的话,建议 先看看之前的博文 android学习之ListView的基本使用
首先定义一个主布局:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ExpandableListView android:id="@+id/expandableView" android:layout_width="wrap_content" android:layout_height="wrap_content"></ExpandableListView> </RelativeLayout>
然后自定义ExpandableListView中的组名显示布局:item_group.xml
<RelativeLayout 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/tv_group_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerInParent="true" android:text="title" android:textSize="30sp" android:layout_marginLeft="30dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/iv_group_img" android:layout_alignParentRight="true"/> </RelativeLayout>
接着定义每个组下子项的布局:item_child.xml
<RelativeLayout 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/tv_child_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginTop="30dp" android:textSize="20sp" android:layout_alignParentLeft="true" android:text="test"/> <TextView android:id="@+id/tv_child_explain" android:layout_width="wrap_content" android:layout_alignLeft="@id/tv_child_title" android:layout_below="@id/tv_child_title" android:layout_height="wrap_content" android:text="explain"/> <ImageView android:id="@+id/iv_child_img" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
为了方便,可以建立一个类为每个布局的组件创建一个字段,如给子项定义一个Child类:
/** * Created by mhwang on 2015/11/25. */ public class Child { /**子项标题*/ private String title; /**子项解释*/ private String explain; public Child(){ title = "title"; explain = "explain"; } public String getTitle() { return title; } public String getExplain() { return explain; } public void setTitle(String title) { this.title = title; } public void setExplain(String explain) { this.explain = explain; } }
如果需要,也可以为群组建立类。
然后到了关键部分,为ExpandableListView创建一个适配器,适配器是连接视图与数据的桥梁。负责将数据送到视图中。这里自定义MyAdapter适配器继承BaseExpandableListAdapter,并重写其所有方法。
/** * Created by mhwang on 2015/11/25. */ public class MyAdapter extends BaseExpandableListAdapter { /**群组名*/ private ArrayList<String> groups; /**群组下的子项*/ private ArrayList<ArrayList<Child>> childs; private Context mContext; public MyAdapter(Context context){ mContext = context; init(); } /**为了测试方便,先初始化一些数据*/ public void init(){ groups = new ArrayList<String>(); //添加一些群组 for(int i = 0; i < 10; i++){ groups.add("群组"+i); } childs = new ArrayList<ArrayList<Child>>(); //为每个群组添加一些子项 for(int i = 0; i < groups.size(); i++){ //如果该群组是偶数,为其添加5个子项,奇数添加3项 ArrayList<Child> values = new ArrayList<>(); if(i % 2 == 0 ){ for(int j = 0; j < 5; j++) { Child child = new Child(); child.setTitle("子项"+j); child.setExplain("解释"+j); values.add(child); childs.add(values); } }else{ for(int j = 0; j < 3; j++){ Child child = new Child(); child.setTitle("子项"+j); child.setExplain("解释"+j); values.add(child); childs.add(values); } } } } @Override public int getGroupCount() { return groups.size(); } @Override public int getChildrenCount(int groupPosition) { return childs.get(groupPosition).size(); } @Override public Object getGroup(int groupPosition) { return groups.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return childs.get(groupPosition).get(childPosition); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public boolean hasStableIds() { return true; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { /**创建view */ View v = LayoutInflater.from(mContext).inflate(R.layout.item_group,null); /**通过创建的view与自定义布局绑定,就要以找到布局里的组件了*/ TextView tvGroupTitle = (TextView)v.findViewById(R.id.tv_group_title); ImageView ivGroupImg = (ImageView)v.findViewById(R.id.iv_group_img); tvGroupTitle.setText(groups.get(groupPosition)); ivGroupImg.setBackgroundResource(R.drawable.m1); return v; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View v = LayoutInflater.from(mContext).inflate(R.layout.item_child,null); TextView tvChildTitle = (TextView)v.findViewById(R.id.tv_child_title); TextView tvChildExplain = (TextView)v.findViewById(R.id.tv_child_explain); ImageView ivChildImg = (ImageView)v.findViewById(R.id.iv_child_img); tvChildTitle.setText(childs.get(groupPosition).get(childPosition).getTitle()); tvChildExplain.setText(childs.get(groupPosition).get(childPosition).getExplain()); ivChildImg.setBackgroundResource(R.drawable.m2); return v; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } }
最后一步,在MainActivity中获取ExpandableListView实例并调用其setAdapter方法将自定义的MyAdapter对象传进去即可。
public class MainActivity extends AppCompatActivity { ExpandableListView expandableListView; MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); expandableListView = (ExpandableListView)findViewById(R.id.expandableView); adapter = new MyAdapter(this); expandableListView.setAdapter(adapter); } }
这里有几点值得注意:
1、与ListView不同,在ExpandableListView中使用ViewHolder的话会出问题,因为ExpandableListView中的每一个组下子项数目并不是相同的,重用之前的convertView会崩溃。
2、如果是从外部读入数据到列表项中,如数据库等,要特别注意列表项数据为null的情形,否则会有空指针异常并崩溃。
相关文章推荐
- [树莓派] - u盘做系统盘
- 传智计算器简单界面1等
- LeetCode() Issomorphic Strings
- 第一个特征点提取算法
- 山东理工ACM:1334
- vim编辑器使用技巧
- IOS 真机调试 由于安全原因未能启动的解决方法
- SQL server 数据存储过程
- 前台几个功能使用的框架说明
- pureftpd安装配置[总结]
- 山东理工ACM:1180
- 杭电oj 1004
- QQ守卫农场辅助--QQ守卫农场外挂
- 在WIN2008R2的IIS7环境下安装PHP5.6.15
- bulk collect
- sql server 使用函数辅助查询
- SQL server 子查询 链接查询
- hdu 1421
- Apache 指定的网络名不再可用 winnt_accept: Asynchronous AcceptEx failed 的解决办法
- 利用两个栈实现一个队列(C++版)