如果在此之前没接触过listview多条目布局的,可以建议先看下我之前写的博文:
好了,言归正传,对于可折叠的listview,很多小伙伴们用的都是网上的开源控件expandablelistview,但是还是那句话第三方控件适合外包快速开发,有些自己项目是自己公司的,然后领导要求尽量不使用第三方控件。所以写这个代码仅供大家借鉴参考。
先附上效果图:
概述:要想实现expandablelistview效果,其实也就是自定义adapter,逻辑基本都在adapter里。准备工作1:首先要想实现这种效果就必须用到adapter的多条目(不会的话学会多条目再看本文章)。2:然后每一个item下面的listview是自定义的(listview嵌套listview,不用多说了吧)。
如图1所示,每一个item都是一个listview,然后自己
如图2所示,每一个子item都是一个listview,然后这是子listview的item;
标题1 和下面的name0,name1都是item,这就是adapter多条目布局;
好了重新捋一下思路:最外层是一个listview,然后里面每个item也是一个listview(自定义listview,涉及嵌套问题)。然后在子Item的adapter里根据Bean的flug判断是否是展开还是闭合。最后应该监听一下子listview的第0个Item(标题0,标题1,标题2…),维护flug字段。
上代码
class ATest{
private String name;//标题名字
private String flug;//判断该item是否展开
public String getFlug() {
return flug;
}
public void setFlug(String flug) {
this.flug = flug;
}
private List<BTest> list;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<BTest> getList() {
return list;
}
public void setList(List<BTest> list) {
this.list = list;
}
}
class BTest{
private String name;//子Item的名称(name0,name1.....)
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
然后模拟假数据:
aTestList = new ArrayList<>();
for(int i = 0;i < 10;i++){
ATest aTest = new ATest();
aTest.setName("标题" + i);
List<BTest> bTests = new ArrayList<>();
for(int j = 0;j < 5;j++){
BTest bTest = new BTest();
bTest.setName("name" + j);
bTest.setAge("age" + j);
bTests.add(bTest);
}
aTest.setList(bTests);
aTestList.add(aTest);
}
接下来是重点adapter:
class AAdapter extends BaseAdapter{
private List<ATest> aTestList;
public AAdapter(List<ATest> aTestList) {
this.aTestList = aTestList;
}
@Override
public int getCount() {
return aTestList.size();
}
@Override
public Object getItem(int position) {
return aTestList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AViewHolder aViewHolder;
if(convertView == null){
convertView = View.inflate(parent.getContext(), R.layout.stickys_listview, null);
aViewHolder = new AViewHolder();
aViewHolder.listView = (MyListview) convertView.findViewById(R.id.mylistview);
convertView.setTag(aViewHolder);
}else{
aViewHolder = (AViewHolder) convertView.getTag();
}
final BTestAdapter bTestAdapter = new BTestAdapter(aTestList, position);
aViewHolder.listView.setAdapter(bTestAdapter);
return convertView;
}
class AViewHolder {
public MyListview listView;
}
}
上述代码是最外层listview的adapter;
接下来就是子listview的adapter了,首先我们可以看到图2所示,第0个和其他的内部颜色是不一样的(实际开发中布局也是不一样的)。所以我们必须要用到多布局(0和其他,共两种布局)。
下述代码是子listview的adapter:
class BTestAdapter extends BaseAdapter{
private static final int TYPE_NUMBER1 = 0;
private static final int TYPE_NUMBER2 = 1;
// private String title_String;
// private String flug = "0";
private List<ATest> aList;
private int parentPosition;
public BTestAdapter(List<ATest> aList, int position) {
this.aList = aList;
this.parentPosition = position;
}
@Override
public int getCount() {
return aList.get(parentPosition).getList().size() + 1;
}
@Override
public Object getItem(int position) {
return aList.get(parentPosition).getList().get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
if(position == 0){
return TYPE_NUMBER1;
}else{
return TYPE_NUMBER2;
}
}
@Override
public View getView(final int position, View convertView,final ViewGroup parent) {
BTestViewHolder1 bTestViewHolder1 = null;
BTestViewHolder2 bTestViewHolder2 = null;
int type = getItemViewType(position);
if(convertView == null){
switch (type){
case TYPE_NUMBER1:{
convertView = View.inflate(parent.getContext(), R.layout.expand_item1, null);
bTestViewHolder1 = new BTestViewHolder1();
bTestViewHolder1.text_title = (TextView) convertView.findViewById(R.id.text_title);
convertView.setTag(bTestViewHolder1);
break;
}
case TYPE_NUMBER2:{
convertView = View.inflate(parent.getContext(), R.layout.expand_item2, null);
bTestViewHolder2 = new BTestViewHolder2();
bTestViewHolder2.text_name = (TextView) convertView.findViewById(R.id.text_name);
bTestViewHolder2.text_age = (TextView) convertView.findViewById(R.id.text_age);
bTestViewHolder2.linearlayout = (LinearLayout)convertView.findViewById(R.id.linearlayout);
convertView.setTag(bTestViewHolder2);
break;
}
}
}else{
switch (type){
case TYPE_NUMBER1:{
bTestViewHolder1 = (BTestViewHolder1) convertView.getTag();
break;
}
case TYPE_NUMBER2:{
bTestViewHolder2 = (BTestViewHolder2) convertView.getTag();
break;
}
}
}
final ATest aTest = aList.get(parentPosition);
switch (type){
case TYPE_NUMBER1:{
bTestViewHolder1.text_title.setText(aTest.getName());
bTestViewHolder1.text_title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(aTest.getFlug() == null || aTest.getFlug() == "0"){
aTest.setFlug("1");
}else{
aTest.setFlug("0");
}
notifyDataSetChanged();
}
});
break;
}
case TYPE_NUMBER2:{
if("1".equals(aTest.getFlug())){
bTestViewHolder2.text_name.setVisibility(View.VISIBLE);
bTestViewHolder2.text_age.setVisibility(View.VISIBLE);
bTestViewHolder2.text_name.setText(aTest.getList().get(position - 1).getName());
bTestViewHolder2.text_age.setText(aTest.getList().get(position - 1).getAge());
bTestViewHolder2.linearlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* TODO 处理逻辑
*/
Toast.makeText(parent.getContext(), parentPosition + " + " + position, Toast.LENGTH_SHORT).show();
}
});
}else{
bTestViewHolder2.text_name.setVisibility(View.GONE);
bTestViewHolder2.text_age.setVisibility(View.GONE);
}
break;
}
}
return convertView;
}
class BTestViewHolder1{
public TextView text_title;
}
class BTestViewHolder2{
public TextView text_name;
public TextView text_age;
public LinearLayout linearlayout;
}
}
将下述代码摘出,说明重要性。该代码是监听子listview的第0个元素,然后维护flug字段;
bTestViewHolder1.text_title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(aTest.getFlug() == null || aTest.getFlug() == "0"){
aTest.setFlug("1");
}else{
aTest.setFlug("0");
}
notifyDataSetChanged();
}
});
注意:里面的TYPE_NUMBER1 一定要从0开始。要不会报数组越界错误。
思路很重要,内部代码都是浮云….!小伙伴们可以多看一下思路。
好了 大功告成了! 有点复杂。一人一思路,其实根据数据Bean结构不同,adapter的书写是不一样的。
欢迎各位小伙伴们指正。