Android自定义组件系列【5】——进阶实践(2)

来源:互联网 发布:python循环语句 编辑:程序博客网 时间:2024/05/16 05:32

上一篇《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(36000);  
  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. }  
前面几行很容易,和上面的例子几乎一样,我们只需要再关注一下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(00, 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的实现》进行详细解读,如果有问题希望指出。

0 0