教你用两层ExpandableListView嵌套GridView实现三级展示界面
dqwe7108
8年前
<p>写在前面:</p> <p>最近项目中使用一个三级展示列表,要求第一级和第二季都可以折叠,并有不同的图标变换,第三层展示数据,可点击。经过一盘折腾,算是实现了,效果就在下面:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/86f504a0f2c804633b8c406721668ab1.gif"></p> <p>这里写图片描述</p> <p>思路:</p> <p>最外层是ExpandableListView,它的子视图又是一个ExpandableListView,这个子ExpandableListView的子视图是我们的第三级展示界面,也就是GridView。分析清楚了之后,写起来就简单了,下面说说遇到的问题。</p> <p>1,最外层的ExpandableListView嵌套的子ExpandableListView必须解决显示不全的问题。</p> <p>2,在解决了上面的问题后,会发现,最里层的GridView如果不做处理也会出现显示不全的问题。</p> <p>3,当上述两个问题都解决了之后,如果我们把最外层和第二层的ExpandableListView都使用自定义的ExpandableListView时,任然会出现子ExpandableListView显示不全问题,所以,这两个ExpandableListView不能使用同一个。</p> <p>思路和问题都搞定了,我们现在看看主要的类代码:</p> <p>这是MainActivity.java初始化方法代码</p> <pre> <code class="language-java">public class MainActivity extends AppCompatActivity { private ExpandableListView expandableListView; private List<String> groupList = new ArrayList<>(); private ParentExpandAdapter parentExpandAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initData(); initView(); } private void initData() { for (int i = 0; i < 11; i++) { groupList.add("Android工程师之版权 " + (1 + i)); } } private void initView() { setContentView(R.layout.activity_main); expandableListView = (ExpandableListView) findViewById(R.id.expand_main); parentExpandAdapter = new ParentExpandAdapter(MainActivity.this, groupList); expandableListView.setAdapter(parentExpandAdapter); // 被展开组的监听 expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() { @Override public void onGroupExpand(int groupPosition) { // 保证每次只有一个组是展开状态 for (int i = 0; i < parentExpandAdapter.getGroupCount(); i++) { if (i != groupPosition) { expandableListView.collapseGroup(i); } } } }); } }</code></pre> <p>初始化了ExpandableListView,并设置了每次只展开一个组监听。</p> <p>ParentExpandAdapter.java代码</p> <pre> <code class="language-java">public class ParentExpandAdapter extends BaseExpandableListAdapter { private Context context; private List<String> parentList; public ParentExpandAdapter(Context context, List<String> parentList) { this.context = context; this.parentList = parentList; } @Override public int getGroupCount() { return parentList.size(); } @Override public int getChildrenCount(int groupPosition) { return 5; } @Override public Object getGroup(int groupPosition) { return parentList.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return parentList.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 false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { ParentViewHolder parentHolder; if (null == convertView) { parentHolder = new ParentViewHolder(); convertView = View.inflate(context, R.layout.fire_tab_parent_group_item, null); parentHolder.parentTv = (TextView) convertView.findViewById(R.id.parentGroupTV); parentHolder.parentIv = (ImageView) convertView.findViewById(R.id.iv_parent_group_indicator); convertView.setTag(parentHolder); } else { parentHolder = (ParentViewHolder) convertView.getTag(); } parentHolder.parentTv.setText(parentList.get(groupPosition)); if (isExpanded) { parentHolder.parentIv.setImageResource(R.drawable.icon_arrow_up); } else { parentHolder.parentIv.setImageResource(R.drawable.icon_arrow_down); } return convertView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { ChildViewHolder childHolder; if (null == convertView) { childHolder = new ChildViewHolder(); convertView = View.inflate(context, R.layout.item_expand_group_child, null); childHolder.childExpandLv = (ExpandableListView) convertView.findViewById(R.id.expand_group_item); convertView.setTag(childHolder); } else { childHolder = (ChildViewHolder) convertView.getTag(); } childHolder.childExpandLv.setAdapter(new ChildExpandAdapter(context, parentList.subList(3, 7))); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } class ParentViewHolder { TextView parentTv; ImageView parentIv; } class ChildViewHolder { // 二级视图又是一个ExpandableListView ExpandableListView childExpandLv; } }</code></pre> <p>因为一级只有一个TextView和一个ImageView,比较简单。因为子视图又是一个ExpandableListView,所以这里设置了监听,保证每次只展开一个分组,如果没有这个需求当然可以不设置,另外就是通过判断增加了指示箭头。</p> <p>二级适配器ChildExpandAdapter.java代码</p> <pre> <code class="language-java">public class ChildExpandAdapter extends BaseExpandableListAdapter { private Context context; private List<String> parentList; public ChildExpandAdapter(Context context, List<String> parentList) { this.context = context; this.parentList = parentList; } @Override public int getGroupCount() { return parentList.size(); } @Override public int getChildrenCount(int groupPosition) { return 1; } @Override public Object getGroup(int groupPosition) { return parentList.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return parentList.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 false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { ParentViewHolder parentHolder; if (null == convertView) { parentHolder = new ParentViewHolder(); convertView = View.inflate(context, R.layout.fire_tab_child_group_item, null); parentHolder.parentTv = (TextView) convertView.findViewById(R.id.childGroupTV); parentHolder.parentIv = (ImageView) convertView.findViewById(R.id.iv_fire_tab_child_indicator); convertView.setTag(parentHolder); } else { parentHolder = (ParentViewHolder) convertView.getTag(); } parentHolder.parentTv.setText(parentList.get(groupPosition)); if (isExpanded) { parentHolder.parentIv.setImageResource(R.drawable.icon_arrow_up); } else { parentHolder.parentIv.setImageResource(R.drawable.icon_arrow_down); } return convertView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { ChildViewHolder childHolder; if (null == convertView) { childHolder = new ChildViewHolder(); convertView = View.inflate(context, R.layout.item_child_child, null); childHolder.gridView = (GridView) convertView.findViewById(R.id.gv_child_child_item); convertView.setTag(childHolder); } else { childHolder = (ChildViewHolder) convertView.getTag(); } childHolder.gridView.setAdapter(new GridViewAdapter(context, getList())); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } class ParentViewHolder { TextView parentTv; ImageView parentIv; } class ChildViewHolder { // 此ExpandableListView的ClildView又是一个GridView GridView gridView; } private List<String> getList() { List<String> list = new ArrayList<>(); for (int i = 0; i < 50; i++) { list.add("android " + i); } return list; } }</code></pre> <p>根据我们前面的分析,这里的二级ChildView是一个GridView,这里做了初始化,并设置了点击监听。</p> <p>再来看看最重要的代码——自定义ExpandableListView</p> <pre> <code class="language-java">public class CustomExpandableListview extends ExpandableListView { public CustomExpandableListview(Context context) { super(context); } public CustomExpandableListview(Context context, AttributeSet attrs) { super(context, attrs); } public CustomExpandableListview(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }</code></pre> <p>这里通过测量,计算出子ExpandableListView的高度,解决了显示不全问题,GridView也是一样的。</p> <p> </p> <p> </p> <p>来自:http://www.jianshu.com/p/a778064d1701</p> <p> </p>