├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── baobing │ │ └── cc │ │ └── expandlistviewwithcheckbox │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── baobing │ │ │ └── cc │ │ │ └── expandlistviewwithcheckbox │ │ │ ├── CustomExpandableListView.java │ │ │ ├── ExpandListViewAdapter.java │ │ │ ├── FirstModel.java │ │ │ ├── MainActivity.java │ │ │ ├── SecondModel.java │ │ │ └── ThirdModel.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── item_expand_lv_first.xml │ │ ├── item_expand_lv_second.xml │ │ └── item_expand_lv_third.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── baobing │ └── cc │ └── expandlistviewwithcheckbox │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##ExpandableListView三级列表实现(带CheckBox全选功能) 2 | [csdn文章链接](http://blog.csdn.net/bigname22/article/details/77919025 "csdn文章链接") 3 | 4 | **动动小指头 star☆ 支持一下^_^** 5 | 6 | 场景:多选车辆,并且在同一个页面实现。 7 | *(数据结构:公司-线路-车辆三层)* 8 | 9 | 那么第一时间想到的只能是 **ExpandableListView** 这个神奇的组件了,但常规就两层,那要怎么办?ExpandableListView嵌套ExpandableListView呗! 10 | 11 | 然后翻阅了一下网上的案例。嗯嗯,很好,案例还算多,总结使用时最关键的两点是: 12 | 13 | 1.第一个ExpandableListView中的getChildCount()要返回 1;因为这个1是用来装第二个ExpandableListView的。 14 | 2.第一个ExpandableListView中的getChildView()要返回ExpandableListView. 15 | 16 | 但网上没有结合三级结合checkbox的案例,所以又的多动下脑子了。 17 | 18 | 继续讲,第一个ExpandableListView的GroupItem对应的数据是公司,ChildItem是第二个ExpandableListView,他的GroupItem对应的数据是线路,ChildItem是车辆。也就是说,第一个关心的是公司,第二个关心的是线路、车辆。 19 | 20 | 效果图打头阵了: 21 | ![这里写图片描述](http://img.blog.csdn.net/20170909232239057?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmlnbmFtZTIy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 22 | 23 | 下面贴我的代码: 24 | 首先设计数据源:FirstModel,SecondModel,ThirdModel。分别代表第一、二、三层数据,上级当然也是包含下级的。(demo在下方贴) 25 | 接下来主要说最最主要的适配器: 26 | 27 | ``` 28 | 29 | /** 30 | * author:Created by LiangSJ 31 | * date: 2017/9/7. 32 | * description:牛逼的适配器 33 | */ 34 | 35 | public class ExpandListViewAdapter extends BaseExpandableListAdapter { 36 | private List mListData; 37 | private LayoutInflater mInflate; 38 | private Context context; 39 | 40 | public ExpandListViewAdapter(List mListData, Context context) { 41 | this.mListData = mListData; 42 | this.context = context; 43 | this.mInflate = LayoutInflater.from(context); 44 | } 45 | 46 | @Override 47 | public int getGroupCount() { 48 | return mListData.size(); 49 | } 50 | 51 | @Override 52 | public int getChildrenCount(int groupPosition) { 53 | //关键的一步,别侧漏 54 | return 1; 55 | } 56 | 57 | @Override 58 | public Object getGroup(int groupPosition) { 59 | return mListData.get(groupPosition); 60 | } 61 | 62 | @Override 63 | public Object getChild(int groupPosition, int childPosition) { 64 | return mListData.get(groupPosition).getListSecondModel().get(childPosition); 65 | } 66 | 67 | @Override 68 | public long getGroupId(int groupPosition) { 69 | return groupPosition; 70 | } 71 | 72 | @Override 73 | public long getChildId(int groupPosition, int childPosition) { 74 | return childPosition; 75 | } 76 | 77 | @Override 78 | public boolean hasStableIds() { 79 | return false; 80 | } 81 | 82 | @Override 83 | public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 84 | //正常流程,第一层的逻辑 85 | FirstHolder holder = null; 86 | if (convertView == null) { 87 | holder = new FirstHolder(); 88 | convertView = mInflate.inflate(R.layout.item_expand_lv_first, parent, false); 89 | holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 90 | holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 91 | convertView.setTag(holder); 92 | } else { 93 | holder = (FirstHolder) convertView.getTag(); 94 | } 95 | holder.tv.setText(mListData.get(groupPosition).getTitle()); 96 | final FirstHolder finalHolder = holder; 97 | /** 98 | checkbox关键点,第一层checkbox的选中状态监听, 99 | 如果勾选中,则把其下的第二层以及第三层都选上,否则相反。 100 | */ 101 | finalHolder.cb.setOnClickListener(new View.OnClickListener() { 102 | @Override 103 | public void onClick(View v) { 104 | boolean isChecked = finalHolder.cb.isChecked(); 105 | Log.d("bigname", "onclick: first:" + groupPosition + "," + isChecked); 106 | mListData.get(groupPosition).setCheck(isChecked); 107 | for (int i = 0; i < mListData.get(groupPosition).getListSecondModel().size(); i++) { 108 | SecondModel secondModel = mListData.get(groupPosition).getListSecondModel().get(i); 109 | secondModel.setCheck(isChecked); 110 | for (int j = 0; j < secondModel.getListThirdModel().size(); j++) { 111 | ThirdModel thirdModel = secondModel.getListThirdModel().get(j); 112 | thirdModel.setCheck(isChecked); 113 | } 114 | } 115 | notifyDataSetChanged(); 116 | } 117 | }); 118 | /**通过isCheck属性控制checkbox 119 | 的选中状态,2,3层同理*/ 120 | finalHolder.cb.setChecked(mListData.get(groupPosition).isCheck()); 121 | return convertView; 122 | } 123 | 124 | @Override 125 | public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { 126 | //关键的第二步,返回第二个expandablelistview 127 | CustomExpandableListView lv = ((CustomExpandableListView) convertView); 128 | if (convertView == null) { 129 | lv = new CustomExpandableListView(context); 130 | } 131 | SecondAdapter secondAdapter = new SecondAdapter(context, mListData.get(groupPosition).getListSecondModel()); 132 | lv.setAdapter(secondAdapter); 133 | return lv; 134 | } 135 | 136 | @Override 137 | public boolean isChildSelectable(int groupPosition, int childPosition) { 138 | return false; 139 | } 140 | /* 141 | * 第二层的适配器,这里更是重点,圈起来,要考! 142 | * */ 143 | class SecondAdapter extends BaseExpandableListAdapter { 144 | Context context; 145 | LayoutInflater inflater; 146 | List listSecondModel; 147 | 148 | public SecondAdapter(Context context,List listSecondModel) { 149 | this.context = context; 150 | this.listSecondModel = listSecondModel; 151 | inflater = LayoutInflater.from(context); 152 | } 153 | 154 | @Override 155 | public int getGroupCount() { 156 | int size = listSecondModel.size(); 157 | Log.d("bigname", "getGroupCount: "+size); 158 | return size; 159 | } 160 | 161 | @Override 162 | public int getChildrenCount(int groupPosition) { 163 | return listSecondModel.get(groupPosition).getListThirdModel().size(); 164 | } 165 | 166 | @Override 167 | public Object getGroup(int groupPosition) { 168 | return listSecondModel.get(groupPosition); 169 | } 170 | 171 | @Override 172 | public Object getChild(int groupPosition, int childPosition) { 173 | return listSecondModel.get(groupPosition).getListThirdModel().get(childPosition); 174 | } 175 | 176 | @Override 177 | public long getGroupId(int groupPosition) { 178 | return groupPosition; 179 | } 180 | 181 | @Override 182 | public long getChildId(int groupPosition, int childPosition) { 183 | return childPosition; 184 | } 185 | 186 | @Override 187 | public boolean hasStableIds() { 188 | return false; 189 | } 190 | 191 | @Override 192 | public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 193 | //第二层逻辑 194 | SecondHolder holder = null; 195 | if (convertView == null) { 196 | holder = new SecondHolder(); 197 | convertView = mInflate.inflate(R.layout.item_expand_lv_second, parent, false); 198 | holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 199 | holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 200 | convertView.setTag(holder); 201 | } else { 202 | holder = (SecondHolder) convertView.getTag(); 203 | } 204 | holder.tv.setText(listSecondModel.get(groupPosition).getTitle()); 205 | final SecondHolder secondHolder = holder; 206 | /** 207 | * checkbox关键点,第一层checkbox的选中状态监听, 208 | * 如果勾选中,则把其下的第三层都选上,否则相反。 209 | */ 210 | secondHolder.cb.setOnClickListener(new View.OnClickListener() { 211 | @Override 212 | public void onClick(View v) { 213 | boolean isChecked = secondHolder.cb.isChecked(); 214 | Log.d("bigname", "onCheckedChanged: second:" + groupPosition + "," + isChecked); 215 | listSecondModel.get(groupPosition).setCheck(isChecked); 216 | for (int i = 0; i < listSecondModel.get(groupPosition).getListThirdModel().size(); i++) { 217 | ThirdModel thirdModel = listSecondModel.get(groupPosition).getListThirdModel().get(i); 218 | thirdModel.setCheck(isChecked); 219 | } 220 | notifyDataSetChanged(); 221 | } 222 | }); 223 | secondHolder.cb.setChecked(listSecondModel.get(groupPosition).isCheck()); 224 | return convertView; 225 | } 226 | 227 | @Override 228 | public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { 229 | ThirdHolder holder = null; 230 | if (convertView == null) { 231 | holder = new ThirdHolder(); 232 | convertView = mInflate.inflate(R.layout.item_expand_lv_third, parent, false); 233 | holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 234 | holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 235 | convertView.setTag(holder); 236 | } else { 237 | holder = (ThirdHolder) convertView.getTag(); 238 | } 239 | holder.tv.setText(listSecondModel.get(groupPosition).getListThirdModel().get(childPosition).getTitle()); 240 | final ThirdHolder thirdHolder = holder; 241 | thirdHolder.cb.setOnClickListener(new View.OnClickListener() { 242 | @Override 243 | public void onClick(View v) { 244 | boolean isChecked = thirdHolder.cb.isChecked(); 245 | Log.d("bigname", "onCheckedChanged: third:" + groupPosition + "," + isChecked); 246 | listSecondModel.get(groupPosition).getListThirdModel().get(childPosition).setCheck(isChecked); 247 | } 248 | }); 249 | thirdHolder.cb.setChecked(listSecondModel.get(groupPosition).getListThirdModel().get(childPosition).isCheck()); 250 | return convertView; 251 | } 252 | 253 | 254 | @Override 255 | public boolean isChildSelectable(int groupPosition, int childPosition) { 256 | return true; 257 | } 258 | } 259 | 260 | 261 | class FirstHolder { 262 | TextView tv; 263 | CheckBox cb; 264 | } 265 | 266 | class SecondHolder { 267 | TextView tv; 268 | CheckBox cb; 269 | } 270 | 271 | class ThirdHolder{ 272 | TextView tv; 273 | CheckBox cb; 274 | } 275 | } 276 | 277 | ``` 278 | 实现三级联动是很简单的,但是再加入checkbox的时候有一点小问题出现。我考虑用数据源中的isCheck的布尔值属性取专门控制checkbox的状态,**①***然后当选中checkbox时,要把其对应的第二、三层的数据源的isCheck属性设置为同样的状态,然后执行notifydatachange()就可以了*。 279 | 这里有个问题就是:你得监听到checkbox的状态改变,然后才能执行①中的操作。起初我使用了的监听手法时checkbox.setOnCheckChangeListener(),这会导致一些问题,像回收机制出现时都会被监到,从而①中的代码又被不按套路的执行一遍。所以后来使用onClickListener()来监听勾选状态的改变,问题也就迎刃而解。 280 | 再总结,无论是三级还是二级、一级的列表,都可以使用在数据源中利用boolean属性专门控制其勾选状态;三级和二级要实现上下级勾选联动的功能思路也无非就是改变数据源中的boolean属性再重绘列表。 281 | 282 | 注意:checkbox会强焦点导致列表无法正常展开,把focus设为false就好了。 283 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.baobing.cc.expandlistviewwithcheckbox" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.3.1' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | } 31 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\software\sdk\androidsdk\sdk-for-studio/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/baobing/cc/expandlistviewwithcheckbox/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.baobing.cc.expandlistviewwithcheckbox", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/baobing/cc/expandlistviewwithcheckbox/CustomExpandableListView.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ExpandableListView; 6 | 7 | /** 8 | * author:Created by LiangSJ 9 | * date: 2017/8/21. 10 | * description:解决,expandablelistview嵌套冲突问题 11 | */ 12 | 13 | public class CustomExpandableListView extends ExpandableListView{ 14 | public CustomExpandableListView(Context context) { 15 | super(context); 16 | } 17 | 18 | public CustomExpandableListView(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | public CustomExpandableListView(Context context, AttributeSet attrs, int defStyleAttr) { 23 | super(context, attrs, defStyleAttr); 24 | } 25 | 26 | public CustomExpandableListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 27 | super(context, attrs, defStyleAttr, defStyleRes); 28 | } 29 | @Override 30 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 31 | // 解决显示不全的问题 32 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2 33 | , MeasureSpec.AT_MOST); 34 | super.onMeasure(widthMeasureSpec, expandSpec); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/baobing/cc/expandlistviewwithcheckbox/ExpandListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.BaseExpandableListAdapter; 9 | import android.widget.CheckBox; 10 | import android.widget.TextView; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * author:Created by LiangSJ 16 | * date: 2017/9/7. 17 | * description:? 18 | */ 19 | 20 | public class ExpandListViewAdapter extends BaseExpandableListAdapter { 21 | private List mListData; 22 | private LayoutInflater mInflate; 23 | private Context context; 24 | 25 | public ExpandListViewAdapter(List mListData, Context context) { 26 | this.mListData = mListData; 27 | this.context = context; 28 | this.mInflate = LayoutInflater.from(context); 29 | } 30 | 31 | @Override 32 | public int getGroupCount() { 33 | return mListData.size(); 34 | } 35 | 36 | @Override 37 | public int getChildrenCount(int groupPosition) { 38 | return 1; 39 | } 40 | 41 | @Override 42 | public Object getGroup(int groupPosition) { 43 | return mListData.get(groupPosition); 44 | } 45 | 46 | @Override 47 | public Object getChild(int groupPosition, int childPosition) { 48 | return mListData.get(groupPosition).getListSecondModel().get(childPosition); 49 | } 50 | 51 | @Override 52 | public long getGroupId(int groupPosition) { 53 | return groupPosition; 54 | } 55 | 56 | @Override 57 | public long getChildId(int groupPosition, int childPosition) { 58 | return childPosition; 59 | } 60 | 61 | @Override 62 | public boolean hasStableIds() { 63 | return false; 64 | } 65 | 66 | @Override 67 | public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 68 | FirstHolder holder = null; 69 | if (convertView == null) { 70 | holder = new FirstHolder(); 71 | convertView = mInflate.inflate(R.layout.item_expand_lv_first, parent, false); 72 | holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 73 | holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 74 | convertView.setTag(holder); 75 | } else { 76 | holder = (FirstHolder) convertView.getTag(); 77 | } 78 | holder.tv.setText(mListData.get(groupPosition).getTitle()); 79 | final FirstHolder finalHolder = holder; 80 | finalHolder.cb.setOnClickListener(new View.OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | boolean isChecked = finalHolder.cb.isChecked(); 84 | Log.d("bigname", "onclick: first:" + groupPosition + "," + isChecked); 85 | mListData.get(groupPosition).setCheck(isChecked); 86 | for (int i = 0; i < mListData.get(groupPosition).getListSecondModel().size(); i++) { 87 | SecondModel secondModel = mListData.get(groupPosition).getListSecondModel().get(i); 88 | secondModel.setCheck(isChecked); 89 | for (int j = 0; j < secondModel.getListThirdModel().size(); j++) { 90 | ThirdModel thirdModel = secondModel.getListThirdModel().get(j); 91 | thirdModel.setCheck(isChecked); 92 | } 93 | } 94 | notifyDataSetChanged(); 95 | } 96 | }); 97 | finalHolder.cb.setChecked(mListData.get(groupPosition).isCheck()); 98 | return convertView; 99 | } 100 | 101 | @Override 102 | public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { 103 | // SecondHolder holder = null; 104 | // if (convertView == null) { 105 | // holder = new SecondHolder(); 106 | // convertView = mInflate.inflate(R.layout.item_expand_lv_second, parent, false); 107 | // holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 108 | // holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 109 | // convertView.setTag(holder); 110 | // } else { 111 | // holder = (SecondHolder) convertView.getTag(); 112 | // } 113 | // holder.tv.setText(mListData.get(groupPosition).getListSecondModel().get(childPosition).getTitle()); 114 | // holder.cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 115 | // @Override 116 | // public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 117 | // mListData.get(groupPosition).getListSecondModel().get(childPosition).setCheck(isChecked); 118 | // } 119 | // }); 120 | // holder.cb.setChecked(mListData.get(groupPosition).getListSecondModel().get(childPosition).isCheck()); 121 | // return convertView; 122 | // Object object= (Object) getChild(groupPosition, childPosition); 123 | // CustomExpandableListView subObjects= () convertView;; 124 | // if (convertView==null) { 125 | // subObjects= new CustomExpandableListView(activity); 126 | // } 127 | // Adapter2 adapter= new Adapter2(activity, object); 128 | // subObjects.setAdapter(adapter); 129 | // 130 | // return subObjects 131 | CustomExpandableListView lv = ((CustomExpandableListView) convertView); 132 | if (convertView == null) { 133 | lv = new CustomExpandableListView(context); 134 | } 135 | SecondAdapter secondAdapter = new SecondAdapter(context, mListData.get(groupPosition).getListSecondModel()); 136 | lv.setAdapter(secondAdapter); 137 | return lv; 138 | } 139 | 140 | @Override 141 | public boolean isChildSelectable(int groupPosition, int childPosition) { 142 | return false; 143 | } 144 | /* 145 | * 第二层的适配器 146 | * */ 147 | class SecondAdapter extends BaseExpandableListAdapter { 148 | Context context; 149 | LayoutInflater inflater; 150 | List listSecondModel; 151 | 152 | public SecondAdapter(Context context,List listSecondModel) { 153 | this.context = context; 154 | this.listSecondModel = listSecondModel; 155 | inflater = LayoutInflater.from(context); 156 | } 157 | 158 | @Override 159 | public int getGroupCount() { 160 | int size = listSecondModel.size(); 161 | Log.d("bigname", "getGroupCount: "+size); 162 | return size; 163 | } 164 | 165 | @Override 166 | public int getChildrenCount(int groupPosition) { 167 | return listSecondModel.get(groupPosition).getListThirdModel().size(); 168 | } 169 | 170 | @Override 171 | public Object getGroup(int groupPosition) { 172 | return listSecondModel.get(groupPosition); 173 | } 174 | 175 | @Override 176 | public Object getChild(int groupPosition, int childPosition) { 177 | return listSecondModel.get(groupPosition).getListThirdModel().get(childPosition); 178 | } 179 | 180 | @Override 181 | public long getGroupId(int groupPosition) { 182 | return groupPosition; 183 | } 184 | 185 | @Override 186 | public long getChildId(int groupPosition, int childPosition) { 187 | return childPosition; 188 | } 189 | 190 | @Override 191 | public boolean hasStableIds() { 192 | return false; 193 | } 194 | 195 | @Override 196 | public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 197 | SecondHolder holder = null; 198 | if (convertView == null) { 199 | holder = new SecondHolder(); 200 | convertView = mInflate.inflate(R.layout.item_expand_lv_second, parent, false); 201 | holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 202 | holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 203 | convertView.setTag(holder); 204 | } else { 205 | holder = (SecondHolder) convertView.getTag(); 206 | } 207 | holder.tv.setText(listSecondModel.get(groupPosition).getTitle()); 208 | final SecondHolder secondHolder = holder; 209 | secondHolder.cb.setOnClickListener(new View.OnClickListener() { 210 | @Override 211 | public void onClick(View v) { 212 | boolean isChecked = secondHolder.cb.isChecked(); 213 | Log.d("bigname", "onCheckedChanged: second:" + groupPosition + "," + isChecked); 214 | listSecondModel.get(groupPosition).setCheck(isChecked); 215 | for (int i = 0; i < listSecondModel.get(groupPosition).getListThirdModel().size(); i++) { 216 | ThirdModel thirdModel = listSecondModel.get(groupPosition).getListThirdModel().get(i); 217 | thirdModel.setCheck(isChecked); 218 | } 219 | notifyDataSetChanged(); 220 | } 221 | }); 222 | secondHolder.cb.setChecked(listSecondModel.get(groupPosition).isCheck()); 223 | return convertView; 224 | } 225 | 226 | @Override 227 | public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { 228 | ThirdHolder holder = null; 229 | if (convertView == null) { 230 | holder = new ThirdHolder(); 231 | convertView = mInflate.inflate(R.layout.item_expand_lv_third, parent, false); 232 | holder.tv = ((TextView) convertView.findViewById(R.id.tv)); 233 | holder.cb = ((CheckBox) convertView.findViewById(R.id.cb)); 234 | convertView.setTag(holder); 235 | } else { 236 | holder = (ThirdHolder) convertView.getTag(); 237 | } 238 | holder.tv.setText(listSecondModel.get(groupPosition).getListThirdModel().get(childPosition).getTitle()); 239 | final ThirdHolder thirdHolder = holder; 240 | thirdHolder.cb.setOnClickListener(new View.OnClickListener() { 241 | @Override 242 | public void onClick(View v) { 243 | boolean isChecked = thirdHolder.cb.isChecked(); 244 | Log.d("bigname", "onCheckedChanged: third:" + groupPosition + "," + isChecked); 245 | listSecondModel.get(groupPosition).getListThirdModel().get(childPosition).setCheck(isChecked); 246 | } 247 | }); 248 | thirdHolder.cb.setChecked(listSecondModel.get(groupPosition).getListThirdModel().get(childPosition).isCheck()); 249 | return convertView; 250 | } 251 | 252 | 253 | @Override 254 | public boolean isChildSelectable(int groupPosition, int childPosition) { 255 | return true; 256 | } 257 | } 258 | 259 | 260 | class FirstHolder { 261 | TextView tv; 262 | CheckBox cb; 263 | } 264 | 265 | class SecondHolder { 266 | TextView tv; 267 | CheckBox cb; 268 | } 269 | 270 | class ThirdHolder{ 271 | TextView tv; 272 | CheckBox cb; 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /app/src/main/java/com/baobing/cc/expandlistviewwithcheckbox/FirstModel.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * author:Created by LiangSJ 7 | * date: 2017/9/7. 8 | * description:? 9 | */ 10 | 11 | public class FirstModel { 12 | private boolean isCheck; 13 | private String title; 14 | private List listSecondModel; 15 | 16 | public FirstModel() { 17 | } 18 | 19 | public boolean isCheck() { 20 | 21 | return isCheck; 22 | } 23 | 24 | public void setCheck(boolean check) { 25 | isCheck = check; 26 | } 27 | 28 | public List getListSecondModel() { 29 | return listSecondModel; 30 | } 31 | 32 | public void setListSecondModel(List listSecondModel) { 33 | this.listSecondModel = listSecondModel; 34 | } 35 | 36 | public String getTitle() { 37 | return title; 38 | } 39 | 40 | public void setTitle(String title) { 41 | this.title = title; 42 | } 43 | 44 | public FirstModel(boolean isCheck, String title, List listSecondModel) { 45 | 46 | this.isCheck = isCheck; 47 | this.title = title; 48 | this.listSecondModel = listSecondModel; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/baobing/cc/expandlistviewwithcheckbox/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.ExpandableListView; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | List mListData; 14 | private ExpandableListView mLv; 15 | private ExpandListViewAdapter mAdapter; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | initDate(); 22 | mLv = ((ExpandableListView) findViewById(R.id.lv)); 23 | mAdapter = new ExpandListViewAdapter(mListData, this); 24 | mLv.setAdapter(mAdapter); 25 | } 26 | 27 | private void initDate() { 28 | mListData = new ArrayList<>(); 29 | for (int i = 0; i < 20; i++) { 30 | FirstModel firstModel = new FirstModel(); 31 | List listSecondModel = new ArrayList<>(); 32 | firstModel.setCheck(false); 33 | firstModel.setTitle("第一级" + i); 34 | firstModel.setListSecondModel(listSecondModel); 35 | mListData.add(firstModel); 36 | for (int j = 0; j < 6; j++) { 37 | SecondModel secondModel = new SecondModel(); 38 | List thirdModelList = new ArrayList<>(); 39 | secondModel.setCheck(false); 40 | secondModel.setTitle("第二级" + j); 41 | secondModel.setListThirdModel(thirdModelList); 42 | listSecondModel.add(secondModel); 43 | for (int k = 0; k < 3; k++) { 44 | ThirdModel thirdModel = new ThirdModel(); 45 | thirdModel.setCheck(false); 46 | thirdModel.setTitle("第三级" + k); 47 | thirdModelList.add(thirdModel); 48 | } 49 | } 50 | } 51 | } 52 | 53 | public void btnOnclick(View view) { 54 | List selectResult = new ArrayList<>(); 55 | for (int i = 0; i < mListData.size(); i++) { 56 | List listSecondModel = mListData.get(i).getListSecondModel(); 57 | for (int j = 0; j < listSecondModel.size(); j++) { 58 | List listThirdModel = listSecondModel.get(j).getListThirdModel(); 59 | for (int k = 0; k < listThirdModel.size(); k++) { 60 | StringBuilder address = new StringBuilder(); 61 | address.append("一级:").append(i).append(","); 62 | address.append("二级:").append(j).append(","); 63 | address.append("三级:").append(k).append("||"); 64 | if (listThirdModel.get(k).isCheck()) { 65 | selectResult.add(address.toString()); 66 | } 67 | } 68 | } 69 | } 70 | Log.d("bigname", "btnOnclick: "+selectResult); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/baobing/cc/expandlistviewwithcheckbox/SecondModel.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * author:Created by LiangSJ 7 | * date: 2017/9/7. 8 | * description:? 9 | */ 10 | 11 | public class SecondModel { 12 | private boolean isCheck; 13 | private String title; 14 | private List listThirdModel; 15 | 16 | public boolean isCheck() { 17 | return isCheck; 18 | } 19 | 20 | public void setCheck(boolean check) { 21 | isCheck = check; 22 | } 23 | 24 | public String getTitle() { 25 | return title; 26 | } 27 | 28 | public void setTitle(String title) { 29 | this.title = title; 30 | } 31 | 32 | public List getListThirdModel() { 33 | return listThirdModel; 34 | } 35 | 36 | public void setListThirdModel(List listThirdModel) { 37 | this.listThirdModel = listThirdModel; 38 | } 39 | 40 | public SecondModel(boolean isCheck, String title, List listThirdModel) { 41 | 42 | this.isCheck = isCheck; 43 | this.title = title; 44 | this.listThirdModel = listThirdModel; 45 | } 46 | 47 | public SecondModel() { 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/baobing/cc/expandlistviewwithcheckbox/ThirdModel.java: -------------------------------------------------------------------------------- 1 | package com.baobing.cc.expandlistviewwithcheckbox; 2 | 3 | /** 4 | * author:Created by LiangSJ 5 | * date: 2017/9/8. 6 | * description:? 7 | */ 8 | 9 | public class ThirdModel { 10 | private boolean isCheck; 11 | private String title; 12 | 13 | public boolean isCheck() { 14 | return isCheck; 15 | } 16 | 17 | public void setCheck(boolean check) { 18 | isCheck = check; 19 | } 20 | 21 | public String getTitle() { 22 | return title; 23 | } 24 | 25 | public void setTitle(String title) { 26 | this.title = title; 27 | } 28 | 29 | public ThirdModel() { 30 | 31 | } 32 | 33 | public ThirdModel(boolean isCheck, String title) { 34 | 35 | this.isCheck = isCheck; 36 | this.title = title; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |