├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── build.gradle ├── demo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── drawthink │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── drawthink │ │ │ └── demo │ │ │ ├── ImageFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── TextFragment.java │ │ │ ├── adapter │ │ │ ├── BookAdapter.java │ │ │ └── ImageAdapter.java │ │ │ ├── bean │ │ │ ├── Book.java │ │ │ └── ImageBean.java │ │ │ ├── holder │ │ │ ├── BookViewHolder.java │ │ │ └── ImageViewHolder.java │ │ │ └── itemdecoration │ │ │ └── SimplePaddingDecoration.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_image.xml │ │ ├── fragment_text.xml │ │ ├── item_image_layout.xml │ │ ├── item_layout.xml │ │ └── title_item_layout.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── bird.jpg │ │ ├── cat.jpg │ │ ├── dog.jpg │ │ ├── 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 │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── drawthink │ └── demo │ └── ExampleUnitTest.java ├── expandable-recyclerview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── drawthink │ │ └── expandablerecyclerview │ │ ├── adapter │ │ └── BaseRecyclerViewAdapter.java │ │ ├── bean │ │ ├── BaseItem.java │ │ ├── GroupItem.java │ │ └── RecyclerViewData.java │ │ ├── holder │ │ └── BaseViewHolder.java │ │ └── listener │ │ └── OnRecyclerViewListener.java │ └── res │ └── values │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot └── screenshot.gif └── 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 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 38 | 39 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 87 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 114 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 代码[github地址](https://github.com/drawthink/ExpandableRecyclerView) 2 | 3 | 4 | 1.目前只支持两级结构。 5 | 6 | 2.支持所有组同时全部展开,支持同一时间只能展开一组。 7 | 8 | 3.GroupView,ChildView高度自定义。 9 | 10 | 4.支持初始化数据时,指定展开某组数据。 11 | 12 | 5.支持GroupItem,ChildItem的Onlick,OnLongClick事件。 13 | 14 | 6.展开收起带动画。 15 | 16 | 17 | 效果图: 18 | 19 | ![](https://github.com/drawthink/ExpandableRecyclerView/blob/master/screenshot/screenshot.gif?raw=true) 20 | 21 | 使用步骤:加入依赖 22 | ``` 23 | compile 'com.drawthink:expandable-recyclerview:0.0.3' 24 | 25 | ``` 26 | 1.继承BaseViewHolder,实现自己的ViewHolder 27 | 28 | 1.1 在构造函数中初始化你的View(包括GroupView,和childView). 29 | 30 | 1.2 分别实现以下两个方法,并在对应方法中返回对应Layout布局文件中根节点的ID。 31 | 32 | ``` 33 | public int getGroupViewResId() 34 | 35 | public int getChildViewResId() 36 | ``` 37 | 示例代码: 38 | ``` 39 | public class ImageViewHolder extends BaseViewHolder { 40 | 41 | public ImageView image; 42 | public TextView tvTitle; 43 | 44 | /** 45 | * 初始化你的View(这里包括GroupView,和childView) 46 | */ 47 | public ImageViewHolder(Context ctx, View itemView, int viewType) { 48 | super(ctx,itemView, viewType); 49 | image = (ImageView) itemView.findViewById(R.id.iv_image); 50 | tvTitle = (TextView)itemView.findViewById(R.id.tv_title); 51 | } 52 | 53 | /** 54 | * @return 返回你的GroupView 布局文件中根节点的ID 55 | */ 56 | @Override 57 | public int getGroupViewResId() { 58 | return R.id.group; 59 | } 60 | 61 | /** 62 | * @return 返回你的ChildView 布局文件中根节点的ID 63 | */ 64 | @Override 65 | public int getChildViewResId() { 66 | return R.id.child; 67 | } 68 | 69 | } 70 | ``` 71 | 72 | 2.继承BaseRecyclerViewAdapter ,完成自己的Adapter。 73 | 74 | T,S,VH各参数见如下注释 75 | ``` 76 | /** 77 | * author:Drawthink 78 | * describe: 79 | * date: 2017/5/22 80 | * T :group data 81 | * S :child data 82 | * VH :ViewHolder 83 | */ 84 | 85 | public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter 86 | 87 | ``` 88 | 示例Adapter代码: 89 | ``` 90 | public class ImageAdapter extends BaseRecyclerViewAdapter { 91 | 92 | private Context ctx; 93 | private List datas; 94 | private LayoutInflater mInflater; 95 | 96 | public ImageAdapter(Context ctx, List datas) { 97 | super(ctx, datas); 98 | mInflater = LayoutInflater.from(ctx); 99 | this.ctx = ctx; 100 | this.datas = datas; 101 | } 102 | 103 | @Override 104 | public void onBindGroupHolder(ImageViewHolder holder, int groupPos,int position, String groupData) { 105 | holder.tvTitle.setText(groupData); 106 | } 107 | 108 | @Override 109 | public void onBindChildpHolder(ImageViewHolder holder, int groupPos,int childPos,int position, ImageBean childData) { 110 | holder.image.setBackgroundResource(childData.getResId()); 111 | } 112 | 113 | @Override 114 | public View getGroupView(ViewGroup parent) { 115 | return mInflater.inflate(R.layout.title_item_layout,parent,false); 116 | } 117 | 118 | @Override 119 | public View getChildView(ViewGroup parent) { 120 | return mInflater.inflate(R.layout.item_image_layout,parent,false); 121 | } 122 | 123 | @Override 124 | public ImageViewHolder createRealViewHolder(Context ctx, View view, int viewType) { 125 | return new ImageViewHolder(ctx,view,viewType); 126 | } 127 | } 128 | ``` 129 | 130 | 完成以上两步之后,基本大工告成,由于ExpandableRecyclerView的数据是要分组的,所以提供了RecyclerViewData来封装 131 | ``` 132 | /** 133 | * @param groupData 134 | * @param childDatas 135 | * @param isExpand 初始化展示数据时,该组数据是否展开 136 | */ 137 | public RecyclerViewData(T groupData, List childDatas,boolean isExpand) 138 | 139 | ``` 140 | 那接下来看下数据具体是怎样封装的。 141 | ``` 142 | mDatas = new ArrayList<>(); 143 | List bean1 = new ArrayList<>(); 144 | List bean2 = new ArrayList<>(); 145 | List bean3 = new ArrayList<>(); 146 | // 每个子列表长度可以不相同 147 | bean1.add(new ImageBean("Dog", R.mipmap.dog)); 148 | bean1.add(new ImageBean("Dog", R.mipmap.dog)); 149 | bean2.add(new ImageBean("Cat", R.mipmap.cat)); 150 | bean3.add(new ImageBean("Bird", R.mipmap.bird)); 151 | 152 | mDatas.add(new RecyclerViewData("Dog", bean1, true)); 153 | mDatas.add(new RecyclerViewData("Cat", bean2, true)); 154 | mDatas.add(new RecyclerViewData("Bird", bean3, true)); 155 | ``` 156 | 所有工作以完成,现在你可以象平常使用Adapter,RecyclerView一样,来愉快的写代码了。 157 | 158 | 注意:在对元数据mDatas进行增删操作时,要调用adapter.notifyRecyclerViewData();否则会造成数据索引错乱的问题。 159 | 160 | 161 | 代码[github地址](https://github.com/drawthink/ExpandableRecyclerView) -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | jcenter() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "26.0.0" 6 | 7 | defaultConfig { 8 | applicationId "com.drawthink.demo" 9 | minSdkVersion 15 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:23.0.0' 31 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 32 | testCompile 'junit:junit:4.12' 33 | compile 'com.drawthink:expandable-recyclerview:0.0.3' 34 | } 35 | -------------------------------------------------------------------------------- /demo/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 E:\Android\sdk/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 | -------------------------------------------------------------------------------- /demo/src/androidTest/java/com/drawthink/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo; 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.drawthink.demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/ImageFragment.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Toast; 12 | 13 | import com.drawthink.demo.adapter.ImageAdapter; 14 | import com.drawthink.demo.bean.ImageBean; 15 | import com.drawthink.demo.itemdecoration.SimplePaddingDecoration; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import drawthink.expandablerecyclerview.bean.RecyclerViewData; 21 | import drawthink.expandablerecyclerview.listener.OnRecyclerViewListener; 22 | 23 | public class ImageFragment extends Fragment implements OnRecyclerViewListener.OnItemClickListener { 24 | 25 | 26 | private List mDatas; 27 | private RecyclerView mRecyclerview; 28 | private ImageAdapter adapter; 29 | private LinearLayoutManager linearLayoutManager; 30 | 31 | @Override 32 | public void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | mDatas = new ArrayList<>(); 35 | } 36 | 37 | @Override 38 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 39 | Bundle savedInstanceState) { 40 | View view = inflater.inflate(R.layout.fragment_image, container, false); 41 | mRecyclerview = (RecyclerView) view.findViewById(R.id.recyclerview); 42 | linearLayoutManager = new LinearLayoutManager(getActivity()); 43 | linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); 44 | mRecyclerview.setLayoutManager(linearLayoutManager); 45 | mRecyclerview.addItemDecoration(new SimplePaddingDecoration(getActivity())); 46 | initImages(); 47 | adapter = new ImageAdapter(getActivity(), mDatas); 48 | adapter.setOnItemClickListener(this); 49 | mRecyclerview.setAdapter(adapter); 50 | adapter.notifyDataSetChanged(); 51 | return view; 52 | } 53 | 54 | private void initImages() { 55 | mDatas = new ArrayList<>(); 56 | List bean1 = new ArrayList<>(); 57 | List bean2 = new ArrayList<>(); 58 | List bean3 = new ArrayList<>(); 59 | // 每个子列表长度可以不相同 60 | bean1.add(new ImageBean("Dog", R.mipmap.dog)); 61 | bean1.add(new ImageBean("Dog", R.mipmap.dog)); 62 | bean2.add(new ImageBean("Cat", R.mipmap.cat)); 63 | bean3.add(new ImageBean("Bird", R.mipmap.bird)); 64 | 65 | mDatas.add(new RecyclerViewData("Dog", bean1, true)); 66 | mDatas.add(new RecyclerViewData("Cat", bean2, true)); 67 | mDatas.add(new RecyclerViewData("Bird", bean3, true)); 68 | } 69 | 70 | @Override 71 | public void onGroupItemClick(int position,int groupPosition, View view) { 72 | String group = (String) mDatas.get(groupPosition).getGroupData(); 73 | Toast.makeText(getActivity(), "groupPos:" + groupPosition + " group:" + group, Toast.LENGTH_SHORT).show(); 74 | } 75 | 76 | @Override 77 | public void onChildItemClick(int position,int groupPosition, int childPosition, View view) { 78 | ImageBean bean = (ImageBean) mDatas.get(groupPosition).getChild(childPosition); 79 | Toast.makeText(getActivity(), "groupPos:" + groupPosition + " childPos:" + childPosition + " child:" + bean.getName(), Toast.LENGTH_SHORT).show(); 80 | } 81 | 82 | 83 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentTransaction; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | private FragmentManager fm; 13 | TextFragment textFragment; 14 | ImageFragment imageFragment; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | fm = getSupportFragmentManager(); 21 | showFragment(R.id.text_fragment); 22 | } 23 | 24 | @Override 25 | public boolean onCreateOptionsMenu(Menu menu) { 26 | getMenuInflater().inflate(R.menu.menu_main, menu); 27 | return true; 28 | } 29 | 30 | @Override 31 | public boolean onOptionsItemSelected(MenuItem item) { 32 | int id = item.getItemId(); 33 | showFragment(id); 34 | return false; 35 | } 36 | 37 | private void showFragment(int viewId) { 38 | FragmentTransaction ft = fm.beginTransaction(); 39 | switch (viewId) { 40 | case R.id.text_fragment: 41 | if (textFragment == null) { 42 | textFragment = new TextFragment(); 43 | ft.add(R.id.fragment_container, textFragment); 44 | } else { 45 | ft.show(textFragment); 46 | } 47 | if (null != imageFragment) { 48 | ft.hide(imageFragment); 49 | } 50 | break; 51 | case R.id.image_fragment: 52 | if (imageFragment == null) { 53 | imageFragment = new ImageFragment(); 54 | ft.add(R.id.fragment_container, imageFragment); 55 | } else { 56 | ft.show(imageFragment); 57 | } 58 | if (null != textFragment) { 59 | ft.hide(textFragment); 60 | } 61 | break; 62 | } 63 | ft.commit(); 64 | } 65 | 66 | 67 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/TextFragment.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo; 2 | 3 | 4 | import android.content.DialogInterface; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.app.AlertDialog; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.Toast; 14 | 15 | 16 | import com.drawthink.demo.adapter.BookAdapter; 17 | import com.drawthink.demo.bean.Book; 18 | import com.drawthink.demo.itemdecoration.SimplePaddingDecoration; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import drawthink.expandablerecyclerview.bean.RecyclerViewData; 23 | import drawthink.expandablerecyclerview.listener.OnRecyclerViewListener; 24 | 25 | public class TextFragment extends Fragment implements OnRecyclerViewListener.OnItemClickListener, OnRecyclerViewListener.OnItemLongClickListener{ 26 | 27 | 28 | private List mDatas; 29 | private RecyclerView mRecyclerview; 30 | private BookAdapter adapter; 31 | private LinearLayoutManager linearLayoutManager; 32 | 33 | @Override 34 | public void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | mDatas = new ArrayList<>(); 37 | linearLayoutManager = new LinearLayoutManager(getActivity()); 38 | linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); 39 | initBooks(); 40 | } 41 | 42 | @Override 43 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 44 | Bundle savedInstanceState) { 45 | View view = inflater.inflate(R.layout.fragment_text, container, false); 46 | mRecyclerview = (RecyclerView) view.findViewById(R.id.recyclerview); 47 | mRecyclerview.setLayoutManager(linearLayoutManager); 48 | mRecyclerview.addItemDecoration(new SimplePaddingDecoration(getActivity())); 49 | 50 | adapter = new BookAdapter(getActivity(), mDatas); 51 | adapter.setOnItemClickListener(this); 52 | adapter.setOnItemLongClickListener(this); 53 | 54 | mRecyclerview.setAdapter(adapter); 55 | adapter.notifyDataSetChanged(); 56 | return view; 57 | } 58 | 59 | private void initBooks() { 60 | List bean1 = new ArrayList<>(); 61 | List bean2 = new ArrayList<>(); 62 | List bean3 = new ArrayList<>(); 63 | List bean4 = new ArrayList<>(); 64 | // id , pid , label , 其他属性 65 | bean1.add(new Book("文件管理系统")); 66 | bean1.add(new Book("游戏")); 67 | bean1.add(new Book("文档")); 68 | bean1.add(new Book("程序")); 69 | bean2.add(new Book("war3")); 70 | bean2.add(new Book("刀塔传奇")); 71 | 72 | bean1.add(new Book("面向对象")); 73 | bean2.add(new Book("非面向对象")); 74 | 75 | bean2.add(new Book("C++")); 76 | bean2.add(new Book("JAVA")); 77 | bean2.add(new Book("Javascript")); 78 | bean2.add(new Book("C")); 79 | 80 | bean3.add(new Book("文件管理系统")); 81 | bean3.add(new Book("游戏")); 82 | bean4.add(new Book("文档")); 83 | bean4.add(new Book("程序")); 84 | bean4.add(new Book("war3")); 85 | bean3.add(new Book("刀塔传奇")); 86 | 87 | bean3.add(new Book("面向对象")); 88 | bean4.add(new Book("非面向对象")); 89 | 90 | bean3.add(new Book("文件管理系统")); 91 | bean3.add(new Book("游戏")); 92 | bean4.add(new Book("文档")); 93 | bean4.add(new Book("程序")); 94 | bean4.add(new Book("war3")); 95 | bean4.add(new Book("刀塔传奇")); 96 | 97 | mDatas.add(new RecyclerViewData("分组0", bean1, true)); 98 | mDatas.add(new RecyclerViewData("分组1", bean2, true)); 99 | mDatas.add(new RecyclerViewData("分组2", bean3, true)); 100 | mDatas.add(new RecyclerViewData("分组3", bean4, true)); 101 | } 102 | 103 | @Override 104 | public void onGroupItemClick(int position,int groupPosition, View view) { 105 | String group = (String) mDatas.get(groupPosition).getGroupData(); 106 | Toast.makeText(getActivity(), "groupPos:" + groupPosition + " group:" + group, Toast.LENGTH_SHORT).show(); 107 | } 108 | 109 | @Override 110 | public void onChildItemClick(int position,int groupPosition, int childPosition, View view) { 111 | Book bean = (Book) mDatas.get(groupPosition).getChild(childPosition); 112 | Toast.makeText(getActivity(), "groupPos:" + groupPosition + " childPos:" + childPosition + " child:" + bean.getName(), Toast.LENGTH_SHORT).show(); 113 | } 114 | 115 | 116 | @Override 117 | public void onGroupItemLongClick(int position,int groupPosition, View view) { 118 | String group = (String) mDatas.get(groupPosition).getGroupData(); 119 | Toast.makeText(getActivity(), "groupPos:" + groupPosition + " group:" + group, Toast.LENGTH_SHORT).show(); 120 | showDeleteDialog(position,groupPosition,0,true); 121 | } 122 | 123 | @Override 124 | public void onChildItemLongClick(int position,int groupPosition, int childPosition, View view) { 125 | Book bean = (Book) mDatas.get(groupPosition).getChild(childPosition); 126 | Toast.makeText(getActivity(), "groupPos:" + groupPosition + " childPos:" + childPosition + " child:" + bean.getName(), Toast.LENGTH_SHORT).show(); 127 | showDeleteDialog(position,groupPosition,childPosition,false); 128 | } 129 | 130 | /** 131 | * 删除数据 132 | * @param position 133 | * @param isGroup 134 | */ 135 | private void showDeleteDialog(final int position, final int groupPosition, final int childPosition, final boolean isGroup){ 136 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) 137 | .setTitle("提示!") 138 | .setMessage(isGroup?"您确定要删除此组数据":"您确定要删除此条数据") 139 | .setPositiveButton("确定", new DialogInterface.OnClickListener() { 140 | @Override 141 | public void onClick(DialogInterface dialog, int which) { 142 | //然后根据回调里的groupPosition和childPosition来更新你的数据源 143 | if(isGroup){ 144 | mDatas.remove(groupPosition); 145 | }else { 146 | mDatas.get(groupPosition).removeChild(childPosition); 147 | } 148 | adapter.notifyRecyclerViewData(); 149 | } 150 | }) 151 | .setNegativeButton("取消", new DialogInterface.OnClickListener() { 152 | @Override 153 | public void onClick(DialogInterface dialog, int which) { 154 | dialog.dismiss(); 155 | } 156 | }); 157 | builder.show(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/adapter/BookAdapter.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.drawthink.demo.R; 9 | import com.drawthink.demo.bean.Book; 10 | import com.drawthink.demo.holder.BookViewHolder; 11 | 12 | import java.util.List; 13 | 14 | import drawthink.expandablerecyclerview.adapter.BaseRecyclerViewAdapter; 15 | import drawthink.expandablerecyclerview.bean.RecyclerViewData; 16 | 17 | /** 18 | * author:Drawthink 19 | * describe: 20 | * date: 2017/5/22 21 | */ 22 | 23 | public class BookAdapter extends BaseRecyclerViewAdapter { 24 | 25 | private Context ctx; 26 | private LayoutInflater mInflater; 27 | 28 | public BookAdapter(Context ctx, List datas) { 29 | super(ctx, datas); 30 | mInflater = LayoutInflater.from(ctx); 31 | this.ctx = ctx; 32 | } 33 | 34 | /** 35 | * head View数据设置 36 | * @param holder 37 | * @param groupPos 38 | * @param position 39 | * @param groupData 40 | */ 41 | @Override 42 | public void onBindGroupHolder(BookViewHolder holder, int groupPos,int position,String groupData) { 43 | holder.tvTitle.setText(groupData); 44 | } 45 | 46 | /** 47 | * child View数据设置 48 | * @param holder 49 | * @param groupPos 50 | * @param childPos 51 | * @param position 52 | * @param childData 53 | */ 54 | @Override 55 | public void onBindChildpHolder(BookViewHolder holder, int groupPos,int childPos,int position, Book childData) { 56 | holder.tvName.setText(childData.getName()); 57 | } 58 | 59 | @Override 60 | public View getGroupView(ViewGroup parent) { 61 | return mInflater.inflate(R.layout.title_item_layout,parent,false); 62 | } 63 | 64 | @Override 65 | public View getChildView(ViewGroup parent) { 66 | return mInflater.inflate(R.layout.item_layout,parent,false); 67 | } 68 | 69 | @Override 70 | public BookViewHolder createRealViewHolder(Context ctx, View view, int viewType) { 71 | return new BookViewHolder(ctx,view,viewType); 72 | } 73 | 74 | /** 75 | * true 全部可展开 76 | * fasle 同一时间只能展开一个 77 | * */ 78 | @Override 79 | public boolean canExpandAll() { 80 | return false; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/adapter/ImageAdapter.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | 9 | import com.drawthink.demo.R; 10 | import com.drawthink.demo.bean.ImageBean; 11 | import com.drawthink.demo.holder.ImageViewHolder; 12 | 13 | import java.util.List; 14 | 15 | import drawthink.expandablerecyclerview.adapter.BaseRecyclerViewAdapter; 16 | import drawthink.expandablerecyclerview.bean.RecyclerViewData; 17 | 18 | /** 19 | * author:Drawthink 20 | * describe: 21 | * date: 2017/5/25 22 | */ 23 | 24 | public class ImageAdapter extends BaseRecyclerViewAdapter { 25 | 26 | private Context ctx; 27 | private List datas; 28 | private LayoutInflater mInflater; 29 | 30 | public ImageAdapter(Context ctx, List datas) { 31 | super(ctx, datas); 32 | mInflater = LayoutInflater.from(ctx); 33 | this.ctx = ctx; 34 | this.datas = datas; 35 | } 36 | 37 | @Override 38 | public void onBindGroupHolder(ImageViewHolder holder, int groupPos,int position, String groupData) { 39 | holder.tvTitle.setText(groupData); 40 | } 41 | 42 | @Override 43 | public void onBindChildpHolder(ImageViewHolder holder, int groupPos,int childPos,int position, ImageBean childData) { 44 | holder.image.setBackgroundResource(childData.getResId()); 45 | } 46 | 47 | @Override 48 | public View getGroupView(ViewGroup parent) { 49 | return mInflater.inflate(R.layout.title_item_layout,parent,false); 50 | } 51 | 52 | @Override 53 | public View getChildView(ViewGroup parent) { 54 | return mInflater.inflate(R.layout.item_image_layout,parent,false); 55 | } 56 | 57 | @Override 58 | public ImageViewHolder createRealViewHolder(Context ctx, View view, int viewType) { 59 | return new ImageViewHolder(ctx,view,viewType); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/bean/Book.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.bean; 2 | 3 | 4 | public class Book { 5 | private String name; 6 | 7 | 8 | public Book(String name) { 9 | this.name = name; 10 | } 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/bean/ImageBean.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.bean; 2 | 3 | /** 4 | * author:Drawthink 5 | * describe: 6 | * date: 2017/5/25 7 | */ 8 | 9 | public class ImageBean { 10 | private String name; 11 | private int resId; 12 | 13 | public ImageBean(String name, int resId) { 14 | this.name = name; 15 | this.resId = resId; 16 | } 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public void setName(String name) { 23 | this.name = name; 24 | } 25 | 26 | public int getResId() { 27 | return resId; 28 | } 29 | 30 | public void setResId(int resId) { 31 | this.resId = resId; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/holder/BookViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.holder; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.drawthink.demo.R; 8 | 9 | import drawthink.expandablerecyclerview.holder.BaseViewHolder; 10 | 11 | /** 12 | * author:Drawthink 13 | * describe: 14 | * date: 2017/5/22 15 | */ 16 | 17 | public class BookViewHolder extends BaseViewHolder { 18 | 19 | public TextView tvName; 20 | public TextView tvTitle; 21 | 22 | public BookViewHolder(Context ctx, View itemView, int viewType) { 23 | super(ctx,itemView, viewType); 24 | tvName = (TextView) itemView.findViewById(R.id.tv_name); 25 | tvTitle = (TextView)itemView.findViewById(R.id.tv_title); 26 | } 27 | 28 | @Override 29 | public int getGroupViewResId() { 30 | return R.id.group; 31 | } 32 | 33 | @Override 34 | public int getChildViewResId() { 35 | return R.id.child; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/holder/ImageViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.holder; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.widget.ImageView; 6 | import android.widget.TextView; 7 | 8 | import com.drawthink.demo.R; 9 | 10 | import drawthink.expandablerecyclerview.holder.BaseViewHolder; 11 | 12 | /** 13 | * author:Drawthink 14 | * describe: 15 | * date: 2017/5/22 16 | */ 17 | 18 | public class ImageViewHolder extends BaseViewHolder { 19 | 20 | public ImageView image; 21 | public TextView tvTitle; 22 | 23 | /** 24 | * 初始化你的View(这里包括GroupView,和childView) 25 | */ 26 | public ImageViewHolder(Context ctx, View itemView, int viewType) { 27 | super(ctx,itemView, viewType); 28 | image = (ImageView) itemView.findViewById(R.id.iv_image); 29 | tvTitle = (TextView)itemView.findViewById(R.id.tv_title); 30 | } 31 | 32 | /** 33 | * @return 返回你的GroupView 布局文件中根节点的ID 34 | */ 35 | @Override 36 | public int getGroupViewResId() { 37 | return R.id.group; 38 | } 39 | 40 | /** 41 | * @return 返回你的ChildView 布局文件中根节点的ID 42 | */ 43 | @Override 44 | public int getChildViewResId() { 45 | return R.id.child; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /demo/src/main/java/com/drawthink/demo/itemdecoration/SimplePaddingDecoration.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo.itemdecoration; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | import com.drawthink.demo.R; 9 | 10 | public class SimplePaddingDecoration extends RecyclerView.ItemDecoration { 11 | 12 | private int dividerHeight; 13 | 14 | 15 | public SimplePaddingDecoration(Context context) { 16 | dividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height); 17 | } 18 | 19 | @Override 20 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 21 | super.getItemOffsets(outRect, view, parent, state); 22 | outRect.bottom = dividerHeight;//类似加了一个bottom padding 23 | } 24 | } -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/fragment_image.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/fragment_text.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/item_image_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/item_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/title_item_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /demo/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/bird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xhdpi/bird.jpg -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xhdpi/cat.jpg -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/dog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xhdpi/dog.jpg -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 5dp 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ExpandableRecyclerView 3 | 4 | 5 | Hello blank fragment 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /demo/src/test/java/com/drawthink/demo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.drawthink.demo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /expandable-recyclerview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /expandable-recyclerview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "24.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:recyclerview-v7:23.0.0' 23 | } 24 | 25 | android { 26 | lintOptions { 27 | abortOnError false 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /expandable-recyclerview/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:\android\sdk/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 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/java/drawthink/expandablerecyclerview/adapter/BaseRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package drawthink.expandablerecyclerview.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import drawthink.expandablerecyclerview.bean.BaseItem; 11 | import drawthink.expandablerecyclerview.bean.GroupItem; 12 | import drawthink.expandablerecyclerview.bean.RecyclerViewData; 13 | import drawthink.expandablerecyclerview.holder.BaseViewHolder; 14 | import drawthink.expandablerecyclerview.listener.OnRecyclerViewListener; 15 | import static drawthink.expandablerecyclerview.holder.BaseViewHolder.VIEW_TYPE_CHILD; 16 | import static drawthink.expandablerecyclerview.holder.BaseViewHolder.VIEW_TYPE_PARENT; 17 | 18 | 19 | /** 20 | * author:Drawthink 21 | * describe: 22 | * date: 2017/5/22 23 | * T :group data 24 | * S :child data 25 | * VH :ViewHolder 26 | */ 27 | 28 | public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter { 29 | 30 | public static final String TAG = BaseRecyclerViewAdapter.class.getSimpleName(); 31 | 32 | private Context ctx; 33 | /** 34 | * all data 35 | */ 36 | private List allDatas; 37 | /** 38 | * showing datas 39 | */ 40 | private List showingDatas = new ArrayList<>(); 41 | 42 | /** 43 | * child datas 44 | */ 45 | private List> childDatas; 46 | 47 | private OnRecyclerViewListener.OnItemClickListener itemClickListener; 48 | private OnRecyclerViewListener.OnItemLongClickListener itemLongClickListener; 49 | 50 | public void setOnItemClickListener(OnRecyclerViewListener.OnItemClickListener listener) { 51 | this.itemClickListener = listener; 52 | } 53 | public void setOnItemLongClickListener(OnRecyclerViewListener.OnItemLongClickListener longClickListener){ 54 | this.itemLongClickListener = longClickListener; 55 | } 56 | 57 | public BaseRecyclerViewAdapter(Context ctx, List datas) { 58 | this.ctx = ctx; 59 | this.allDatas = datas; 60 | setShowingDatas(); 61 | this.notifyDataSetChanged(); 62 | } 63 | 64 | public void setAllDatas(List allDatas) { 65 | this.allDatas = allDatas; 66 | setShowingDatas(); 67 | this.notifyDataSetChanged(); 68 | } 69 | 70 | @Override 71 | public int getItemCount() { 72 | return null == showingDatas ? 0 : showingDatas.size(); 73 | } 74 | 75 | @Override 76 | public int getItemViewType(int position) { 77 | if (showingDatas.get(position) instanceof GroupItem) { 78 | return VIEW_TYPE_PARENT; 79 | } else { 80 | return VIEW_TYPE_CHILD; 81 | } 82 | } 83 | 84 | @Override 85 | public VH onCreateViewHolder(ViewGroup parent, int viewType) { 86 | View view = null; 87 | switch (viewType) { 88 | case VIEW_TYPE_PARENT: 89 | view = getGroupView(parent); 90 | break; 91 | case VIEW_TYPE_CHILD: 92 | view = getChildView(parent); 93 | break; 94 | } 95 | return createRealViewHolder(ctx, view, viewType); 96 | } 97 | 98 | 99 | @Override 100 | public void onBindViewHolder(final VH holder, final int position) { 101 | final Object item = showingDatas.get(position); 102 | final int gp = getGroupPosition(position); 103 | final int cp = getChildPosition(gp, position); 104 | if (item != null && item instanceof GroupItem) { 105 | onBindGroupHolder(holder,gp, position, (T) ((GroupItem) item).getGroupData()); 106 | holder.groupView.setOnClickListener(new View.OnClickListener() { 107 | @Override 108 | public void onClick(View v) { 109 | if (null != itemClickListener) { 110 | itemClickListener.onGroupItemClick(position,gp, holder.groupView); 111 | } 112 | if (item instanceof GroupItem && ((GroupItem) item).isExpand()) { 113 | collapseGroup(position); 114 | } else { 115 | expandGroup(position); 116 | } 117 | } 118 | }); 119 | holder.groupView.setOnLongClickListener(new View.OnLongClickListener() { 120 | @Override 121 | public boolean onLongClick(View v) { 122 | if (null != itemLongClickListener) { 123 | itemLongClickListener.onGroupItemLongClick(position,gp, holder.groupView); 124 | } 125 | return true; 126 | } 127 | }); 128 | } else { 129 | onBindChildpHolder(holder,gp,cp, position, (S) item); 130 | holder.childView.setOnClickListener(new View.OnClickListener() { 131 | @Override 132 | public void onClick(View v) { 133 | if (null != itemClickListener) { 134 | itemClickListener.onChildItemClick(position,gp, cp, holder.childView); 135 | } 136 | } 137 | }); 138 | holder.childView.setOnLongClickListener(new View.OnLongClickListener() { 139 | @Override 140 | public boolean onLongClick(View v) { 141 | if (null != itemLongClickListener) { 142 | int gp = getGroupPosition(position); 143 | itemLongClickListener.onChildItemLongClick(position,gp,cp, holder.childView); 144 | } 145 | return true; 146 | } 147 | }); 148 | } 149 | } 150 | 151 | 152 | /** 153 | * setup showing datas 154 | */ 155 | private void setShowingDatas() { 156 | if (null != showingDatas) { 157 | showingDatas.clear(); 158 | } 159 | if (this.childDatas == null) { 160 | this.childDatas = new ArrayList<>(); 161 | } 162 | childDatas.clear(); 163 | GroupItem groupItem; 164 | for (int i = 0; i < allDatas.size(); i++) { 165 | if (allDatas.get(i).getGroupItem() instanceof GroupItem) { 166 | groupItem = allDatas.get(i).getGroupItem(); 167 | } else { 168 | break; 169 | } 170 | childDatas.add(i, groupItem.getChildDatas()); 171 | showingDatas.add(groupItem); 172 | if (null != groupItem && groupItem.hasChilds() && groupItem.isExpand()) { 173 | showingDatas.addAll(groupItem.getChildDatas()); 174 | } 175 | } 176 | } 177 | 178 | /** 179 | * expandGroup 180 | * @param position showingDatas position 181 | */ 182 | private void expandGroup(int position) { 183 | Object item = showingDatas.get(position); 184 | if (null == item) { 185 | return; 186 | } 187 | if (!(item instanceof GroupItem)) { 188 | return; 189 | } 190 | if (((GroupItem) item).isExpand()) { 191 | return; 192 | } 193 | if(!canExpandAll()){ 194 | for(int i=0;i tempChilds; 205 | if (((GroupItem) item).hasChilds()) { 206 | tempChilds = ((GroupItem) item).getChildDatas(); 207 | ((GroupItem) item).onExpand(); 208 | if(canExpandAll()){ 209 | showingDatas.addAll(position + 1, tempChilds); 210 | notifyItemRangeInserted(position+1,tempChilds.size()); 211 | notifyItemRangeChanged(position+1,showingDatas.size()-(position+1)); 212 | }else { 213 | int tempPsi = showingDatas.indexOf(item); 214 | showingDatas.addAll(tempPsi + 1, tempChilds); 215 | notifyItemRangeInserted(tempPsi+1,tempChilds.size()); 216 | notifyItemRangeChanged(tempPsi+1,showingDatas.size()-(tempPsi+1)); 217 | } 218 | } 219 | } 220 | 221 | /** 222 | * collapseGroup 223 | * @param position showingDatas position 224 | */ 225 | private int collapseGroup(int position) { 226 | Object item = showingDatas.get(position); 227 | if (null == item) { 228 | return -1; 229 | } 230 | if (!(item instanceof GroupItem)) { 231 | return -1; 232 | } 233 | if (!((GroupItem) item).isExpand()) { 234 | return -1; 235 | } 236 | int tempSize = showingDatas.size(); 237 | List tempChilds; 238 | if (((GroupItem) item).hasChilds()) { 239 | tempChilds = ((GroupItem) item).getChildDatas(); 240 | ((GroupItem) item).onExpand(); 241 | showingDatas.removeAll(tempChilds); 242 | notifyItemRangeRemoved(position+1,tempChilds.size()); 243 | notifyItemRangeChanged(position+1,tempSize-(position+1)); 244 | return position; 245 | } 246 | return -1; 247 | } 248 | /** 249 | * @param position showingDatas position 250 | * @return GroupPosition 251 | */ 252 | private int getGroupPosition(int position) { 253 | Object item = showingDatas.get(position); 254 | if (item instanceof GroupItem) { 255 | for (int j = 0; j < allDatas.size(); j++) { 256 | if(allDatas.get(j).getGroupItem().equals(item)){ 257 | return j; 258 | } 259 | } 260 | } 261 | for (int i = 0; i < childDatas.size(); i++) { 262 | if (childDatas.get(i).contains(item)) { 263 | return i; 264 | } 265 | } 266 | return -1; 267 | } 268 | /** 269 | * @param groupPosition 270 | * @param showDataPosition 271 | * @return ChildPosition 272 | */ 273 | private int getChildPosition(int groupPosition, int showDataPosition) { 274 | Object item = showingDatas.get(showDataPosition); 275 | try { 276 | return childDatas.get(groupPosition).indexOf(item); 277 | } catch (IndexOutOfBoundsException ex) { 278 | Log.e(TAG, ex.getMessage()); 279 | } 280 | return 0; 281 | } 282 | 283 | /** 284 | * return groupView 285 | */ 286 | public abstract View getGroupView(ViewGroup parent); 287 | 288 | /** 289 | * return childView 290 | */ 291 | public abstract View getChildView(ViewGroup parent); 292 | 293 | /** 294 | * return instance 295 | */ 296 | public abstract VH createRealViewHolder(Context ctx, View view, int viewType); 297 | 298 | /** 299 | * onBind groupData to groupView 300 | * @param holder 301 | * @param position 302 | */ 303 | public abstract void onBindGroupHolder(VH holder, int groupPos,int position,T groupData); 304 | 305 | /** 306 | * onBind childData to childView 307 | * @param holder 308 | * @param position 309 | */ 310 | public abstract void onBindChildpHolder(VH holder, int groupPos,int childPos,int position,S childData); 311 | 312 | /** 313 | * if return true Allow all expand otherwise Only one can be expand at the same time 314 | * */ 315 | public boolean canExpandAll() { 316 | return true; 317 | } 318 | 319 | /** 320 | * 对原数据进行增加删除,调用此方法进行notify 321 | */ 322 | public void notifyRecyclerViewData(){ 323 | notifyDataSetChanged(); 324 | setShowingDatas(); 325 | } 326 | 327 | 328 | } 329 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/java/drawthink/expandablerecyclerview/bean/BaseItem.java: -------------------------------------------------------------------------------- 1 | package drawthink.expandablerecyclerview.bean; 2 | 3 | /** 4 | * author:Drawthink 5 | * describe: 6 | * date: 2017/5/22 7 | */ 8 | 9 | public abstract class BaseItem { 10 | 11 | public abstract boolean isParent(); 12 | 13 | // public abstract boolean isExpand(); 14 | } 15 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/java/drawthink/expandablerecyclerview/bean/GroupItem.java: -------------------------------------------------------------------------------- 1 | package drawthink.expandablerecyclerview.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * author:Drawthink 7 | * describe: 8 | * date: 2017/5/22 9 | * T 为group数据对象 10 | * S 为child数据对象 11 | */ 12 | 13 | public class GroupItem extends BaseItem{ 14 | 15 | /**head data*/ 16 | private T groupData; 17 | 18 | /** childDatas*/ 19 | private List childDatas; 20 | 21 | /** 是否展开, 默认展开*/ 22 | private boolean isExpand = true; 23 | 24 | 25 | /** 返回是否是父节点*/ 26 | @Override 27 | public boolean isParent() { 28 | return true; 29 | } 30 | 31 | public boolean isExpand(){ 32 | return isExpand; 33 | } 34 | 35 | public void onExpand() { 36 | isExpand = !isExpand; 37 | } 38 | 39 | public GroupItem(T groupData, List childDatas, boolean isExpand) { 40 | this.groupData = groupData; 41 | this.childDatas = childDatas; 42 | this.isExpand = isExpand; 43 | } 44 | 45 | public boolean hasChilds(){ 46 | if(getChildDatas() == null || getChildDatas().isEmpty() ){ 47 | return false; 48 | } 49 | return true; 50 | } 51 | 52 | public List getChildDatas() { 53 | return childDatas; 54 | } 55 | 56 | public void setChildDatas(List childDatas) { 57 | this.childDatas = childDatas; 58 | } 59 | 60 | public void removeChild(int childPosition){ 61 | 62 | } 63 | 64 | public T getGroupData() { 65 | return groupData; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/java/drawthink/expandablerecyclerview/bean/RecyclerViewData.java: -------------------------------------------------------------------------------- 1 | package drawthink.expandablerecyclerview.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * author:Drawthink 7 | * describe: 8 | * date: 2017/5/22 9 | * T 为group数据对象 10 | * S 为child数据对象 11 | */ 12 | 13 | public class RecyclerViewData{ 14 | 15 | private GroupItem groupItem; 16 | 17 | /** 18 | * @param groupData 19 | * @param childDatas 20 | * @param isExpand 初始化展示数据时,该组数据是否展开 21 | */ 22 | public RecyclerViewData(T groupData, List childDatas,boolean isExpand) { 23 | this.groupItem = new GroupItem(groupData,childDatas,isExpand); 24 | } 25 | 26 | public RecyclerViewData(T groupData, List childDatas) { 27 | this.groupItem = new GroupItem(groupData,childDatas,false); 28 | } 29 | 30 | public GroupItem getGroupItem() { 31 | return groupItem; 32 | } 33 | 34 | public void setGroupItem(GroupItem groupItem) { 35 | this.groupItem = groupItem; 36 | } 37 | 38 | public T getGroupData(){ 39 | return (T)groupItem.getGroupData(); 40 | } 41 | 42 | public void removeChild(int position){ 43 | if(null == groupItem || !groupItem.hasChilds()){ 44 | return; 45 | } 46 | groupItem.getChildDatas().remove(position); 47 | } 48 | 49 | public S getChild(int childPosition){ 50 | return (S)groupItem.getChildDatas().get(childPosition); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/java/drawthink/expandablerecyclerview/holder/BaseViewHolder.java: -------------------------------------------------------------------------------- 1 | package drawthink.expandablerecyclerview.holder; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | /** 9 | * author:Drawthink 10 | * describe:BaseViewHolder 11 | * date: 2017/5/22 12 | */ 13 | 14 | public abstract class BaseViewHolder extends RecyclerView.ViewHolder { 15 | 16 | public static final int VIEW_TYPE_PARENT = 1; 17 | public static final int VIEW_TYPE_CHILD = 2; 18 | 19 | public ViewGroup childView; 20 | 21 | public ViewGroup groupView; 22 | 23 | public BaseViewHolder(Context ctx, View itemView, int viewType) { 24 | super(itemView); 25 | switch (viewType) { 26 | case VIEW_TYPE_PARENT: 27 | groupView = (ViewGroup)itemView.findViewById(getGroupViewResId()); 28 | break; 29 | case VIEW_TYPE_CHILD: 30 | childView = (ViewGroup) itemView.findViewById(getChildViewResId()); 31 | break; 32 | } 33 | } 34 | 35 | /** 36 | * return ChildView root layout id 37 | */ 38 | public abstract int getChildViewResId(); 39 | 40 | /** 41 | * return GroupView root layout id 42 | * */ 43 | public abstract int getGroupViewResId(); 44 | 45 | 46 | } -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/java/drawthink/expandablerecyclerview/listener/OnRecyclerViewListener.java: -------------------------------------------------------------------------------- 1 | package drawthink.expandablerecyclerview.listener; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * author:Drawthink 7 | * describe:RecyclerViewListener 8 | * date: 2017/5/22 9 | */ 10 | 11 | public interface OnRecyclerViewListener { 12 | 13 | /** 14 | * 单击事件 15 | */ 16 | interface OnItemClickListener { 17 | /** position 当前在列表中的position*/ 18 | void onGroupItemClick(int position,int groupPosition, View view); 19 | 20 | void onChildItemClick(int position,int groupPosition, int childPosition, View view); 21 | } 22 | 23 | /** 24 | * 双击事件 25 | */ 26 | interface OnItemLongClickListener { 27 | void onGroupItemLongClick(int position,int groupPosition, View view); 28 | 29 | void onChildItemLongClick(int position,int groupPosition, int childPosition, View view); 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /expandable-recyclerview/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ExpandableRecyclerView 3 | 4 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /screenshot/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drawthink/ExpandableRecyclerView/468f5397d8d9d49518bd981976744514efd5313d/screenshot/screenshot.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':demo' 2 | --------------------------------------------------------------------------------