Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1566775
  • 博文数量: 113
  • 博客积分: 3526
  • 博客等级: 中校
  • 技术积分: 1815
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-08 09:46
个人简介

记录总结自己的工作

文章分类

全部博文(113)

文章存档

2015年(19)

2014年(10)

2013年(6)

2012年(16)

2011年(24)

2010年(21)

2009年(17)

分类: Android平台

2014-02-28 10:02:49

       工作中遇到一个选择车型的问题,需要在扩展列表中选择车辆品牌->车型->年款,所以必须得使用三级的扩展列表来实现,而且第三级还得使用GridView来展示。下面就一步步来吧。


       1.定义需要使用的车型类,每个车辆品牌下面包含n个车型,每个车型下面包含n个年款

点击(此处)折叠或打开

  1. /**
  2.  * 汽车的品牌类
  3.  *
  4.  * @author liyanshun 2014-2-21
  5.  */
  6. public class CarBrand {
  7.     /**
  8.      * 汽车的品牌名字
  9.      */
  10.     public String mBrandName;
  11.     public String mSortLetters;
  12.     /** 该品牌下包含的汽车类型 */
  13.     public ArrayList<CarStyle> mCarStyleList;
  14. }

  15. /**
  16.  * 汽车车类型
  17.  *
  18.  * @author liyanshun 2014-2-26
  19.  */
  20. public class CarStyle {
  21.     /** 汽车的类型名 */
  22.     public String mStyleName;
  23.     /** 该类型下包含的年款 */
  24.     public ArrayList<String> mModelList;
  25. }

      2.列表要可以按照首字母快速定位,这个功能参考了别人的实现,详情见这篇博客:http://blog.csdn.net/xiaanming/article/details/12684155

      3.实现第一级扩展列表。第一级比较好实现,只用使用一个ExpandableListView,并定义Adapter就可以了。需要注意的是每个品牌下面的子View个数即为其包含的车型个数,而每个车型都是一个新                                   的ExpandableListView。当然也可以使用一个ExpandableListView来展示所有的车型,但是那样的话会导致点击靠下的车型时,其后面的车型可能会被后一项的品牌给覆盖掉。所以在这里使用多了多                                个ExpandableListView。Adapter的实现如下:


点击(此处)折叠或打开

  1. /**
  2.  * 用来选择车辆品牌并且带字母排序的adapter
  3.  *
  4.  * @author liyanshun 2014-2-21
  5.  */
  6. public class CarBrandAdapter extends BaseExpandableListAdapter implements
  7.         SectionIndexer {
  8.     private List<CarBrand> mBrandList = null;
  9.     private Context mContext;

  10.     public CarBrandAdapter(Context mContext, List<CarBrand> list) {
  11.         this.mContext = mContext;
  12.         this.mBrandList = list;
  13.     }

  14.     /**
  15.      * 当ListView数据发生变化时,调用此方法来更新ListView
  16.      *
  17.      * @param mBrandList
  18.      */
  19.     public void updateListView(List<CarBrand> list) {
  20.         this.mBrandList = list;
  21.         notifyDataSetChanged();
  22.     }

  23.     public int getCount() {
  24.         return this.mBrandList.size();
  25.     }

  26.     public Object getItem(int position) {
  27.         return mBrandList.get(position);
  28.     }

  29.     public long getItemId(int position) {
  30.         return position;
  31.     }

  32.     final static class ViewHolder {
  33.         TextView tvLetter;
  34.         TextView tvTitle;
  35.         ImageView carBrand;
  36.         ImageView close;
  37.         View body;
  38.         View titleBar;
  39.     }

  40.     final static class CarStyleViewHolder {
  41.         ExpandableListView styleList;
  42.     }

  43.     /**
  44.      * 根据ListView的当前位置获取分类的首字母的Char ascii值
  45.      */
  46.     public int getSectionForPosition(int position) {
  47.         return mBrandList.get(position).mSortLetters.charAt(0);
  48.     }

  49.     /**
  50.      * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
  51.      */
  52.     public int getPositionForSection(int section) {
  53.         for (int i = 0; i < getCount(); i++) {
  54.             String sortStr = mBrandList.get(i).mSortLetters;
  55.             char firstChar = sortStr.toUpperCase().charAt(0);
  56.             if (firstChar == section) {
  57.                 return i;
  58.             }
  59.         }

  60.         return -1;
  61.     }

  62.     /**
  63.      * 提取英文的首字母,非英文字母用#代替。
  64.      *
  65.      * @param str
  66.      * @return
  67.      */
  68.     private String getAlpha(String str) {
  69.         String sortStr = str.trim().substring(0, 1).toUpperCase();
  70.         // 正则表达式,判断首字母是否是英文字母
  71.         if (sortStr.matches("[A-Z]")) {
  72.             return sortStr;
  73.         } else {
  74.             return "#";
  75.         }
  76.     }

  77.     @Override
  78.     public Object[] getSections() {
  79.         return null;
  80.     }

  81.     @Override
  82.     public int getGroupCount() {
  83.         return mBrandList == null ? 0 : mBrandList.size();
  84.     }

  85.     @Override
  86.     public int getChildrenCount(int groupPosition) {
  87.         return mBrandList == null ? 0
  88.                 : (mBrandList.get(groupPosition) == null ? 0 : (mBrandList
  89.                         .get(groupPosition).mCarStyleList == null ? 0
  90.                         : mBrandList.get(groupPosition).mCarStyleList.size()));
  91.     }

  92.     @Override
  93.     public Object getGroup(int groupPosition) {
  94.         return mBrandList.get(groupPosition);
  95.     }

  96.     @Override
  97.     public Object getChild(int groupPosition, int childPosition) {
  98.         return mBrandList.get(groupPosition).mCarStyleList.get(childPosition);
  99.     }

  100.     @Override
  101.     public long getGroupId(int groupPosition) {
  102.         return groupPosition;
  103.     }

  104.     @Override
  105.     public long getChildId(int groupPosition, int childPosition) {
  106.         return groupPosition;
  107.     }

  108.     @Override
  109.     public boolean hasStableIds() {
  110.         return false;
  111.     }

  112.     @Override
  113.     public View getGroupView(int groupPosition, boolean isExpanded,
  114.             View convertView, ViewGroup parent) {
  115.         ViewHolder viewHolder = null;
  116.         final CarBrand mContent = mBrandList.get(groupPosition);
  117.         if (convertView == null) {
  118.             viewHolder = new ViewHolder();
  119.             convertView = LayoutInflater.from(mContext).inflate(
  120.                     R.layout.car_brand_item, null);
  121.             viewHolder.tvTitle = (TextView) convertView
  122.                     .findViewById(R.id.title);
  123.             viewHolder.tvLetter = (TextView) convertView
  124.                     .findViewById(R.id.catalog);
  125.             viewHolder.carBrand = (ImageView) convertView
  126.                     .findViewById(R.id.item_img);
  127.             viewHolder.close = (ImageView) convertView
  128.                     .findViewById(R.id.close_img);
  129.             viewHolder.body = convertView.findViewById(R.id.item_body);
  130.             viewHolder.titleBar = convertView.findViewById(R.id.title_bar);
  131.             convertView.setTag(viewHolder);
  132.         } else {
  133.             viewHolder = (ViewHolder) convertView.getTag();
  134.         }

  135.         // 根据position获取分类的首字母的Char ascii值
  136.         int section = getSectionForPosition(groupPosition);

  137.         // 如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
  138.         if (groupPosition == getPositionForSection(section)) {
  139.             viewHolder.titleBar.setVisibility(View.VISIBLE);
  140.             viewHolder.tvLetter.setText(mContent.mSortLetters);
  141.         } else {
  142.             viewHolder.titleBar.setVisibility(View.GONE);
  143.         }

  144.         viewHolder.tvTitle
  145.                 .setText(this.mBrandList.get(groupPosition).mBrandName);

  146.         if (isExpanded) {
  147.             viewHolder.close.setVisibility(View.VISIBLE);
  148.         } else {
  149.             viewHolder.close.setVisibility(View.GONE);
  150.         }

  151.         return convertView;

  152.     }

  153.     @Override
  154.     public View getChildView(int groupPosition, int childPosition,
  155.             boolean isLastChild, View convertView, ViewGroup parent) {
  156.         CarStyleAdapter carStyleAdapter = new CarStyleAdapter(mContext,
  157.                 mBrandList.get(groupPosition).mCarStyleList.get(childPosition));
  158.         CustExpListview SecondLevelexplv = new CustExpListview(mContext);
  159.         SecondLevelexplv.setAdapter(carStyleAdapter);
  160.         SecondLevelexplv.setGroupIndicator(null);
  161.         return SecondLevelexplv;
  162.     }

  163.     @Override
  164.     public boolean isChildSelectable(int groupPosition, int childPosition) {
  165.         return true;
  166.     }

  167.     public class CustExpListview extends ExpandableListView {

  168.         public CustExpListview(Context context) {
  169.             super(context);
  170.         }

  171.         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  172.             widthMeasureSpec = MeasureSpec.makeMeasureSpec(960,
  173.                     MeasureSpec.AT_MOST);
  174.             heightMeasureSpec = MeasureSpec.makeMeasureSpec(600,
  175.                     MeasureSpec.AT_MOST);
  176.             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  177.         }
  178.     }
  179. }
      
     4 .将这个Adapter加到ExpandableListView中就可以实现二级的扩展菜单了,下面来实现带GridView的三级扩展菜单。与二级的不同,三级的GridView必须使用一个来实现,也就是说
     每个车型下面的n个年款使用一个GridView来展示。所以需要注意的就是返回ChildCount的时候只能返回1。这个Adapter的实现如下:


点击(此处)折叠或打开

  1. /**
  2.  * 显示车型和年款的adapter
  3.  *
  4.  * @author liyanshun 2014-2-27
  5.  */
  6. public class CarStyleAdapter extends BaseExpandableListAdapter implements
  7.         OnItemClickListener {
  8.     private static final String TAG = "CarStyleAdapter";
  9.     private CarStyle mCarStyle = null;
  10.     private Context mContext;

  11.     public CarStyleAdapter(Context mContext, CarStyle carStyle) {
  12.         this.mContext = mContext;
  13.         this.mCarStyle = carStyle;
  14.     }

  15.     @Override
  16.     public int getGroupCount() {
  17.         return mCarStyle == null ? 0 : 1;
  18.     }

  19.     @Override
  20.     public int getChildrenCount(int groupPosition) {
  21.         //只显示一个Child,否则会造成GridView的重复显示
  22.         return mCarStyle == null ? 0 : (mCarStyle.mModelList == null ? 0 : 1);
  23.     }

  24.     @Override
  25.     public Object getGroup(int groupPosition) {
  26.         return mCarStyle;
  27.     }

  28.     @Override
  29.     public Object getChild(int groupPosition, int childPosition) {
  30.         return mCarStyle.mModelList.get(childPosition);
  31.     }

  32.     @Override
  33.     public long getGroupId(int groupPosition) {
  34.         return groupPosition;
  35.     }

  36.     @Override
  37.     public long getChildId(int groupPosition, int childPosition) {
  38.         return groupPosition;
  39.     }

  40.     @Override
  41.     public boolean hasStableIds() {
  42.         return false;
  43.     }

  44.     @Override
  45.     public View getGroupView(int groupPosition, boolean isExpanded,
  46.             View convertView, ViewGroup parent) {
  47.         Logger.d(TAG, "groupPosition:" + groupPosition);
  48.         ViewHolder viewHolder = null;
  49.         if (convertView == null) {
  50.             viewHolder = new ViewHolder();
  51.             convertView = LayoutInflater.from(mContext).inflate(
  52.                     R.layout.car_style_item, null);
  53.             viewHolder.tvTitle = (TextView) convertView
  54.                     .findViewById(R.id.style_name);
  55.             viewHolder.bottmLine = (View) convertView
  56.                     .findViewById(R.id.style_bottom_line);
  57.             viewHolder.styleArrow = (ImageView) convertView
  58.                     .findViewById(R.id.style_arrow);
  59.             viewHolder.closeView = (ImageView) convertView
  60.                     .findViewById(R.id.style_close_img);
  61.             convertView.setTag(viewHolder);
  62.         } else {
  63.             viewHolder = (ViewHolder) convertView.getTag();
  64.         }
  65.         viewHolder.tvTitle.setText(mCarStyle.mStyleName);
  66.         if (isExpanded) {
  67.             viewHolder.styleArrow.setVisibility(View.VISIBLE);
  68.             viewHolder.closeView.setVisibility(View.VISIBLE);
  69.         } else {
  70.             viewHolder.styleArrow.setVisibility(View.GONE);
  71.             viewHolder.closeView.setVisibility(View.GONE);
  72.         }
  73.         return convertView;
  74.     }

  75.     @Override
  76.     public View getChildView(int groupPosition, int childPosition,
  77.             boolean isLastChild, View convertView, ViewGroup parent) {
  78.         GridView gridView = null;
  79.         if (convertView == null) {
  80.             LayoutInflater layoutInflater = (LayoutInflater) mContext
  81.                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  82.             convertView = layoutInflater.inflate(R.layout.car_model_grid, null);

  83.             gridView = (GridView) convertView.findViewById(R.id.gridview);
  84.             gridView.setNumColumns(2);// 设置每行列数
  85.             gridView.setGravity(Gravity.CENTER);// 位置居中
  86.             gridView.setHorizontalSpacing(10);// 水平间隔

  87.             gridView.setAdapter(new GridAdapter());

  88.             //计算并设置gridView的高度
  89.             final int rowHeightDp = 40;
  90.             final float ROW_HEIGHT = mContext.getResources()
  91.                     .getDisplayMetrics().density * rowHeightDp;
  92.             double size = mCarStyle.mModelList.size();
  93.             int rowCount = (int) Math.ceil(size/2);
  94.             final int GRID_HEIGHT = (int) (ROW_HEIGHT * rowCount);
  95.             gridView.getLayoutParams().height = GRID_HEIGHT;
  96.             gridView.setOnItemClickListener(this);
  97.         }

  98.         return convertView;

  99.     }

  100.     @Override
  101.     public boolean isChildSelectable(int groupPosition, int childPosition) {
  102.         return true;
  103.     }

  104.     final static class ViewHolder {
  105.         TextView tvTitle;
  106.         View bottmLine;
  107.         ImageView styleArrow;
  108.         ImageView closeView;
  109.     }

  110.     private class GridAdapter extends BaseAdapter {
  111.         @Override
  112.         public int getCount() {
  113.             return mCarStyle.mModelList.size();
  114.         }

  115.         @Override
  116.         public Object getItem(int position) {
  117.             return mCarStyle.mModelList.get(position);
  118.         }

  119.         @Override
  120.         public long getItemId(int position) {
  121.             return 0;
  122.         }

  123.         @Override
  124.         public View getView(int position, View convertView, ViewGroup parent) {
  125.             ViewHolder viewHolder = null;
  126.             if (convertView == null) {
  127.                 viewHolder = new ViewHolder();
  128.                 convertView = LayoutInflater.from(mContext).inflate(
  129.                         R.layout.car_model_item, null);
  130.                 viewHolder.tvTitle = (TextView) convertView
  131.                         .findViewById(R.id.name);
  132.                 convertView.setTag(viewHolder);
  133.             } else {
  134.                 viewHolder = (ViewHolder) convertView.getTag();
  135.             }
  136.             viewHolder.tvTitle.setText((mCarStyle.mModelList.get(position)));
  137.             return convertView;
  138.         }

  139.     }

  140.     @Override
  141.     public void onItemClick(AdapterView<?> parent, View view, int position,
  142.             long id) {
  143.         Toast.makeText(mContext, "" + position, Toast.LENGTH_SHORT).show();
  144.     }
  145. }

    5.好了,最重要的两个Adapter已经实现了,只需要将其加入了界面中就可以了。在这里我使用了一个fragment来进行展示:
   

点击(此处)折叠或打开

  1. /**
  2.  * 选择汽车品牌
  3.  *
  4.  * @author liyanshun 2014-2-21
  5.  */
  6. public class SelectBrandFragment extends FatherFragment implements
  7.         OnClickListener, OnItemClickListener {
  8.     private static final String TAG = "SelectBrandFragment";
  9.     private ExpandableListView mSortListView;
  10.     private SideBar mSideBar;
  11.     private TextView mDialog;
  12.     private CarBrandAdapter mAdapter;
  13.     /**
  14.      * 汉字转换成拼音的类
  15.      */
  16.     private CharacterParser characterParser;
  17.     private List<CarBrand> SourceDateList;

  18.     /**
  19.      * 根据拼音来排列ListView里面的数据类
  20.      */
  21.     private PinyinComparator pinyinComparator;

  22.     String[] data={"奥迪","宝马","奔驰","雪铁龙","大众","牧马人"};
  23.     @Override
  24.     public void onStart() {
  25.         super.onStart();
  26.         Logger.d(TAG,"onStart");
  27.         //已经设置过layout了,无需再次设定
  28.         if(mLayoutAdded){
  29.             return;
  30.         }
  31.         super.setLayout(R.layout.select_brand);
  32.         mSortListView = (ExpandableListView) mBodyView.findViewById(R.id.lv);
  33.         mSideBar = (SideBar) mBodyView.findViewById(R.id.sidrbar);
  34.         mDialog = (TextView) mBodyView.findViewById(R.id.dialog);
  35.         mSideBar.setTextView(mDialog);
  36.         mTitle.setText(R.string.select_brand);
  37.         mRightTitle.setText(R.string.jump);
  38.         mRightTitle.setOnClickListener(this);

  39.         // 实例化汉字转拼音类
  40.         characterParser = CharacterParser.getInstance();
  41.         pinyinComparator = new PinyinComparator();

  42.         mSortListView.setOnItemClickListener(this);
  43.         // 设置右侧触摸监听
  44.         mSideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {

  45.             @Override
  46.             public void onTouchingLetterChanged(String s) {
  47.                 // 该字母首次出现的位置
  48.                 int position = mAdapter.getPositionForSection(s.charAt(0));
  49.                 if (position != -1) {
  50.                     mSortListView.setSelection(position);
  51.                 }

  52.             }
  53.         });

  54.          SourceDateList = filledData(data);
  55. //        
  56. //        // 根据a-z进行排序源数据
  57.         Collections.sort(SourceDateList, pinyinComparator);
  58.         mAdapter = new CarBrandAdapter(mContext, SourceDateList);
  59. //        CarStyleAdapter carStyleAdapter=new CarStyleAdapter(mContext,SourceDateList.get(2).mCarStyleList);
  60.         mSortListView.setAdapter(mAdapter);
  61.     }

  62.     @Override
  63.     public void onClick(View v) {
  64.         int id = v.getId();
  65.         switch (id) {
  66.         case R.id.right_button:
  67.             Logger.d(TAG,"rightbutton");
  68.             break;
  69.         }

  70.     }

  71.     @Override
  72.     public void onItemClick(AdapterView<?> parent, View view, int position,
  73.             long id) {
  74.         Logger.d(TAG,"onItemClick:"+position);

  75.     }
  76.     
  77.     /**
  78.      * 为ListView填充数据
  79.      * @param date
  80.      * @return
  81.      */
  82.     private List<CarBrand> filledData(String [] date){
  83.         List<CarBrand> mBrandList = new ArrayList<CarBrand>();
  84.         for(int i=0; i<date.length; i++){
  85.             CarBrand carBrand = new CarBrand();
  86.             carBrand.mBrandName=date[i];
  87.             //汉字转换成拼音
  88.             String pinyin = characterParser.getSelling(date[i]);
  89.             String sortString = pinyin.substring(0, 1).toUpperCase();
  90.             
  91.             // 正则表达式,判断首字母是否是英文字母
  92.             if(sortString.matches("[A-Z]")){
  93.                 carBrand.mSortLetters=sortString.toUpperCase();
  94.             }else{
  95.                 carBrand.mSortLetters="#";
  96.             }
  97.             ArrayList<CarStyle> mStyleList = new ArrayList<CarStyle>();
  98.             for(int j=0;j<=i;j++){
  99.                 CarStyle carStyle=new CarStyle();
  100.                 carStyle.mStyleName=date[i]+"201"+j;
  101.                 ArrayList<String> mModelList = new ArrayList<String>();
  102.                 for(int k=0;k<=j;k++){
  103.                     mModelList.add(carStyle.mStyleName+":"+"手动款");
  104.                 }
  105.                 carStyle.mModelList=mModelList;
  106.                 mStyleList.add(carStyle);
  107.             }
  108.             carBrand.mCarStyleList=mStyleList;
  109.             mBrandList.add(carBrand);
  110.         }
  111.         return mBrandList;
  112.         
  113.     }
  114. }

      6.大功告成了,来看一下显示的效果吧。



源码又重新整理一下放在github上。














      
阅读(34019) | 评论(17) | 转发(1) |
给主人留下些什么吧!~~

云少嘎嘎嘎2015-01-19 09:51:30

yytyxj:我是说着CarBrandAdapter里面的getchildcount(),我看你返回的是list的大小,但是我看你getchildview是expandablelistview.你的gridview是第三级啊。

没错呀,CarBrandAdapter有N个child,每个child都是一个新的expandablelistview,这个新的expandablelistview才只有一个是gridView的child。理解没?

回复 | 举报

yytyxj2015-01-16 16:47:05

云少嘎嘎嘎:我的是第二级的只有一个child,这个child是一个gridView

我是说着CarBrandAdapter里面的getchildcount(),我看你返回的是list的大小,但是我看你getchildview是expandablelistview.你的gridview是第三级啊。

回复 | 举报

云少嘎嘎嘎2015-01-16 14:34:34

yytyxj:楼主你的第一个adapter的childcount()里面返回不应该是1吗?每个二级是一个expandablelistview,可是我看你的不是啊,我在做的时候写的是1,但是二级点不了请问你有碰到这个问题吗

我的是第二级的只有一个child,这个child是一个gridView

回复 | 举报

yytyxj2015-01-16 12:01:49

楼主你的第一个adapter的childcount()里面返回不应该是1吗?每个二级是一个expandablelistview,可是我看你的不是啊,我在做的时候写的是1,但是二级点不了请问你有碰到这个问题吗

云少嘎嘎嘎2015-01-14 09:56:32

zero_ci:楼主您好   参照您的实例我也写了一个没有达到预期的效果 不知道是否方便留下源码呢· zero_ci@sina.cn  谢谢!

这是公司项目里的代码,我真不能全拿出来。我的文章哪里写的不够明白吗?有问题咱们可以一起探讨一下。

回复 | 举报