上一篇《Android自己定义组件系列【5】——进阶实践(1)》中对任老师的《可下拉的PinnedHeaderExpandableListView的实现》前一部分进行了实现,这一篇我们来看看ExpandableListView的使用并实现剩下的部分。

原文出处:http://blog.csdn.net/singwhatiwanna/article/details/25546871

一、ExpandableListView的使用方法

ExpandableListView是ListView的子类,它在普通ListView的基础上进行了扩展,适配器为ExpandableListAdapter。

与Adapter相似的是。实现ExpandableListAdapter也有例如以下方式:

1、扩展BaseExpandableListAdapter实现ExpandableListAdapter

2、使用SimpleExpandableListAdapter将两个List集合包装成ExpandableListAdapter

3、使用SimpleCursorTreeAdapter将Cursor中的数据包装成SimpleCursorTreeAdapter

接下来用第一种方式来做个小样例。来看看ExpandableListView的使用

  1. ExpandableListAdapter adapter = new BaseExpandableListAdapter() {
  2.  
  3. @Override
  4. public boolean isChildSelectable(int arg0, int arg1) {
  5. // TODO Auto-generated method stub
  6. return false;
  7. }
  8.  
  9. @Override
  10. public boolean hasStableIds() {
  11. // TODO Auto-generated method stub
  12. return false;
  13. }
  14.  
  15. @Override
  16. public View getGroupView(int arg0, boolean arg1, View arg2, ViewGroup arg3) {
  17. // TODO Auto-generated method stub
  18. return null;
  19. }
  20.  
  21. @Override
  22. public long getGroupId(int arg0) {
  23. // TODO Auto-generated method stub
  24. return 0;
  25. }
  26.  
  27. @Override
  28. public int getGroupCount() {
  29. // TODO Auto-generated method stub
  30. return 0;
  31. }
  32.  
  33. @Override
  34. public Object getGroup(int arg0) {
  35. // TODO Auto-generated method stub
  36. return null;
  37. }
  38.  
  39. @Override
  40. public int getChildrenCount(int arg0) {
  41. // TODO Auto-generated method stub
  42. return 0;
  43. }
  44.  
  45. @Override
  46. public View getChildView(int arg0, int arg1, boolean arg2, View arg3,
  47. ViewGroup arg4) {
  48. // TODO Auto-generated method stub
  49. return null;
  50. }
  51.  
  52. @Override
  53. public long getChildId(int arg0, int arg1) {
  54. // TODO Auto-generated method stub
  55. return 0;
  56. }
  57.  
  58. @Override
  59. public Object getChild(int arg0, int arg1) {
  60. // TODO Auto-generated method stub
  61. return null;
  62. }
  63. };

能够看到BaseExpandableListApdater中的方法非常多,主要方法介绍例如以下:

getGroupCount():返回组列表数量

getGroupView():返回的View作为组列表项

getChildrenCount():返回子列表项的数量

getChildView():返回的View作为特定组、特定位置的子列表项

  1. package com.example.expandablelistviewtest;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.Gravity;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.AbsListView;
  9. import android.widget.BaseExpandableListAdapter;
  10. import android.widget.ExpandableListAdapter;
  11. import android.widget.ExpandableListView;
  12. import android.widget.ImageView;
  13. import android.widget.LinearLayout;
  14. import android.widget.TextView;
  15.  
  16. public class MainActivity extends Activity {
  17.  
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_main);
  22. ExpandableListAdapter adapter = new BaseExpandableListAdapter() {
  23.  
  24. int[] logos = new int[] {
  25. R.drawable.ic_launcher,
  26. R.drawable.ic_launcher,
  27. R.drawable.ic_launcher
  28. };
  29.  
  30. private String[] groupTypes = new String[]{
  31. "计算机语言", "人类语言", "动物语言"
  32. };
  33.  
  34. private String[][] childTypes = new String[][] {
  35. {"Java", "C++", "C", "PHP"},
  36. {"汉语", "英语", "日语", "法语"},
  37. {"咕咕", "汪汪", "喵喵"}
  38. };
  39.  
  40. // 获取指定组位置、指定子列表项处的子列表项数据
  41. @Override
  42. public Object getChild(int groupPosition, int childPosition) {
  43. return childTypes[groupPosition][childPosition];
  44. }
  45.  
  46. @Override
  47. public long getChildId(int groupPosition, int childPosition) {
  48. return childPosition;
  49. }
  50.  
  51. @Override
  52. public int getChildrenCount(int groupPosition) {
  53. return childTypes[groupPosition].length;
  54. }
  55.  
  56. private TextView getTextView() {
  57. AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
  58. ViewGroup.LayoutParams.MATCH_PARENT, 64);
  59. TextView textView = new TextView(MainActivity.this);
  60. textView.setLayoutParams(lp);
  61. textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
  62. textView.setPadding(36, 0, 0, 0);
  63. textView.setTextSize(20);
  64. return textView;
  65. }
  66.  
  67. // 该方法决定每一个子选项的外观
  68. @Override
  69. public View getChildView(int groupPosition, int childPosition,
  70. boolean isLastChild, View convertView, ViewGroup parent) {
  71. TextView textView = getTextView();
  72. textView.setText(getChild(groupPosition, childPosition)
  73. .toString());
  74. return textView;
  75. }
  76.  
  77. // 获取指定组位置处的组数据
  78. @Override
  79. public Object getGroup(int groupPosition) {
  80. return groupTypes[groupPosition];
  81. }
  82.  
  83. @Override
  84. public int getGroupCount() {
  85. return groupTypes.length;
  86. }
  87.  
  88. @Override
  89. public long getGroupId(int groupPosition) {
  90. return groupPosition;
  91. }
  92.  
  93. // 该方法决定每一个组选项的外观
  94. @Override
  95. public View getGroupView(int groupPosition, boolean isExpanded,
  96. View convertView, ViewGroup parent) {
  97. LinearLayout ll = new LinearLayout(MainActivity.this);
  98. ll.setOrientation(0);
  99. ImageView logo = new ImageView(MainActivity.this);
  100. logo.setImageResource(logos[groupPosition]);
  101. ll.addView(logo);
  102. TextView textView = getTextView();
  103. textView.setText(getGroup(groupPosition).toString());
  104. ll.addView(textView);
  105. return ll;
  106. }
  107.  
  108. @Override
  109. public boolean isChildSelectable(int groupPosition,
  110. int childPosition) {
  111. return true;
  112. }
  113.  
  114. @Override
  115. public boolean hasStableIds() {
  116. return true;
  117. }
  118. };
  119. ExpandableListView expandListView = (ExpandableListView) findViewById(R.id.list);
  120. expandListView.setAdapter(adapter);
  121. }
  122.  
  123. }
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:paddingBottom="@dimen/activity_vertical_margin"
  6. android:paddingLeft="@dimen/activity_horizontal_margin"
  7. android:paddingRight="@dimen/activity_horizontal_margin"
  8. android:paddingTop="@dimen/activity_vertical_margin"
  9. tools:context=".MainActivity" >
  10. <ExpandableListView
  11. android:id="@+id/list"
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"/>
  14.  
  15. </RelativeLayout>

二、代码分析

首先看onCreate方法:

  1. @Override
  2. public void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.main);
  5. expandableListView = (PinnedHeaderExpandableListView) findViewById(R.id.expandablelist);
  6. stickyLayout = (StickyLayout)findViewById(R.id.sticky_layout);
  7. initData();
  8.  
  9. adapter = new MyexpandableListAdapter(this);
  10. expandableListView.setAdapter(adapter);
  11.  
  12. // 展开全部group
  13. for (int i = 0, count = expandableListView.getCount(); i < count; i++) {
  14. expandableListView.expandGroup(i);
  15. }
  16.  
  17. expandableListView.setOnHeaderUpdateListener(this);
  18. expandableListView.setOnChildClickListener(this);
  19. expandableListView.setOnGroupClickListener(this);
  20. stickyLayout.setOnGiveUpTouchEventListener(this);
  21.  
  22. }

前面几行非常easy。和上面的样例差点儿一样。我们仅仅须要再关注一下initData()方法和以下的几行监听函数。

initData()中是模拟的数据。例如以下:

  1. void initData() {
  2. groupList = new ArrayList<Group>();
  3. Group group = null;
  4. for (int i = 0; i < 3; i++) {
  5. group = new Group();
  6. group.setTitle("group-" + i);
  7. groupList.add(group);
  8. }
  9.  
  10. childList = new ArrayList<List<People>>();
  11. for (int i = 0; i < groupList.size(); i++) {
  12. ArrayList<People> childTemp;
  13. if (i == 0) {
  14. childTemp = new ArrayList<People>();
  15. for (int j = 0; j < 13; j++) {
  16. People people = new People();
  17. people.setName("yy-" + j);
  18. people.setAge(30);
  19. people.setAddress("sh-" + j);
  20.  
  21. childTemp.add(people);
  22. }
  23. } else if (i == 1) {
  24. childTemp = new ArrayList<People>();
  25. for (int j = 0; j < 8; j++) {
  26. People people = new People();
  27. people.setName("ff-" + j);
  28. people.setAge(40);
  29. people.setAddress("sh-" + j);
  30.  
  31. childTemp.add(people);
  32. }
  33. } else {
  34. childTemp = new ArrayList<People>();
  35. for (int j = 0; j < 23; j++) {
  36. People people = new People();
  37. people.setName("hh-" + j);
  38. people.setAge(20);
  39. people.setAddress("sh-" + j);
  40.  
  41. childTemp.add(people);
  42. }
  43. }
  44. childList.add(childTemp);
  45. }
  46.  
  47. }

接下来我们看看监听这几个监听函数

  1. public class MainActivity extends Activity implements
  2. ExpandableListView.OnChildClickListener,
  3. ExpandableListView.OnGroupClickListener,
  4. OnHeaderUpdateListener, OnGiveUpTouchEventListener {

从Activity的继承关系上看。OnChildClickListener和OnGroupClickListener是ExpandableListView类的监听函数。

  1. @Override
  2. public boolean onGroupClick(final ExpandableListView parent, final View v,
  3. int groupPosition, final long id) {
  4.  
  5. return false;
  6. }
  7.  
  8. @Override
  9. public boolean onChildClick(ExpandableListView parent, View v,
  10. int groupPosition, int childPosition, long id) {
  11. Toast.makeText(MainActivity.this,
  12. childList.get(groupPosition).get(childPosition).getName(), 1)
  13. .show();
  14.  
  15. return false;
  16. }

再来看看OnHeaderUpdateListener,这个监听函数实际上是在重写(自己定义)的ExpandableListView中自己定义的监听。

  1. public void setOnHeaderUpdateListener(OnHeaderUpdateListener listener) {
  2. mHeaderUpdateListener = listener;
  3. if (listener == null) {
  4. return;
  5. }
  6. mHeaderView = listener.getPinnedHeader();
  7. int firstVisiblePos = getFirstVisiblePosition();
  8. int firstVisibleGroupPos = getPackedPositionGroup(getExpandableListPosition(firstVisiblePos));
  9. listener.updatePinnedHeader(firstVisibleGroupPos);
  10. requestLayout();
  11. postInvalidate();
  12. }

getPinnedHeader()方法创建(得到)一个列表头。然后通过updatePinnedHeader方法设置当前可见的子列表元素的组名称。

requestLayout()方法的作用是当view确定自身已经不再适合现有的区域时,该view本身调用这种方法要求parent view又一次调用他的onMeasure onLayout来对又一次设置自己位置。特别的当view的layoutparameter发生改变,而且它的值还没能应用到view上,这时候适合调用这种方法。

postInvalidate()方法的作用是实现界面刷新。

  1. public interface OnHeaderUpdateListener {
  2. /**
  3. * 採用单例模式返回同一个view对象就可以
  4. * 注意:view必须要有LayoutParams
  5. */
  6. public View getPinnedHeader();
  7.  
  8. public void updatePinnedHeader(int firstVisibleGroupPos);
  9. }

从OnHeaderUpdateListener监听函数的定义上看。当触发监听后会调用两个方法的实现例如以下:

  1. @Override
  2. public View getPinnedHeader() {
  3. if (mHeaderView == null) {
  4. mHeaderView = (ViewGroup) getLayoutInflater().inflate(R.layout.group, null);
  5. mHeaderView.setLayoutParams(new LayoutParams(
  6. LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
  7. }
  8. return mHeaderView;
  9. }

  1. @Override
  2. public void updatePinnedHeader(int firstVisibleGroupPos) {
  3. Group firstVisibleGroup = (Group) adapter.getGroup(firstVisibleGroupPos);
  4. TextView textView = (TextView) getPinnedHeader().findViewById(R.id.group);
  5. textView.setText(firstVisibleGroup.getTitle());
  6. }

接下来我们须要知道什么情况下回触发这个监听函数。

  1. protected void refreshHeader() {
  2. if (mHeaderView == null) {
  3. return;
  4. }
  5. int firstVisiblePos = getFirstVisiblePosition();
  6. int pos = firstVisiblePos + 1;
  7. int firstVisibleGroupPos = getPackedPositionGroup(getExpandableListPosition(firstVisiblePos));
  8. int group = getPackedPositionGroup(getExpandableListPosition(pos));
  9.  
  10. if (group == firstVisibleGroupPos + 1) {
  11. View view = getChildAt(1);
  12. if (view.getTop() <= mHeaderHeight) {
  13. int delta = mHeaderHeight - view.getTop();
  14. mHeaderView.layout(0, -delta, mHeaderWidth, mHeaderHeight - delta);
  15. }
  16. } else {
  17. mHeaderView.layout(0, 0, mHeaderWidth, mHeaderHeight);
  18. }
  19.  
  20. if (mHeaderUpdateListener != null) {
  21. mHeaderUpdateListener.updatePinnedHeader(firstVisibleGroupPos);
  22. }
  23. }

能够看到再调用refreshHeader()方法的时候会触发updatePinnerHeader方法。

  1. @Override
  2. public void onScroll(AbsListView view, int firstVisibleItem,
  3. int visibleItemCount, int totalItemCount) {
  4. if (totalItemCount > 0) {
  5. refreshHeader();
  6. }
  7. if (mScrollListener != null) {
  8. mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
  9. }
  10. }

呵呵,这下最终恍然大悟了。在onScroll方法中调用了refreshHeader,这就是说在滑动屏幕的时候OnHeaderUpdateListener监听会触发。会不断的推断是否应该改变列名称。

快凌晨1点钟了,今天就分析到这吧。明天继续。

再次声明一下,本文是为了学习Android自己定义组件,对任老师博客《可下拉的PinnedHeaderExpandableListView的实现》进行具体解读。假设有问题希望指出。

原文出处:http://blog.csdn.net/singwhatiwanna/article/details/25546871

Android自己定义组件系列【5】——进阶实践(2)的更多相关文章

  1. Android自己定义组件系列【7】——进阶实践(4)

    上一篇<Android自己定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识.这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpa ...

  2. Android自己定义组件系列【6】——进阶实践(3)

    上一篇<Android自己定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计 ...

  3. Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动

    在上一篇文章<Android自己定义组件系列[3]--自己定义ViewGroup实现側滑>中实现了仿Facebook和人人网的側滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布 ...

  4. Android自己定义组件系列【3】——自己定义ViewGroup实现側滑

    有关自己定义ViewGroup的文章已经非常多了,我为什么写这篇文章,对于刚開始学习的人或者对自己定义组件比較生疏的朋友尽管能够拿来主义的用了,可是要一步一步的实现和了解当中的过程和原理才干真真脱离别 ...

  5. Android自己定义组件系列【5】——高级实践(1)

    在接下来的几篇文章将任老师的博文<您可以下拉PinnedHeaderExpandableListView实现>骤来具体实现.来学习一下大神的代码并记录一下. 原文出处:http://blo ...

  6. Android自己定义组件系列【1】——自己定义View及ViewGroup

    View类是ViewGroup的父类,ViewGroup具有View的全部特性.ViewGroup主要用来充当View的容器.将当中的View作为自己孩子,并对其进行管理.当然孩子也能够是ViewGr ...

  7. Android自己定义组件系列【2】——Scroller类

    在上一篇中介绍了View类的scrollTo和scrollBy两个方法,对这两个方法不太了解的朋友能够先看<自己定义View及ViewGroup> scrollTo和scrollBy尽管实 ...

  8. Android自己定义组件系列【9】——Canvas绘制折线图

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了非常多插件,可是非常多时候我们须要依据详细项目自己定义这些图表,这一篇文章我们一起来看看怎样在Android中使用Can ...

  9. Android自己定义组件系列【8】——面膜文字动画

    我们掩盖文字动画Flash中非经货共同体共同,由于Android应用程序开发人员做你想要做这个动画在应用程序中去?本文中,我们看的是如何自己的定义ImageView来实现让一张文字图片实现文字的遮罩闪 ...

随机推荐

  1. 去掉PhpStorm打开自动启动的项目

    有时候启动的项目很大,导致很卡,而且在编辑器中更改也没效果,简单暴力的办法 找到项目的目录,删除其中的.idea文件夹

  2. 修改python注册表

    转自:http://blog.csdn.net/u014680513/article/details/51005650 # script to register Python 2.0 or later ...

  3. swiper 旋转木马效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  4. C#基础学习(二)

    ---恢复内容开始--- 面向对象 (类是不占内存,实例占内存) C#与python不用可以直接从另一个文件直接实例化一个类,不需要导包:                                ...

  5. python爬虫入门02:教你通过 Fiddler 进行手机抓包

    哟~哟~哟~ hi起来 everybody 今天要说说怎么在我们的手机抓包 通过 python爬虫入门01:教你在Chrome浏览器轻松抓包 我们知道了 HTTP 的请求方式 以及在 Chrome 中 ...

  6. 75-ADMI,Average Directional Movement Index,平均方向性运动指标.(2015.7.1)

    ADMI,Average Directional Movement Index 平均方向性运动指标 Directional Movement Index,平均方向性运动指标.(2015.7.1)&qu ...

  7. python 调用 C 动态库

    首先是 C 的头文件和源文件, #ifndef POINT_H #define POINT_H struct point { int x; int y; }; void point_print(str ...

  8. 【HDU 2196】 Computer (树形DP)

    [HDU 2196] Computer 题链http://acm.hdu.edu.cn/showproblem.php?pid=2196 刘汝佳<算法竞赛入门经典>P282页留下了这个问题 ...

  9. 7-14 电话聊天狂人(25 分)(Hash表基本操作)

    7-14 电话聊天狂人(25 分) 给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人. 输入格式: 输入首先给出正整数N(≤10​5​​),为通话记录条数.随后N行,每行给出一条通话记录.简单 ...

  10. hash存储结构【六】

    一.概述: 我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器.所以该类型非常适合于存储值对象的信息.如Username.Password和Ag ...