├── .gitignore ├── .idea ├── assetWizardSettings.xml ├── caches │ └── build_file_checksums.ser ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── baozi │ │ └── treerecyclerview │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── baozi │ │ └── treerecyclerview │ │ ├── adpater │ │ ├── TreeRecyclerAdapter.java │ │ ├── TreeRecyclerType.java │ │ └── wrapper │ │ │ ├── BaseWrapper.java │ │ │ ├── HeaderWrapper.java │ │ │ ├── LoadingWrapper.java │ │ │ ├── SwipeWrapper.java │ │ │ └── TreeLoadWrapper.java │ │ ├── annotation │ │ ├── TreeDataType.java │ │ └── TreeItemType.java │ │ ├── base │ │ ├── BaseRecyclerAdapter.java │ │ └── ViewHolder.java │ │ ├── factory │ │ ├── ItemConfig.java │ │ └── ItemHelperFactory.java │ │ ├── item │ │ ├── SimpleTreeItem.java │ │ ├── SwipeItem.java │ │ ├── TreeItem.java │ │ ├── TreeItemGroup.java │ │ ├── TreeSelectItemGroup.java │ │ └── TreeSortItem.java │ │ ├── manager │ │ ├── ItemManageImpl.java │ │ └── ItemManager.java │ │ └── widget │ │ ├── DragSelectRecyclerAdapter.java │ │ ├── DragSelectRecyclerView.java │ │ ├── TreeSortAdapter.java │ │ └── swipe │ │ ├── SwipeItemMangerInterface.java │ │ ├── SwipeLayout.java │ │ └── SwipeMode.java │ └── res │ └── values │ ├── attr.xml │ └── values.xml ├── build.gradle ├── demo ├── .gitignore ├── build.gradle ├── libs │ └── fastjson-1.2.9.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── baozi │ │ └── demo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── city.txt │ │ └── test.html │ ├── java │ │ └── com │ │ │ └── baozi │ │ │ └── demo │ │ │ ├── activity │ │ │ ├── CartAt.java │ │ │ ├── CityAt.java │ │ │ ├── MainActivity.java │ │ │ ├── SortAt.java │ │ │ ├── SwipeSortAt.java │ │ │ ├── TBActivity.java │ │ │ └── TestActivity.kt │ │ │ ├── fragment │ │ │ ├── ClickLoadFg.java │ │ │ ├── GalleryFg.java │ │ │ ├── MineFg.java │ │ │ ├── NewsFg.java │ │ │ └── SimpleRecyclerViewFg.java │ │ │ └── item │ │ │ ├── cart │ │ │ ├── CartBean.java │ │ │ ├── CartGroupItem.java │ │ │ ├── CartGroupItem2.java │ │ │ ├── CartGroupItem3.java │ │ │ └── CartItem.java │ │ │ ├── city │ │ │ ├── AreaItem.java │ │ │ ├── CountyItem.java │ │ │ ├── ProvinceBean.java │ │ │ └── ProvinceItem.java │ │ │ ├── clickload │ │ │ ├── ClickLoadChildItem.java │ │ │ └── ClickLoadGroupItem.java │ │ │ ├── mine │ │ │ ├── MineCategoryBean.java │ │ │ ├── MineCategoryItem.java │ │ │ ├── MineHeadItem.java │ │ │ └── MineItem.java │ │ │ ├── news │ │ │ ├── NewsImageItem.java │ │ │ ├── NewsItem.java │ │ │ └── NewsItemBean.java │ │ │ ├── sort │ │ │ ├── IndexBar.java │ │ │ ├── SortChildItem.java │ │ │ └── SortGroupItem.java │ │ │ ├── swipe │ │ │ └── SwipeSortItem.java │ │ │ └── tbhome │ │ │ ├── GoodsItem.java │ │ │ ├── HomeCategoryItem.java │ │ │ ├── HomeItemA.java │ │ │ ├── HomeItemB.java │ │ │ ├── HomeItemC.java │ │ │ ├── HomeItemD.java │ │ │ ├── HomeItemE.java │ │ │ └── HomeItemF.java │ └── res │ │ ├── drawable │ │ ├── bg_title.xml │ │ ├── ic_keyboard_arrow_down_black_24dp.xml │ │ ├── ic_keyboard_arrow_right_black_24dp.xml │ │ ├── ic_person_black_24dp.xml │ │ ├── ic_photo_24dp.xml │ │ └── shape_radius30_stroke1_gray_333.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_shopping_cart.xml │ │ ├── activity_sort.xml │ │ ├── activity_tb_home.xml │ │ ├── at_test.xml │ │ ├── item_brand_title.xml │ │ ├── item_cart_child.xml │ │ ├── item_cart_group.xml │ │ ├── item_grallery.xml │ │ ├── item_image.xml │ │ ├── item_mine.xml │ │ ├── item_mine_category.xml │ │ ├── item_mine_head.xml │ │ ├── item_news_foot.xml │ │ ├── item_news_image.xml │ │ ├── item_news_title.xml │ │ ├── item_sort_child.xml │ │ ├── item_sort_group.xml │ │ ├── item_tb_goods.xml │ │ ├── item_tb_home_a.xml │ │ ├── item_tb_home_b.xml │ │ ├── item_tb_home_c.xml │ │ ├── item_tb_home_d.xml │ │ ├── item_tb_home_e.xml │ │ ├── item_tb_home_f.xml │ │ ├── item_test_group.xml │ │ ├── item_three.xml │ │ ├── item_two.xml │ │ ├── itme_one.xml │ │ ├── layout_delete.xml │ │ ├── layout_empty.xml │ │ ├── layout_loading.xml │ │ └── layout_rv_content.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── baozi │ └── demo │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── 20180928114547.png ├── 20180928114623.png ├── 20180928114648.png ├── 20180928120846.png ├── 20180928120934.png ├── 20180928145931.png └── wx.jpg └── 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 | /.idea/ 10 | -------------------------------------------------------------------------------- /.idea/assetWizardSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 51 | 52 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jlanglang/TreeRecyclerView/6f454078ecd9f05619bb1d44b282d6d758f7ffeb/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | xmlns:android 11 | 12 | ^$ 13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 | 21 | xmlns:.* 22 | 23 | ^$ 24 | 25 | 26 | BY_NAME 27 | 28 |
29 |
30 | 31 | 32 | 33 | .*:id 34 | 35 | http://schemas.android.com/apk/res/android 36 | 37 | 38 | 39 |
40 |
41 | 42 | 43 | 44 | .*:name 45 | 46 | http://schemas.android.com/apk/res/android 47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | 55 | name 56 | 57 | ^$ 58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 | style 67 | 68 | ^$ 69 | 70 | 71 | 72 |
73 |
74 | 75 | 76 | 77 | .* 78 | 79 | ^$ 80 | 81 | 82 | BY_NAME 83 | 84 |
85 |
86 | 87 | 88 | 89 | .* 90 | 91 | http://schemas.android.com/apk/res/android 92 | 93 | 94 | ANDROID_ATTRIBUTE_ORDER 95 | 96 |
97 |
98 | 99 | 100 | 101 | .* 102 | 103 | .* 104 | 105 | 106 | BY_NAME 107 | 108 |
109 |
110 |
111 |
112 |
113 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 54 | 55 | 59 | 60 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 54 | 55 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2021-3-7更新 2 | 3 | 1.优化了获取注解的逻辑,减少了读取class的注解的次数 4 | 5 | 2.ItemManager新增了setTag.getTag方法,可以通过该方法绑定Activity或者Fragment等对象.在TreeItem可以获取该对象 6 | 7 | 3.TreeItem新增了init方法,可以做一些初始化设置,比如默认是否展开等等 8 | 9 | 4.新增了getItemOffsets的重写函数,与ItemDecoration接口保持一致(旧的方法依旧保留) 10 | 11 | 12 | 13 | # 更新 14 | 15 | 新增androidx分支.转换支持androidX 16 | 版本号:v1.3.1-androidx 17 | 18 | 新增Kotlin版本分支. 19 | 版本号v1.3.1-kt 20 | 21 | 996.icu 22 | [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE) 23 | 24 | # 特点 25 | 26 | ``` 27 | 1.支持实现树形结构列表及大部分列表样式 28 | 2.每一种条目的逻辑独立,充分解耦,支持复用 29 | 3.支持组件化 30 | 4.支持服务器动态下发,动态组合 31 | 5.侵入性低,不修改RecyclerView原有特性 32 | ``` 33 | 34 | 35 | # 示例图: 36 | 37 | ![image](https://github.com/Jlanglang/TreeRecyclerView/blob/master/image/20180928114547.png) 38 | ![image](https://github.com/Jlanglang/TreeRecyclerView/blob/master/image/20180928114623.png) 39 | ![image](https://github.com/Jlanglang/TreeRecyclerView/blob/master/image/20180928114648.png) 40 | ![image](https://github.com/Jlanglang/TreeRecyclerView/blob/master/image/20180928120846.png) 41 | ![image](https://github.com/Jlanglang/TreeRecyclerView/blob/master/image/20180928120934.png) 42 | ![image](https://github.com/Jlanglang/TreeRecyclerView/blob/master/image/20180928145931.png) 43 | ##### 以上示例都只使用了一个RecyclerView,没有嵌套 44 | 45 | 46 | # 依赖方式 47 | ``` 48 | implementation 'com.github.Jlanglang:TreeRecyclerView:1.3.1.1' 49 | ``` 50 | 根build.gradle里面添加 51 | ``` 52 | repositories { 53 | maven { url 'https://jitpack.io' } 54 | } 55 | ``` 56 | 57 | --- 58 | 59 | 60 | # 如何使用: 61 | 62 | ## 一.你需要创建一个adapter: 63 | ``` 64 | //可折叠 65 | TreeRecyclerAdapter treeRecyclerAdapter = new TreeRecyclerAdapter(TreeRecyclerType.SHOW_EXPAND); 66 | ``` 67 | 68 | ## 二.你需要选择一种展开方式 69 | ``` 70 | public enum TreeRecyclerType { 71 | /** 72 | * 显示所有,不可展开折叠 73 | * 适用场景,不需要折叠,默认显示所有item 74 | */ 75 | SHOW_ALL, 76 | 77 | /** 78 | * 根据isExpand的状态显示展开与折叠, 79 | * 适用场景,多级的data数据展示,保存展开状态 80 | */ 81 | SHOW_EXPAND, 82 | 83 | /** 84 | * 默认只显示第一级,点击展开,折叠不会影响子级展开折叠 85 | * 适用场景,一级一级展开,保存展开状态 86 | */ 87 | SHOW_DEFAULT 88 | } 89 | ``` 90 | 91 | 构造函数传入,不传默认则使用`SHOW_DEFAULT`. 92 | 93 | # 三.怎么写Item 94 | 95 | 注意! 使用这个,没有写`ViewHolder`的概念,只有`TreeItem`和`TreeItemGroup`.子级和父级. 96 | 97 | #### 父级示例: 98 | ``` 99 | /** 100 | * 城市 101 | */ 102 | public class CountyItemParent extends TreeItemGroup {//泛型代表绑定的javabean 103 | 104 | //创建子TreeItem. 105 | @Override 106 | public List initChildList(ProvinceBean.CityBean data) { 107 | return ItemHelperFactory.createItems(data.getAreas(), this); 108 | } 109 | 110 | //该级具体展示的Layout 111 | @Override 112 | public int getLayoutId() { 113 | return R.layout.item_two; 114 | } 115 | 116 | //view和data绑定 117 | @Override 118 | public void onBindViewHolder(@NonNull ViewHolder holder) { 119 | holder.setText(R.id.tv_content, data.getCityName()); 120 | } 121 | } 122 | ``` 123 | 124 | 125 | #### 子级示例: 126 | ``` 127 | /** 128 | * 县 129 | */ 130 | public class AreaItem extends TreeItem {//泛型代表绑定的javabean 131 | 132 | @Override 133 | public int getLayoutId() { 134 | return R.layout.item_three; 135 | } 136 | //绑定操作, 137 | @Override 138 | public void onBindViewHolder(@NonNull ViewHolder holder) { 139 | holder.setText(R.id.tv_content, data.getAreaName()); 140 | } 141 | //这个Item,在RecyclerView的每行所占比,只有RecyclerView设置了GridLayoutManager才会生效. 142 | //这里之所以用除法,是为了可以做到,只改变GridLayoutManager的总数,无需改变每个Item,当然也可以直接返回一个int值. 143 | @Override 144 | public int getSpanSize(int maxSpan) { 145 | return maxSpan / 6; 146 | } 147 | } 148 | 149 | ``` 150 | 151 | # 怎么创建Item: 152 | 153 | 有两种方法: 154 | 155 | #### 第一种: 156 | 157 | 在javabean上使用注解, 158 | ``` 159 | @TreeDataType(iClass = AreaItem.class) 160 | public class AreasBean{ 161 | ... 162 | } 163 | ``` 164 | 然后传入bean对象 165 | ``` 166 | ItemHelperFactory.createItems(list, treeItemGroup); 167 | ``` 168 | 169 | #### 第二种: 170 | 171 | 直接传入bean对象和item的class, 172 | ``` 173 | ItemHelperFactory.createItems(list, Item.class, treeItemGroup); 174 | ``` 175 | 176 | --- 177 | 178 | # 四.如何更新adapter: 179 | 180 | 增删该查都有. 181 | 182 | ``` 183 | treeRecyclerAdapter.getItemManager().replaceAllItem(items);// 替换全部Item 184 | treeRecyclerAdapter.getItemManager().addItems(items);// 添加一组Item 185 | treeRecyclerAdapter.getItemManager().removeItems(items);// 添加一组Item 186 | ``` 187 | 188 | #### 在item里面也是可以更新的: 189 | 190 | ``` 191 | @Override 192 | public void onClick(ViewHolder viewHolder) { 193 | super.onClick(viewHolder); 194 | getItemManager().notifyDataChanged(); 195 | } 196 | ``` 197 | 198 | # 五,如何设置Item点击: 199 | 200 | 1.重写`TreeItem`的`onClick()` 201 | 202 | 2.`adapter`设置`setOnItemClickListener` 203 | ``` 204 | adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() { 205 | @Override 206 | public void onItemClick(@NonNull ViewHolder viewHolder, int position) { 207 | 208 | } 209 | }); 210 | ``` 211 | ##### 注意.二者冲突. 212 | `ItemClickListener`优先级高于`TreeItem`的`onClick`. 213 | 214 | 215 | # 如果不想写上面的Item类怎么办? 216 | 217 | 使用`SimpleTreeItem` 218 | 219 | ``` 220 | ArrayList items = new ArrayList<>(); 221 | for (Pair itemPair : itemPairs) { 222 | SimpleTreeItem simpleTreeItem = new SimpleTreeItem(R.layout.item_mine)//传入布局id. 223 | .onItemBind(viewHolder -> { 224 | 225 | }) 226 | .onItemClick(viewHolder -> { 227 | 228 | }); 229 | simpleTreeItem.setData(itemPair); 230 | items.add(simpleTreeItem); 231 | } 232 | adapter.getItemManager().replaceAllItem(items); 233 | ``` 234 | 235 | # 混淆 236 | ``` 237 | -keep public class * extends com.baozi.treerecyclerview.item.TreeItem {} 238 | -keep public class * extends android.support.annotation.** 239 | 240 | ``` 241 | 242 | # 最后 243 | 244 | 直接设置就行了.adapter可以不先setData 245 | 可以直接setAdapter.然后`adapter.getItemManager().replaceAllItem(items);` 246 | 247 | 248 | ``` 249 | recyclerView.setAdapter(adapter); 250 | ``` 251 | 252 | 253 | 254 | 更多效果.见demo 255 | ### 欢迎大家留言,提出问题. QQ交流群:493180098 256 | 257 | 258 | 259 | 260 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "28.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 22 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 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'com.android.support:appcompat-v7:28.0.0' 24 | implementation 'com.android.support:recyclerview-v7:28.0.0' 25 | implementation 'com.android.support:design:28.0.0' 26 | 27 | } 28 | -------------------------------------------------------------------------------- /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 J:\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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/baozi/treerecyclerview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/adpater/TreeRecyclerType.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.adpater; 2 | 3 | public enum TreeRecyclerType { 4 | /** 5 | * 显示所有,不可展开折叠 6 | * 适用场景,不需要折叠,默认显示所有item 7 | */ 8 | SHOW_ALL, 9 | 10 | /** 11 | * 默认只显示第一级,点击展开,折叠不会影响子级展开折叠 12 | * 根据isExpand的状态显示展开与折叠, 13 | * 适用场景,多级的data数据展示,保存展开状态 14 | */ 15 | SHOW_EXPAND, 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/adpater/wrapper/BaseWrapper.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.adpater.wrapper; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.manager.ItemManager; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Created by baozi on 2017/5/16. 16 | */ 17 | 18 | public class BaseWrapper extends BaseRecyclerAdapter { 19 | 20 | protected BaseRecyclerAdapter mAdapter; 21 | 22 | public BaseWrapper(BaseRecyclerAdapter adapter) { 23 | mAdapter = adapter; 24 | mAdapter.getItemManager().setAdapter(this); 25 | } 26 | 27 | @Override 28 | public void onBindViewHolderClick(@NonNull ViewHolder holder, View view) { 29 | mAdapter.onBindViewHolderClick(holder, view); 30 | } 31 | 32 | @NonNull 33 | @Override 34 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 35 | return mAdapter.onCreateViewHolder(parent, viewType); 36 | } 37 | 38 | @Override 39 | public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { 40 | mAdapter.onAttachedToRecyclerView(recyclerView); 41 | } 42 | 43 | @Override 44 | public void onViewAttachedToWindow(@NonNull ViewHolder holder) { 45 | mAdapter.onViewAttachedToWindow(holder); 46 | } 47 | 48 | @Override 49 | public int getItemViewType(int position) { 50 | return mAdapter.getItemViewType(position); 51 | } 52 | 53 | @Override 54 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 55 | mAdapter.onBindViewHolder(holder, position); 56 | } 57 | 58 | @Override 59 | public int getItemCount() { 60 | return mAdapter.getItemCount(); 61 | } 62 | 63 | 64 | @Override 65 | public int getLayoutId(int position) { 66 | return mAdapter.getLayoutId(position); 67 | } 68 | 69 | @Override 70 | public T getData(int position) { 71 | return mAdapter.getData(position); 72 | } 73 | 74 | @Override 75 | public List getData() { 76 | return mAdapter.getData(); 77 | } 78 | 79 | @Override 80 | public void setData(List data) { 81 | mAdapter.setData(data); 82 | } 83 | 84 | @Override 85 | public void onBindViewHolder(@NonNull ViewHolder holder, T t, int position) { 86 | mAdapter.onBindViewHolder(holder, t, position); 87 | } 88 | 89 | @Override 90 | public int checkPosition(int position) { 91 | return mAdapter.checkPosition(position); 92 | } 93 | 94 | 95 | @Override 96 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 97 | mAdapter.setOnItemClickListener(onItemClickListener); 98 | } 99 | 100 | @Override 101 | public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) { 102 | mAdapter.setOnItemLongClickListener(onItemLongClickListener); 103 | } 104 | 105 | @Override 106 | public int getItemSpanSize(int position, int maxSpan) { 107 | return mAdapter.getItemSpanSize(position, maxSpan); 108 | } 109 | 110 | @Override 111 | public ItemManager getItemManager() { 112 | return mAdapter.getItemManager(); 113 | } 114 | 115 | @Override 116 | public void setItemManager(ItemManager itemManager) { 117 | mAdapter.setItemManager(itemManager); 118 | } 119 | 120 | @Override 121 | public void clear() { 122 | mAdapter.clear(); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/adpater/wrapper/HeaderWrapper.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.adpater.wrapper; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.util.SparseArray; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 10 | import com.baozi.treerecyclerview.base.ViewHolder; 11 | import com.baozi.treerecyclerview.item.TreeItem; 12 | import com.baozi.treerecyclerview.manager.ItemManager; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by baozi on 2017/4/30. 18 | * 在最后一个,优先级高于loadwrapper, 19 | */ 20 | public class HeaderWrapper extends BaseWrapper { 21 | private static final int HEAD_ITEM = 1000; 22 | private SparseArray mHeaderViews = new SparseArray<>(); 23 | private boolean headShow = true; 24 | private int mHeaderSize; 25 | 26 | public HeaderWrapper(BaseRecyclerAdapter adapter) { 27 | super(adapter); 28 | getItemManager().addCheckItemInterfaces(new ItemManager.CheckItemInterface() { 29 | @Override 30 | public int itemToDataPosition(int position) { 31 | return position - getHeadersCount(); 32 | } 33 | 34 | @Override 35 | public int dataToItemPosition(int index) { 36 | return index + getHeadersCount(); 37 | } 38 | }); 39 | } 40 | 41 | @Override 42 | public T getData(int position) { 43 | return mAdapter.getData(position); 44 | } 45 | 46 | @NonNull 47 | @Override 48 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 49 | if (mHeaderViews.get(viewType) != null) { 50 | return ViewHolder.createViewHolder(mHeaderViews.get(viewType)); 51 | } 52 | return mAdapter.onCreateViewHolder(parent, viewType); 53 | } 54 | 55 | @Override 56 | public void onBindViewHolderClick(@NonNull ViewHolder holder, View view) { 57 | int layoutPosition = holder.getLayoutPosition(); 58 | if (isHeaderViewPos(layoutPosition)) { 59 | return; 60 | } 61 | super.onBindViewHolderClick(holder, view); 62 | } 63 | 64 | @Override 65 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 66 | if (isHeaderViewPos(position)) { 67 | return; 68 | } 69 | super.onBindViewHolder(holder, position - getHeadersCount()); 70 | } 71 | 72 | @Override 73 | public int getItemCount() { 74 | return getHeadersCount() + mAdapter.getItemCount(); 75 | } 76 | 77 | 78 | @Override 79 | public int getItemSpanSize(int position, int maxSpan) { 80 | if (isHeaderViewPos(position)) { 81 | return maxSpan; 82 | } 83 | return super.getItemSpanSize(position, maxSpan); 84 | } 85 | 86 | @Override 87 | public int getItemViewType(int position) { 88 | if (isHeaderViewPos(position)) { 89 | return mHeaderViews.keyAt(position); 90 | } 91 | return super.getItemViewType(position - getHeadersCount()); 92 | } 93 | 94 | 95 | public void addHeaderView(View view) { 96 | int size = mHeaderViews.size(); 97 | mHeaderViews.put(HEAD_ITEM + size, view); 98 | mHeaderSize++; 99 | } 100 | 101 | protected boolean isHeaderViewPos(int position) { 102 | return position < getHeadersCount(); 103 | } 104 | 105 | public void setShowHeadView(boolean show) { 106 | this.headShow = show; 107 | int size = mHeaderViews.size(); 108 | for (int i = 0; i < size; i++) { 109 | View view = mHeaderViews.valueAt(i); 110 | view.setVisibility(show ? View.VISIBLE : View.GONE); 111 | } 112 | } 113 | 114 | public int getHeadersCount() { 115 | if (!headShow) { 116 | return 0; 117 | } 118 | return mHeaderSize; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/annotation/TreeDataType.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Created by 125C01063144 on 2018/2/27. 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.TYPE) 13 | public @interface TreeDataType { 14 | /** 15 | * 要绑定的item 16 | */ 17 | Class iClass() default Object.class; 18 | 19 | String bindField() default ""; 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/annotation/TreeItemType.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.annotation; 2 | 3 | 4 | import android.support.annotation.LayoutRes; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * Created by baozi on 2018/2/27. 13 | * 如果使用在item的类上 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ElementType.FIELD, ElementType.TYPE}) 17 | public @interface TreeItemType { 18 | /** 19 | * 映射的type值 20 | * 21 | * @return [type1, type2] 22 | */ 23 | String[] type(); 24 | 25 | /** 26 | * item的列占比 27 | * 28 | * @return 默认返回0, 也就是不设置 29 | */ 30 | int spanSize() default 0; 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/base/BaseRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.base; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.baozi.treerecyclerview.manager.ItemManageImpl; 10 | import com.baozi.treerecyclerview.manager.ItemManager; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by zhy on 16/4/9. 17 | */ 18 | public abstract class BaseRecyclerAdapter extends RecyclerView.Adapter { 19 | 20 | protected ItemManager mItemManager; 21 | protected OnItemClickListener mOnItemClickListener; 22 | protected OnItemLongClickListener mOnItemLongClickListener; 23 | private List data; 24 | 25 | @NonNull 26 | @Override 27 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 28 | ViewHolder holder = ViewHolder.createViewHolder(parent, viewType); 29 | onBindViewHolderClick(holder, holder.itemView); 30 | return holder; 31 | } 32 | 33 | @Override 34 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 35 | onBindViewHolder(holder, getData(position), position); 36 | } 37 | 38 | /** 39 | * 实现item的点击事件 40 | */ 41 | public void onBindViewHolderClick(@NonNull final ViewHolder viewHolder, View view) { 42 | //判断当前holder是否已经设置了点击事件 43 | if (!view.hasOnClickListeners()) { 44 | view.setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | //获得holder的position 48 | int layoutPosition = viewHolder.getLayoutPosition(); 49 | //检查item的position,是否可以点击. 50 | // 检查并得到真实的position 51 | int itemPosition = getItemManager().itemToDataPosition(layoutPosition); 52 | if (mOnItemClickListener != null) { 53 | mOnItemClickListener.onItemClick(viewHolder, itemPosition); 54 | } 55 | } 56 | }); 57 | } 58 | if (!view.isLongClickable()) { 59 | view.setOnLongClickListener(new View.OnLongClickListener() { 60 | @Override 61 | public boolean onLongClick(View v) { 62 | //获得holder的position 63 | int layoutPosition = viewHolder.getLayoutPosition(); 64 | //检查position是否可以点击 65 | //检查并得到真实的position 66 | int itemPosition = getItemManager().itemToDataPosition(layoutPosition); 67 | if (mOnItemLongClickListener != null) { 68 | return mOnItemLongClickListener.onItemLongClick(viewHolder, itemPosition); 69 | } 70 | return false; 71 | } 72 | }); 73 | } 74 | } 75 | 76 | @Override 77 | public int getItemViewType(int position) { 78 | return getLayoutId(position); 79 | } 80 | 81 | @Override 82 | public int getItemCount() { 83 | return getData().size(); 84 | } 85 | 86 | 87 | public int getItemSpanSize(int position, int maxSpan) { 88 | return maxSpan; 89 | } 90 | 91 | public List getData() { 92 | if (data == null) { 93 | data = new ArrayList<>(); 94 | } 95 | return data; 96 | } 97 | 98 | public void setData(List data) { 99 | if (data != null) { 100 | getData().clear(); 101 | getData().addAll(data); 102 | } 103 | } 104 | 105 | @Nullable 106 | public T getData(int position) { 107 | if (position >= 0) { 108 | return getData().get(position); 109 | } 110 | return null; 111 | } 112 | 113 | /** 114 | * 直接强转为指定类型,可以能null 115 | * 116 | * @param position 117 | * @param 118 | * @return 119 | */ 120 | public D getCastData(int position) { 121 | try { 122 | return (D) getData(position); 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | return null; 126 | } 127 | } 128 | 129 | /** 130 | * 操作adapter 131 | * 132 | * @return 133 | */ 134 | public ItemManager getItemManager() { 135 | if (mItemManager == null) { 136 | mItemManager = new ItemManageImpl(this); 137 | } 138 | return mItemManager; 139 | } 140 | 141 | public void setItemManager(ItemManager itemManager) { 142 | mItemManager = itemManager; 143 | } 144 | 145 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 146 | mOnItemClickListener = onItemClickListener; 147 | } 148 | 149 | public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) { 150 | mOnItemLongClickListener = onItemLongClickListener; 151 | } 152 | 153 | 154 | public interface OnItemClickListener { 155 | void onItemClick(@NonNull ViewHolder viewHolder, int position); 156 | } 157 | 158 | public interface OnItemLongClickListener { 159 | boolean onItemLongClick(@NonNull ViewHolder viewHolder, int position); 160 | } 161 | 162 | //检查当前position,获取原始角标 163 | public int checkPosition(int position) { 164 | return getItemManager().itemToDataPosition(position); 165 | } 166 | 167 | 168 | /** 169 | * 获取该position的item的layout 170 | * 171 | * @param position 角标 172 | * @return item的layout id 173 | */ 174 | public abstract int getLayoutId(int position); 175 | 176 | /** 177 | * view与数据绑定 178 | * 179 | * @param holder ViewHolder 180 | * @param t 数据类型 181 | * @param position position 182 | */ 183 | public void onBindViewHolder(@NonNull ViewHolder holder, T t, int position) { 184 | 185 | } 186 | 187 | public void clear() { 188 | getData().clear(); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/factory/ItemConfig.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.factory; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.text.TextUtils; 6 | import android.util.SparseArray; 7 | 8 | import com.baozi.treerecyclerview.annotation.TreeDataType; 9 | import com.baozi.treerecyclerview.annotation.TreeItemType; 10 | import com.baozi.treerecyclerview.item.TreeItem; 11 | 12 | import java.lang.annotation.Annotation; 13 | import java.lang.reflect.Field; 14 | import java.util.HashMap; 15 | 16 | public class ItemConfig { 17 | /** 18 | * type,TreeClass映射 19 | */ 20 | private static final HashMap> treeViewHolderTypes = new HashMap<>(); 21 | /** 22 | * TreeDataType映射 23 | */ 24 | private static final HashMap treeDataTypeMap = new HashMap<>(); 25 | /** 26 | * TreeItemType映射 27 | */ 28 | private static final HashMap treeItemTypeMap = new HashMap<>(); 29 | 30 | public static Class getTreeViewHolderType(String type) { 31 | return treeViewHolderTypes.get(type); 32 | } 33 | 34 | public static void register(String type, Class clazz) { 35 | if (null == clazz) { 36 | return; 37 | } 38 | Class typeClass = treeViewHolderTypes.get(type); 39 | if (typeClass == null) { 40 | treeViewHolderTypes.put(type, clazz); 41 | return; 42 | } 43 | if (clazz != typeClass) {//如果该type,已经添加了,则抛出异常 44 | throw new IllegalStateException("该type映射了" + typeClass.getSimpleName() + "不能再映射其他TreeItem"); 45 | } 46 | } 47 | 48 | public static void register(Class zClass) { 49 | if (treeItemTypeMap.get(zClass) != null) { 50 | return; 51 | } 52 | TreeItemType annotation = zClass.getAnnotation(TreeItemType.class); 53 | if (annotation != null) { 54 | treeItemTypeMap.put(zClass, annotation); 55 | String[] typeList = annotation.type(); 56 | for (String type : typeList) { 57 | register(type, zClass); 58 | } 59 | } 60 | } 61 | 62 | @SafeVarargs 63 | public static void register(@NonNull Class... clazz) { 64 | for (Class zClass : clazz) { 65 | register(zClass); 66 | } 67 | } 68 | 69 | /** 70 | * 获取TreeItem的Class 71 | * 72 | * @param data 73 | * @return 74 | */ 75 | @Nullable 76 | public static Class getTypeClass(Object data) { 77 | Class dataClass = data.getClass(); 78 | //先判断是否继承了ItemData,适用于跨模块获取 79 | //判断是否使用注解绑定了ItemClass,适用当前模块 80 | TreeDataType treeDataType = treeDataTypeMap.get(dataClass); 81 | if (treeDataType == null) { 82 | treeDataType = dataClass.getAnnotation(TreeDataType.class); 83 | } 84 | if (treeDataType != null) { 85 | //缓存注解 86 | treeDataTypeMap.put(dataClass, treeDataType); 87 | 88 | String key = treeDataType.bindField(); 89 | if (!TextUtils.isEmpty(key)) { 90 | try { 91 | Field field = dataClass.getField(key); 92 | String type = field.get(data).toString(); 93 | Class itemClass = getTreeViewHolderType(type); 94 | return itemClass; 95 | } catch (NoSuchFieldException e) { 96 | e.printStackTrace(); 97 | } catch (IllegalAccessException e) { 98 | e.printStackTrace(); 99 | } 100 | } 101 | return treeDataType.iClass(); 102 | } 103 | return null; 104 | } 105 | } -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/factory/ItemHelperFactory.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.factory; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | 8 | import com.baozi.treerecyclerview.adpater.TreeRecyclerType; 9 | import com.baozi.treerecyclerview.annotation.TreeDataType; 10 | import com.baozi.treerecyclerview.annotation.TreeItemType; 11 | import com.baozi.treerecyclerview.item.TreeItem; 12 | import com.baozi.treerecyclerview.item.TreeItemGroup; 13 | 14 | import java.lang.annotation.Annotation; 15 | import java.lang.reflect.Field; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | 20 | /** 21 | * Created by baozi on 2017/4/29. 22 | */ 23 | 24 | public class ItemHelperFactory { 25 | private static final HashMap> classCacheMap = new HashMap<>(); 26 | 27 | public static List createItems(@Nullable List list) { 28 | return createItems(list, null, null); 29 | } 30 | 31 | public static List createItems(@Nullable List list, @Nullable TreeItemGroup treeParentItem) { 32 | return createItems(list, null, treeParentItem); 33 | } 34 | 35 | public static List createItems(@Nullable List list, Class iClass) { 36 | return createItems(list, iClass, null); 37 | } 38 | 39 | public static List createItems(@Nullable List list, Class iClass, @Nullable TreeItemGroup treeParentItem) { 40 | if (null == list) { 41 | return null; 42 | } 43 | int size = list.size(); 44 | ArrayList treeItemList = new ArrayList<>(); 45 | for (int i = 0; i < size; i++) { 46 | Object itemData = list.get(i); 47 | TreeItem treeItem = createItem(itemData, iClass, treeParentItem); 48 | if (treeItem != null) { 49 | treeItemList.add(treeItem); 50 | } 51 | } 52 | return treeItemList; 53 | } 54 | 55 | /** 56 | * 确定item的class类型,并且添加到了itemConfig,用该方法创建TreeItem 57 | * 58 | * @return 59 | */ 60 | public static TreeItem createItem(Object d) { 61 | return createItem(d, null, null); 62 | } 63 | 64 | @Nullable 65 | public static TreeItem createItem(Object data, @Nullable TreeItemGroup treeParentItem) { 66 | return createItem(data, null, treeParentItem); 67 | } 68 | 69 | @Nullable 70 | public static TreeItem createItem(Object data, @Nullable Class zClass) { 71 | return createItem(data, zClass, null); 72 | } 73 | 74 | @Nullable 75 | public static TreeItem createItem(Object data, @Nullable Class zClass, @Nullable TreeItemGroup treeParentItem) { 76 | TreeItem treeItem = null; 77 | Class treeItemClass; 78 | try { 79 | if (zClass != null) { 80 | treeItemClass = zClass; 81 | ItemConfig.register(zClass); 82 | } else { 83 | treeItemClass = ItemConfig.getTypeClass(data); 84 | //判断是否是TreeItem的子类 85 | } 86 | if (treeItemClass != null) { 87 | treeItem = treeItemClass.newInstance(); 88 | treeItem.setData(data); 89 | treeItem.setParentItem(treeParentItem); 90 | TreeItemType annotation = treeItemClass.getAnnotation(TreeItemType.class); 91 | if (annotation != null) { 92 | int spanSize = annotation.spanSize(); 93 | treeItem.setSpanSize(spanSize); 94 | } 95 | } 96 | } catch (ClassCastException e) { 97 | Log.w("ClassCastException", "传入的data与item定义的data泛型不一致"); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } 101 | return treeItem; 102 | } 103 | 104 | 105 | /** 106 | * 根据TreeRecyclerType获取子item集合,不包含TreeItemGroup自身 107 | * 108 | * @param itemGroup 109 | * @param type 110 | * @return 111 | */ 112 | @NonNull 113 | public static ArrayList getChildItemsWithType(@Nullable TreeItemGroup itemGroup, @NonNull TreeRecyclerType type) { 114 | if (itemGroup == null) { 115 | return new ArrayList(); 116 | } 117 | return getChildItemsWithType(itemGroup.getChild(), type); 118 | } 119 | 120 | @NonNull 121 | public static ArrayList getChildItemsWithType(@Nullable List items, @NonNull TreeRecyclerType type) { 122 | ArrayList returnItems = new ArrayList<>(); 123 | if (items == null) { 124 | return returnItems; 125 | } 126 | int childCount = items.size(); 127 | for (int i = 0; i < childCount; i++) { 128 | TreeItem childItem = items.get(i);//获取当前一级 129 | returnItems.add(childItem); 130 | if (childItem instanceof TreeItemGroup) {//获取下一级 131 | List list = null; 132 | switch (type) { 133 | case SHOW_ALL: 134 | //调用下级的getAllChild遍历,相当于递归遍历 135 | list = getChildItemsWithType((TreeItemGroup) childItem, type); 136 | break; 137 | case SHOW_EXPAND: 138 | //根据isExpand,来决定是否展示 139 | if (((TreeItemGroup) childItem).isExpand()) { 140 | list = getChildItemsWithType((TreeItemGroup) childItem, type); 141 | } 142 | break; 143 | } 144 | if (list != null && list.size() > 0) { 145 | returnItems.addAll(list); 146 | } 147 | } 148 | } 149 | return returnItems; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/item/SimpleTreeItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.item; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.treerecyclerview.base.ViewHolder; 8 | 9 | /** 10 | * 简单样式的item 11 | */ 12 | public class SimpleTreeItem extends TreeItem { 13 | private int layout; 14 | private int spanSize; 15 | private Consumer treeClick; 16 | private Consumer treeBind; 17 | private Rect treeRect; 18 | 19 | public SimpleTreeItem() { 20 | this(0, 0); 21 | } 22 | 23 | public SimpleTreeItem(int layout) { 24 | this(layout, 0); 25 | } 26 | 27 | public SimpleTreeItem(int layout, int spanSize) { 28 | this.layout = layout; 29 | this.spanSize = spanSize; 30 | } 31 | 32 | @Override 33 | public int getLayoutId() { 34 | return layout; 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 39 | if (treeBind != null) { 40 | treeBind.accept(viewHolder); 41 | } 42 | } 43 | 44 | @Override 45 | public void onClick(ViewHolder viewHolder) { 46 | if (treeClick != null) { 47 | treeClick.accept(viewHolder); 48 | } 49 | } 50 | 51 | @Override 52 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 53 | if (treeRect != null) { 54 | outRect.set(treeRect); 55 | } 56 | } 57 | 58 | @Override 59 | public int getSpanSize(int maxSpan) { 60 | return spanSize == 0 ? spanSize : maxSpan / spanSize; 61 | } 62 | 63 | public interface Consumer { 64 | void accept(T t); 65 | } 66 | 67 | public SimpleTreeItem onItemClick(Consumer treeClick) { 68 | this.treeClick = treeClick; 69 | return this; 70 | } 71 | 72 | public SimpleTreeItem onItemBind(Consumer treeOnBind) { 73 | this.treeBind = treeOnBind; 74 | return this; 75 | } 76 | 77 | public SimpleTreeItem setTreeOffset(Rect outRect) { 78 | this.treeRect = outRect; 79 | return this; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/item/SwipeItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.item; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.treerecyclerview.base.ViewHolder; 6 | import com.baozi.treerecyclerview.widget.swipe.SwipeItemMangerInterface; 7 | import com.baozi.treerecyclerview.widget.swipe.SwipeLayout; 8 | 9 | /** 10 | * Created by Administrator on 2017/8/18 0018. 11 | * 实现该接口,侧滑删除 12 | */ 13 | 14 | public interface SwipeItem { 15 | 16 | int getSwipeLayoutId(); 17 | 18 | SwipeLayout.DragEdge getDragEdge(); 19 | 20 | void onBindSwipeView(@NonNull ViewHolder viewHolder, int position, SwipeItemMangerInterface swipeManger); 21 | 22 | void openCallback(); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/item/TreeItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.item; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.manager.ItemManager; 11 | 12 | /** 13 | * TreeRecyclerAdapter的item 14 | */ 15 | public abstract class TreeItem { 16 | /** 17 | * 当前item的数据 18 | */ 19 | protected D data; 20 | private TreeItemGroup parentItem; 21 | /** 22 | * item在每行中的spansize 23 | * 默认为0,如果为0则占满一行 24 | */ 25 | private int spanSize; 26 | private ItemManager mItemManager; 27 | 28 | public TreeItem() { 29 | init(); 30 | } 31 | 32 | protected void init() { 33 | } 34 | 35 | public void setParentItem(TreeItemGroup parentItem) { 36 | this.parentItem = parentItem; 37 | } 38 | 39 | /** 40 | * 获取当前item的父级 41 | */ 42 | @Nullable 43 | public TreeItemGroup getParentItem() { 44 | return parentItem; 45 | } 46 | 47 | /** 48 | * 应该在void onBindViewHolder(ViewHolder viewHolder)的地方使用. 49 | * 如果要使用,可能为null,请加判断. 50 | */ 51 | public ItemManager getItemManager() { 52 | return mItemManager; 53 | } 54 | 55 | public void setItemManager(ItemManager itemManager) { 56 | mItemManager = itemManager; 57 | } 58 | 59 | /** 60 | * 该条目的布局id 61 | * 62 | * @return 布局id 63 | */ 64 | public int getLayoutId() { 65 | return 0; 66 | } 67 | 68 | /** 69 | * @param maxSpan 总数 70 | */ 71 | public int getSpanSize(int maxSpan) { 72 | return spanSize == 0 ? maxSpan : spanSize; 73 | } 74 | 75 | 76 | public void setSpanSize(int spanSize) { 77 | this.spanSize = spanSize; 78 | } 79 | 80 | /** 81 | * 设置当前条目间隔 82 | * 废弃,2个版本后删除 83 | */ 84 | @Deprecated 85 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 86 | 87 | } 88 | 89 | /** 90 | * 设置当前条目间隔等 91 | */ 92 | public void getItemOffsets(Rect outRect, 93 | View view, 94 | RecyclerView parent, 95 | RecyclerView.State state, 96 | int checkPosition) { 97 | getItemOffsets(outRect, (RecyclerView.LayoutParams) view.getLayoutParams(), checkPosition); 98 | } 99 | 100 | public D getData() { 101 | return data; 102 | } 103 | 104 | public void setData(D data) { 105 | this.data = data; 106 | } 107 | 108 | /** 109 | * 抽象holder的绑定 110 | */ 111 | public abstract void onBindViewHolder(@NonNull ViewHolder viewHolder); 112 | 113 | /** 114 | * 当前条目的点击回调 115 | */ 116 | public void onClick(ViewHolder viewHolder) { 117 | 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/item/TreeItemGroup.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.item; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 7 | import com.baozi.treerecyclerview.adpater.TreeRecyclerType; 8 | import com.baozi.treerecyclerview.adpater.wrapper.BaseWrapper; 9 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 10 | import com.baozi.treerecyclerview.base.ViewHolder; 11 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 12 | import com.baozi.treerecyclerview.manager.ItemManager; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by baozi on 2016/12/22. 18 | * //拥有子集 19 | * //子集可以是parent,也可以是child 20 | * //可展开折叠 21 | */ 22 | 23 | public abstract class TreeItemGroup extends TreeItem { 24 | 25 | /** 26 | * 持有的子item 27 | */ 28 | private List child; 29 | 30 | /** 31 | * 是否展开 32 | */ 33 | private boolean isExpand; 34 | /** 35 | * 是否能展开 36 | */ 37 | private boolean isCanExpand = true; 38 | 39 | /** 40 | * 能否展开折叠 41 | */ 42 | public boolean isCanExpand() { 43 | return isCanExpand; 44 | } 45 | 46 | public void setCanExpand(boolean canExpand) { 47 | isCanExpand = canExpand; 48 | } 49 | 50 | public boolean isExpand() { 51 | return isExpand; 52 | } 53 | 54 | /** 55 | * 设置为传入 56 | * 57 | * @param expand 传入true则展开,传入false则折叠 58 | */ 59 | public final void setExpand(boolean expand) { 60 | if (!isCanExpand()) { 61 | return; 62 | } 63 | if (expand == isExpand) {//防止重复展开 64 | return; 65 | } 66 | isExpand = expand; 67 | if (expand) { 68 | onExpand(); 69 | } else { 70 | onCollapse(); 71 | } 72 | } 73 | 74 | /** 75 | * 展开 76 | */ 77 | protected void onExpand() { 78 | ItemManager itemManager = getItemManager(); 79 | if (itemManager == null) { 80 | return; 81 | } 82 | List child = this.getChild(); 83 | if (child == null || child.size() == 0) { 84 | isExpand = false; 85 | return; 86 | } 87 | int itemPosition = itemManager.getItemPosition(this); 88 | itemManager.addItems(itemPosition + 1, child); 89 | } 90 | 91 | /** 92 | * 折叠 93 | */ 94 | protected void onCollapse() { 95 | ItemManager itemManager = getItemManager(); 96 | if (itemManager == null) { 97 | return; 98 | } 99 | List child = this.getChild(); 100 | if (child == null || child.size() == 0) { 101 | isExpand = false; 102 | return; 103 | } 104 | itemManager.removeItems(child); 105 | } 106 | 107 | 108 | /** 109 | * 获得所有展开的childs,包括子item的childs 110 | * 111 | * @return 112 | */ 113 | @NonNull 114 | public List getExpandChild() { 115 | return ItemHelperFactory.getChildItemsWithType(this, TreeRecyclerType.SHOW_EXPAND); 116 | } 117 | 118 | 119 | public void setData(D data) { 120 | super.setData(data); 121 | child = initChild(data); 122 | } 123 | 124 | /** 125 | * 获得所有childs,包括下下....级item的childs 126 | * 127 | * @return 128 | */ 129 | @Nullable 130 | public List getAllChilds() { 131 | return ItemHelperFactory.getChildItemsWithType(this, TreeRecyclerType.SHOW_ALL); 132 | } 133 | 134 | /** 135 | * 获得自己的childs. 136 | * 137 | * @return 138 | */ 139 | @Nullable 140 | public List getChild() { 141 | return child; 142 | } 143 | 144 | 145 | public int getChildCount() { 146 | return child == null ? 0 : child.size(); 147 | } 148 | 149 | /** 150 | * 初始化子集 151 | * 152 | * @param data 153 | * @return 154 | */ 155 | @Nullable 156 | protected List initChild(D data) { 157 | return null; 158 | } 159 | 160 | /** 161 | * 是否消费child的click事件 162 | * 163 | * @param child 具体click的item 164 | * @return 返回true代表消费此次事件,child不会走onclick(),返回false说明不消费此次事件,child依然会走onclick() 165 | */ 166 | public boolean onInterceptClick(TreeItem child) { 167 | return false; 168 | } 169 | 170 | @Override 171 | public void onClick(ViewHolder viewHolder) { 172 | super.onClick(viewHolder); 173 | //必须是TreeItemGroup才能展开折叠,并且type不能为 TreeRecyclerType.SHOW_ALL 174 | setExpand(!isExpand()); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/item/TreeSelectItemGroup.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.item; 2 | 3 | 4 | import android.support.annotation.NonNull; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | 10 | /** 11 | * Created by baozi on 2016/12/22. 12 | * 可以选中子item的TreeItemGroup,点击的item会保存起来.可以通过 getSelectItems()获得选中item 13 | */ 14 | public abstract class TreeSelectItemGroup 15 | extends TreeItemGroup { 16 | /** 17 | * 选中的子item.只保存当前的子级 18 | */ 19 | private List selectItems; 20 | 21 | public List getSelectItems() { 22 | if (selectItems == null) { 23 | selectItems = new ArrayList<>(); 24 | } 25 | return selectItems; 26 | } 27 | 28 | /** 29 | * 是否全选选中 30 | */ 31 | public boolean isSelectAll() { 32 | return getSelectItems().containsAll(getChild()); 33 | } 34 | 35 | 36 | /** 37 | * 选择全部,取消全部 38 | * 向下递归 39 | * 40 | * @param b 是否全部选中 41 | * @param isMultistage 是否多级关联 42 | */ 43 | public void selectAll(boolean b, boolean isMultistage) { 44 | List child = getChild(); 45 | if (child == null) { 46 | return; 47 | } 48 | getSelectItems().clear(); 49 | for (int i = 0; i < child.size(); i++) { 50 | TreeItem item = child.get(i); 51 | if (item instanceof TreeSelectItemGroup) { 52 | ((TreeSelectItemGroup) item).selectAll(b); 53 | } 54 | if (b && !isSelect(item)) { 55 | getSelectItems().add(item); 56 | } 57 | } 58 | if (isMultistage) { 59 | updateParentSelect(); 60 | } 61 | } 62 | 63 | /** 64 | * 选择全部,取消全部 65 | * 向下递归 66 | * 67 | * @param b 是否全部选中 68 | */ 69 | public void selectAll(boolean b) { 70 | this.selectAll(b, false); 71 | } 72 | 73 | /** 74 | * 包含的子级是否有选中 75 | */ 76 | public boolean isSelect() { 77 | return !getSelectItems().isEmpty(); 78 | } 79 | 80 | /** 81 | * 是否选中 82 | */ 83 | public boolean isSelect(TreeItem item) { 84 | return getSelectItems().contains(item); 85 | } 86 | 87 | @Override 88 | public boolean onInterceptClick(TreeItem child) { 89 | if (getParentItem() != null) { 90 | return getParentItem().onInterceptClick(this); 91 | } 92 | return super.onInterceptClick(child); 93 | } 94 | 95 | /** 96 | * 添加选中的Item;不建议直接调用该方法, 97 | * 当不需要用onInterceptClick()的时候,可以主动调用添加Item. 98 | * 如果onInterceptClick()生效,还主动调用该方法添加item,将无法添加. 99 | * 向上递归 100 | * 101 | * @param child 要添加选中的item 102 | * @param isMultistage 是否多级关联 103 | */ 104 | protected void selectItem(@NonNull TreeItem child, boolean isMultistage) { 105 | if (selectFlag() == SelectFlag.SINGLE_CHOICE) { 106 | if (getSelectItems().size() != 0) { 107 | getSelectItems().set(0, child); 108 | } else { 109 | getSelectItems().add(child); 110 | } 111 | } else { 112 | int index = getSelectItems().indexOf(child); 113 | if (index == -1) {//不存在则添加 114 | getSelectItems().add(child); 115 | } else {//存在则删除 116 | if (child instanceof TreeSelectItemGroup) { 117 | if (((TreeSelectItemGroup) child).isSelect()) { 118 | return; 119 | } 120 | } 121 | getSelectItems().remove(index); 122 | } 123 | if (isMultistage) { 124 | updateParentSelect(); 125 | } 126 | } 127 | } 128 | 129 | protected void selectItem(@NonNull TreeItem child) { 130 | this.selectItem(child, false); 131 | } 132 | 133 | public void updateParentSelect() { 134 | TreeItemGroup parentItem = getParentItem(); 135 | if (parentItem instanceof TreeSelectItemGroup) { 136 | // 如果当前选中了,但是父类没有选中,则更新 137 | if (isSelect() != ((TreeSelectItemGroup) parentItem).isSelect(this)) { 138 | ((TreeSelectItemGroup) parentItem).selectItem(this, true); 139 | ((TreeSelectItemGroup) parentItem).updateParentSelect(); 140 | } 141 | } 142 | } 143 | 144 | /** 145 | * 默认多选 146 | * 147 | * @return 148 | */ 149 | public SelectFlag selectFlag() { 150 | return SelectFlag.MULTIPLE_CHOICE; 151 | } 152 | 153 | /** 154 | * 决定TreeSelectItemGroup的选中样式 155 | */ 156 | public enum SelectFlag { 157 | /** 158 | * 单选 159 | */ 160 | SINGLE_CHOICE, 161 | /** 162 | * 多选 163 | */ 164 | MULTIPLE_CHOICE 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/item/TreeSortItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.item; 2 | 3 | /** 4 | * Created by Administrator on 2017/8/8 0008. 5 | */ 6 | 7 | public abstract class TreeSortItem extends TreeItemGroup { 8 | protected Object sortKey; 9 | 10 | public void setSortKey(Object sortKey) { 11 | this.sortKey = sortKey; 12 | } 13 | 14 | public Object getSortKey() { 15 | return sortKey; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/manager/ItemManageImpl.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.manager; 2 | 3 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 默认使用 notifyDataChanged();刷新. 9 | * 如果使用带动画效果的,条目过多可能会出现卡顿. 10 | */ 11 | public class ItemManageImpl extends ItemManager { 12 | 13 | 14 | public ItemManageImpl(BaseRecyclerAdapter adapter) { 15 | super(adapter); 16 | } 17 | 18 | @Override 19 | public void addItem(T item) { 20 | getData().add(item); 21 | if (!isOpenAnim()) { 22 | notifyDataChanged(); 23 | return; 24 | } 25 | int itemPosition = getItemPosition(item); 26 | getAdapter().notifyItemInserted(itemPosition); 27 | } 28 | 29 | @Override 30 | public void addItem(int position, T item) { 31 | getData().add(position, item); 32 | if (!isOpenAnim()) { 33 | notifyDataChanged(); 34 | return; 35 | } 36 | position = dataToItemPosition(position); 37 | getAdapter().notifyItemInserted(position); 38 | } 39 | 40 | @Override 41 | public void addItems(List items) { 42 | getData().addAll(items); 43 | if (!isOpenAnim()) { 44 | notifyDataChanged(); 45 | return; 46 | } 47 | getAdapter().notifyItemRangeInserted(getData().size(), items.size()); 48 | } 49 | 50 | @Override 51 | public void addItems(int position, List items) { 52 | getData().addAll(position, items); 53 | if (!isOpenAnim()) { 54 | notifyDataChanged(); 55 | return; 56 | } 57 | int itemPosition = dataToItemPosition(position); 58 | getAdapter().notifyItemRangeInserted(itemPosition, items.size()); 59 | } 60 | 61 | @Override 62 | public void removeItem(T item) { 63 | int position = getItemPosition(item); 64 | getData().remove(item); 65 | if (!isOpenAnim()) { 66 | notifyDataChanged(); 67 | return; 68 | } 69 | int itemPosition = dataToItemPosition(position); 70 | getAdapter().notifyItemRemoved(itemPosition); 71 | } 72 | 73 | @Override 74 | public void removeItem(int position) { 75 | getData().remove(position); 76 | if (!isOpenAnim()) { 77 | notifyDataChanged(); 78 | return; 79 | } 80 | int itemPosition = dataToItemPosition(position); 81 | getAdapter().notifyItemRemoved(itemPosition); 82 | } 83 | 84 | @Override 85 | public void removeItems(List items) { 86 | getData().removeAll(items); 87 | notifyDataChanged(); 88 | } 89 | 90 | @Override 91 | public void replaceItem(int position, T item) { 92 | getData().set(position, item); 93 | if (!isOpenAnim()) { 94 | notifyDataChanged(); 95 | return; 96 | } 97 | int itemPosition = dataToItemPosition(position); 98 | getAdapter().notifyItemChanged(itemPosition); 99 | } 100 | 101 | @Override 102 | public void replaceAllItem(List items) { 103 | setData(items); 104 | if (!isOpenAnim()) { 105 | notifyDataChanged(); 106 | return; 107 | } 108 | getAdapter().notifyItemRangeChanged(0, getData().size()); 109 | } 110 | 111 | protected void setData(List items) { 112 | getAdapter().setData(items); 113 | } 114 | 115 | protected List getData() { 116 | return getAdapter().getData(); 117 | } 118 | 119 | @Override 120 | public T getItem(int position) { 121 | return getData().get(position); 122 | } 123 | 124 | @Override 125 | public int getItemPosition(T item) { 126 | return getData().indexOf(item); 127 | } 128 | 129 | @Override 130 | public void clean() { 131 | getAdapter().clear(); 132 | notifyDataChanged(); 133 | } 134 | } -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/manager/ItemManager.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.manager; 2 | 3 | 4 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * 条目增删管理类 11 | * 12 | * @param 13 | */ 14 | public abstract class ItemManager { 15 | 16 | private BaseRecyclerAdapter mAdapter; 17 | private Object tag; 18 | 19 | public ItemManager(BaseRecyclerAdapter adapter) { 20 | mAdapter = adapter; 21 | } 22 | 23 | public BaseRecyclerAdapter getAdapter() { 24 | return mAdapter; 25 | } 26 | 27 | public void setAdapter(BaseRecyclerAdapter adapter) { 28 | mAdapter = adapter; 29 | } 30 | 31 | private boolean isOpenAnim; 32 | 33 | public boolean isOpenAnim() { 34 | return isOpenAnim; 35 | } 36 | 37 | public void setOpenAnim(boolean openAnim) { 38 | isOpenAnim = openAnim; 39 | } 40 | 41 | //增 42 | public abstract void addItem(T item); 43 | 44 | public abstract void addItem(int position, T item); 45 | 46 | public abstract void addItems(List items); 47 | 48 | public abstract void addItems(int position, List items); 49 | 50 | //删 51 | public abstract void removeItem(T item); 52 | 53 | public abstract void removeItem(int position); 54 | 55 | public abstract void removeItems(List items); 56 | 57 | 58 | //改 59 | public abstract void replaceItem(int position, T item); 60 | 61 | public abstract void replaceAllItem(List items); 62 | 63 | //查 64 | public abstract T getItem(int position); 65 | 66 | public abstract int getItemPosition(T item); 67 | 68 | public abstract void clean(); 69 | 70 | //刷新 71 | public void notifyDataChanged() { 72 | mAdapter.notifyDataSetChanged(); 73 | } 74 | 75 | public void setTag(Object tag) { 76 | this.tag = tag; 77 | } 78 | 79 | public Object getTag() { 80 | return this.tag; 81 | } 82 | 83 | /** 84 | * 检查item属性 85 | */ 86 | public interface CheckItemInterface { 87 | int itemToDataPosition(int position); 88 | 89 | int dataToItemPosition(int index); 90 | } 91 | 92 | public void removeCheckItemInterfaces(CheckItemInterface itemInterface) { 93 | if (checkItemInterfaces == null) return; 94 | checkItemInterfaces.remove(itemInterface); 95 | } 96 | 97 | public void addCheckItemInterfaces(CheckItemInterface itemInterface) { 98 | if (checkItemInterfaces == null) { 99 | checkItemInterfaces = new ArrayList<>(); 100 | } 101 | checkItemInterfaces.add(itemInterface); 102 | } 103 | 104 | private ArrayList checkItemInterfaces; 105 | 106 | /** 107 | * 解决holder角标与data的角标不一致问题。 108 | * 109 | * @param position 110 | * @return 111 | */ 112 | public int itemToDataPosition(int position) { 113 | if (checkItemInterfaces != null) { 114 | for (CheckItemInterface itemInterface : checkItemInterfaces) { 115 | position = itemInterface.itemToDataPosition(position); 116 | } 117 | } 118 | return position; 119 | } 120 | 121 | /** 122 | * 解决data的角标与holder角标不一致问题。 123 | * 124 | * @param index 125 | * @return 126 | */ 127 | public int dataToItemPosition(int index) { 128 | if (checkItemInterfaces != null) { 129 | for (CheckItemInterface itemInterface : checkItemInterfaces) { 130 | index = itemInterface.dataToItemPosition(index); 131 | } 132 | } 133 | return index; 134 | } 135 | } -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/widget/DragSelectRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.widget; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | 7 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 8 | import com.baozi.treerecyclerview.base.ViewHolder; 9 | 10 | import java.util.ArrayList; 11 | 12 | 13 | public abstract class DragSelectRecyclerAdapter extends BaseRecyclerAdapter { 14 | 15 | public interface SelectionListener { 16 | void onDragSelectionChanged(int count); 17 | } 18 | 19 | private ArrayList mSelectedIndices; 20 | private SelectionListener mSelectionListener; 21 | private int mLastCount = -1; 22 | private int mMaxSelectionCount = -1; 23 | 24 | private void fireSelectionListener() { 25 | if (mLastCount == mSelectedIndices.size()) 26 | return; 27 | mLastCount = mSelectedIndices.size(); 28 | if (mSelectionListener != null) 29 | mSelectionListener.onDragSelectionChanged(mLastCount); 30 | } 31 | 32 | protected DragSelectRecyclerAdapter() { 33 | mSelectedIndices = new ArrayList<>(); 34 | } 35 | 36 | @Override 37 | public void onBindViewHolderClick(@NonNull ViewHolder holder, View view) { 38 | super.onBindViewHolderClick(holder, view); 39 | holder.itemView.setTag(holder); 40 | } 41 | 42 | public void setMaxSelectionCount(int maxSelectionCount) { 43 | this.mMaxSelectionCount = maxSelectionCount; 44 | } 45 | 46 | public void setSelectionListener(SelectionListener selectionListener) { 47 | this.mSelectionListener = selectionListener; 48 | } 49 | 50 | public void saveInstanceState(Bundle out) { 51 | saveInstanceState("selected_indices", out); 52 | } 53 | 54 | public void saveInstanceState(String key, Bundle out) { 55 | out.putSerializable(key, mSelectedIndices); 56 | } 57 | 58 | public void restoreInstanceState(Bundle in) { 59 | restoreInstanceState("selected_indices", in); 60 | } 61 | 62 | public void restoreInstanceState(String key, Bundle in) { 63 | if (in != null && in.containsKey(key)) { 64 | //noinspection unchecked 65 | mSelectedIndices = (ArrayList) in.getSerializable(key); 66 | if (mSelectedIndices == null) mSelectedIndices = new ArrayList<>(); 67 | else fireSelectionListener(); 68 | } 69 | } 70 | 71 | public final void setSelected(int index, boolean selected) { 72 | if (!isIndexSelectable(index)) 73 | selected = false; 74 | if (selected) { 75 | if (!mSelectedIndices.contains(index) && 76 | (mMaxSelectionCount == -1 || 77 | mSelectedIndices.size() < mMaxSelectionCount)) { 78 | mSelectedIndices.add(index); 79 | notifyDataSetChanged(); 80 | } 81 | } else if (mSelectedIndices.contains(index)) { 82 | mSelectedIndices.remove((Integer) index); 83 | notifyDataSetChanged(); 84 | } 85 | fireSelectionListener(); 86 | } 87 | 88 | public final boolean toggleSelected(int index) { 89 | boolean selectedNow = false; 90 | if (isIndexSelectable(index)) { 91 | if (mSelectedIndices.contains(index)) { 92 | mSelectedIndices.remove((Integer) index); 93 | } else if (mMaxSelectionCount == -1 || 94 | mSelectedIndices.size() < mMaxSelectionCount) { 95 | mSelectedIndices.add(index); 96 | selectedNow = true; 97 | } 98 | notifyDataSetChanged(); 99 | } 100 | fireSelectionListener(); 101 | return selectedNow; 102 | } 103 | 104 | protected boolean isIndexSelectable(int index) { 105 | return true; 106 | } 107 | 108 | public final void selectRange(int from, int to, int min, int max) { 109 | if (from == to) { 110 | // Finger is back on the initial item, unselect everything else 111 | for (int i = min; i <= max; i++) { 112 | if (i == from) continue; 113 | setSelected(i, false); 114 | } 115 | fireSelectionListener(); 116 | return; 117 | } 118 | 119 | if (to < from) { 120 | // When selecting from one to previous items 121 | for (int i = to; i <= from; i++) 122 | setSelected(i, true); 123 | if (min > -1 && min < to) { 124 | // Unselect items that were selected during this drag but no longer are 125 | for (int i = min; i < to; i++) { 126 | if (i == from) continue; 127 | setSelected(i, false); 128 | } 129 | } 130 | if (max > -1) { 131 | for (int i = from + 1; i <= max; i++) 132 | setSelected(i, false); 133 | } 134 | } else { 135 | // When selecting from one to next items 136 | for (int i = from; i <= to; i++) 137 | setSelected(i, true); 138 | if (max > -1 && max > to) { 139 | // Unselect items that were selected during this drag but no longer are 140 | for (int i = to + 1; i <= max; i++) { 141 | if (i == from) continue; 142 | setSelected(i, false); 143 | } 144 | } 145 | if (min > -1) { 146 | for (int i = min; i < from; i++) 147 | setSelected(i, false); 148 | } 149 | } 150 | fireSelectionListener(); 151 | } 152 | 153 | public final void clearSelected() { 154 | mSelectedIndices.clear(); 155 | notifyDataSetChanged(); 156 | fireSelectionListener(); 157 | } 158 | 159 | public final int getSelectedCount() { 160 | return mSelectedIndices.size(); 161 | } 162 | 163 | public final ArrayList getSelectedIndices() { 164 | if (mSelectedIndices == null) { 165 | mSelectedIndices = new ArrayList<>(); 166 | } 167 | return mSelectedIndices; 168 | } 169 | 170 | public final boolean isIndexSelected(int index) { 171 | return mSelectedIndices.contains(index); 172 | } 173 | } -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/widget/swipe/SwipeItemMangerInterface.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.widget.swipe; 2 | 3 | import java.util.List; 4 | 5 | public interface SwipeItemMangerInterface { 6 | void bind(SwipeLayout swipeLayout, int res, int position); 7 | 8 | void openItem(int position); 9 | 10 | void closeItem(int position); 11 | 12 | void closeAllExcept(SwipeLayout layout); 13 | 14 | void closeAllItems(); 15 | 16 | List getOpenItems(); 17 | 18 | List getOpenLayouts(); 19 | 20 | void removeShownLayouts(SwipeLayout layout); 21 | 22 | boolean isOpen(int position); 23 | 24 | SwipeMode getMode(); 25 | 26 | void setMode(SwipeMode mode); 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/baozi/treerecyclerview/widget/swipe/SwipeMode.java: -------------------------------------------------------------------------------- 1 | package com.baozi.treerecyclerview.widget.swipe; 2 | 3 | public enum SwipeMode { 4 | Single, Multiple 5 | } -------------------------------------------------------------------------------- /app/src/main/res/values/attr.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/values/values.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 56dp 10 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.50' 5 | repositories { 6 | google() 7 | maven { 8 | url 'https://maven.fabric.io/public' 9 | } 10 | maven { 11 | url 'http://maven.aliyun.com/repository/jcenter' 12 | } 13 | maven { 14 | url 'http://maven.aliyun.com/repository/google' 15 | } 16 | maven { 17 | url 'http://maven.aliyun.com/repository/gradle-plugin' 18 | } 19 | maven { 20 | url 'http://maven.aliyun.com/nexus/content/repositories/releases/' 21 | } 22 | jcenter() 23 | } 24 | dependencies { 25 | classpath 'com.android.tools.build:gradle:3.5.3' 26 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 27 | // NOTE: Do not place your application dependencies here; they belong 28 | // in the individual module build.gradle files 29 | } 30 | } 31 | 32 | allprojects { 33 | repositories { 34 | google() 35 | maven { url "https://jitpack.io" } 36 | maven { 37 | url 'https://maven.fabric.io/public' 38 | } 39 | maven { 40 | url 'http://maven.aliyun.com/repository/jcenter' 41 | } 42 | maven { 43 | url 'http://maven.aliyun.com/repository/google' 44 | } 45 | maven { 46 | url 'http://maven.aliyun.com/repository/gradle-plugin' 47 | } 48 | maven { 49 | url 'http://maven.aliyun.com/nexus/content/repositories/releases/' 50 | } 51 | jcenter() 52 | mavenCentral() 53 | } 54 | } 55 | 56 | task clean(type: Delete) { 57 | delete rootProject.buildDir 58 | } 59 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android-extensions' 3 | apply plugin: 'kotlin-android' 4 | apply plugin: 'kotlin-kapt' 5 | android { 6 | compileSdkVersion 28 7 | buildToolsVersion "28.0.3" 8 | 9 | defaultConfig { 10 | applicationId "com.baozi.treerecyclerview" 11 | minSdkVersion 15 12 | targetSdkVersion 28 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | compileOptions { 23 | targetCompatibility 1.8 24 | sourceCompatibility 1.8 25 | } 26 | } 27 | dependencies { 28 | implementation files('libs/fastjson-1.2.9.jar') 29 | implementation 'com.android.support:appcompat-v7:28.0.0' 30 | implementation 'com.android.support:recyclerview-v7:28.0.0' 31 | implementation 'com.android.support:design:28.0.0' 32 | implementation project(':app') 33 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 34 | } 35 | -------------------------------------------------------------------------------- /demo/libs/fastjson-1.2.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jlanglang/TreeRecyclerView/6f454078ecd9f05619bb1d44b282d6d758f7ffeb/demo/libs/fastjson-1.2.9.jar -------------------------------------------------------------------------------- /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 J:\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 | -------------------------------------------------------------------------------- /demo/src/androidTest/java/com/baozi/demo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/src/main/assets/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 菜翼213 6 | 7 | 8 |
9 | 10 |
11 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/activity/CartAt.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.widget.CheckBox; 9 | import android.widget.TextView; 10 | 11 | import com.baozi.demo.R; 12 | import com.baozi.demo.item.cart.CartBean; 13 | import com.baozi.demo.item.cart.CartItem; 14 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 15 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 16 | import com.baozi.treerecyclerview.item.TreeItem; 17 | import com.baozi.treerecyclerview.item.TreeSelectItemGroup; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by a123 on 2018/6/5. 24 | * 购物车列表 25 | */ 26 | public class CartAt extends AppCompatActivity { 27 | private TreeRecyclerAdapter adapter = new TreeRecyclerAdapter(); 28 | 29 | @Override 30 | protected void onCreate(@Nullable Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_shopping_cart); 33 | RecyclerView rv_content = findViewById(R.id.rv_content); 34 | rv_content.setLayoutManager(new LinearLayoutManager(this)); 35 | rv_content.setAdapter(adapter); 36 | List beans = new ArrayList<>(); 37 | beans.add(new CartBean(3)); 38 | 39 | List groupItem = ItemHelperFactory.createItems(beans); 40 | 41 | adapter.getItemManager().replaceAllItem(groupItem); 42 | adapter.setOnItemClickListener((viewHolder, position) -> { 43 | //因为外部和内部会冲突 44 | TreeItem item = adapter.getData(position); 45 | if (item != null) { 46 | item.onClick(viewHolder); 47 | } 48 | notifyPrice(); 49 | }); 50 | initView(); 51 | notifyPrice(); 52 | } 53 | 54 | /** 55 | * 更新价格 56 | */ 57 | public void notifyPrice() { 58 | boolean isSelectAll = true;//默认全选 59 | int price = 0; 60 | for (TreeItem item : adapter.getData()) { 61 | if (item instanceof TreeSelectItemGroup) { 62 | TreeSelectItemGroup group = (TreeSelectItemGroup) item; 63 | if (!group.isSelect()) {//是否有选择的子类 64 | //有一个没选则不是全选 65 | isSelectAll = false; 66 | continue; 67 | } 68 | if (!group.isSelectAll()) {//是否全选了子类 69 | //有一个没选则不是全选 70 | isSelectAll = false; 71 | } 72 | List selectItems = group.getSelectItems(); 73 | for (TreeItem child : selectItems) { 74 | if (child instanceof CartItem) { 75 | Integer data = (Integer) child.getData(); 76 | price += data; 77 | } 78 | } 79 | } 80 | } 81 | adapter.notifyDataSetChanged(); 82 | 83 | ((TextView) findViewById(R.id.tv_all_price)).setText("¥" + price); 84 | CheckBox checkBox = findViewById(R.id.cb_all_check); 85 | checkBox.setChecked(isSelectAll); 86 | } 87 | 88 | public void initView() { 89 | CheckBox checkBox = findViewById(R.id.cb_all_check); 90 | checkBox.setOnClickListener(v -> { 91 | for (TreeItem item : adapter.getData()) { 92 | if (item instanceof TreeSelectItemGroup) { 93 | TreeSelectItemGroup group = (TreeSelectItemGroup) item; 94 | group.selectAll(((CheckBox) v).isChecked()); 95 | } 96 | } 97 | notifyPrice(); 98 | }); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/activity/CityAt.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.DefaultItemAnimator; 8 | import android.support.v7.widget.GridLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.util.Log; 11 | 12 | import com.alibaba.fastjson.JSON; 13 | import com.baozi.demo.R; 14 | import com.baozi.demo.item.city.ProvinceBean; 15 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 16 | import com.baozi.treerecyclerview.adpater.TreeRecyclerType; 17 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 18 | import com.baozi.treerecyclerview.item.TreeItem; 19 | import com.baozi.treerecyclerview.item.TreeItemGroup; 20 | 21 | import java.io.BufferedReader; 22 | import java.io.InputStreamReader; 23 | import java.lang.ref.WeakReference; 24 | import java.util.List; 25 | 26 | /** 27 | * 城市列表 28 | */ 29 | public class CityAt extends AppCompatActivity { 30 | //根据item的状态展示,可折叠 31 | TreeRecyclerAdapter treeRecyclerAdapter = new TreeRecyclerAdapter(TreeRecyclerType.SHOW_EXPAND); 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.layout_rv_content); 37 | RecyclerView recyclerView = findViewById(R.id.rv_content); 38 | recyclerView.setLayoutManager(new GridLayoutManager(this, 6)); 39 | recyclerView.setItemAnimator(new DefaultItemAnimator()); 40 | recyclerView.setAdapter(treeRecyclerAdapter); 41 | new Thread() { 42 | @Override 43 | public void run() { 44 | super.run(); 45 | String string = getFromAssets("city.txt"); 46 | List cityBeen = JSON.parseArray(string, ProvinceBean.class); 47 | refresh(cityBeen); 48 | } 49 | }.start(); 50 | 51 | } 52 | 53 | public String getFromAssets(String fileName) { 54 | StringBuilder result = new StringBuilder(); 55 | try { 56 | InputStreamReader inputReader = new InputStreamReader(getResources().getAssets().open(fileName)); 57 | BufferedReader bufReader = new BufferedReader(inputReader); 58 | String line; 59 | while ((line = bufReader.readLine()) != null) 60 | result.append(line); 61 | return result.toString(); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | } 65 | return result.toString(); 66 | } 67 | 68 | private void refresh(final List cityBeen) { 69 | runOnUiThread(() -> { 70 | //创建item 71 | //新的 72 | List items = ItemHelperFactory.createItems(cityBeen); 73 | //添加到adapter 74 | treeRecyclerAdapter.getItemManager().replaceAllItem(items); 75 | }); 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.activity; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Rect; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.app.FragmentTransaction; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.util.Log; 13 | import android.util.Pair; 14 | import android.view.View; 15 | 16 | import com.baozi.demo.R; 17 | import com.baozi.demo.fragment.ClickLoadFg; 18 | import com.baozi.demo.fragment.GalleryFg; 19 | import com.baozi.demo.fragment.MineFg; 20 | import com.baozi.demo.fragment.NewsFg; 21 | import com.baozi.demo.item.cart.CartGroupItem; 22 | import com.baozi.demo.item.city.AreaItem; 23 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 24 | import com.baozi.treerecyclerview.factory.ItemConfig; 25 | import com.baozi.treerecyclerview.item.SimpleTreeItem; 26 | import com.baozi.treerecyclerview.item.TreeItem; 27 | 28 | import java.util.ArrayList; 29 | import java.util.Arrays; 30 | import java.util.List; 31 | 32 | /** 33 | * @author jlanglang 2016/12/22 9:58 34 | * @版本 2.0 35 | * @Change 36 | */ 37 | public class MainActivity extends AppCompatActivity { 38 | //数据集合 39 | private Pair[] itemPairs = { 40 | new Pair("三级城市", CityAt.class), 41 | new Pair("购物车", CartAt.class), 42 | new Pair("新闻", NewsFg.class), 43 | new Pair("索引", SortAt.class), 44 | new Pair("索引加侧滑删除", SwipeSortAt.class), 45 | new Pair("个人中心", MineFg.class), 46 | new Pair("淘宝首页", TBActivity.class), 47 | new Pair("点击懒加载", ClickLoadFg.class), 48 | new Pair("画廊", TestActivity.class) 49 | }; 50 | private TreeRecyclerAdapter adapter = new TreeRecyclerAdapter(); 51 | 52 | @Override 53 | protected void onCreate(@Nullable Bundle savedInstanceState) { 54 | super.onCreate(savedInstanceState); 55 | setContentView(R.layout.layout_rv_content); 56 | initRecyclerVIew(); 57 | initData(); 58 | ItemConfig.register(CartGroupItem.class); 59 | 60 | } 61 | 62 | /** 63 | * 简单创建Item 64 | */ 65 | private void initData() { 66 | ArrayList items = new ArrayList<>(); 67 | for (Pair itemPair : itemPairs) { 68 | SimpleTreeItem simpleTreeItem = new SimpleTreeItem(R.layout.item_mine) 69 | .onItemBind(viewHolder -> { 70 | Pair itemPair1 = itemPairs[viewHolder.getLayoutPosition()]; 71 | viewHolder.setText(R.id.tv_name, (String) itemPair1.first); 72 | }) 73 | .onItemClick(viewHolder -> { 74 | Pair itemPair12 = itemPairs[viewHolder.getLayoutPosition()]; 75 | Class aClass = (Class) itemPair12.second; 76 | boolean isFragment = Fragment.class.isAssignableFrom(aClass);//判断是不是fragment的子类 77 | if (isFragment) { 78 | startFragment((Class) itemPair12.second); 79 | } else { 80 | startAt((Class) itemPair12.second); 81 | } 82 | }); 83 | simpleTreeItem.setData(itemPair); 84 | items.add(simpleTreeItem); 85 | } 86 | adapter.getItemManager().replaceAllItem(items); 87 | } 88 | 89 | /** 90 | * 初始化列表 91 | */ 92 | private void initRecyclerVIew() { 93 | RecyclerView rv_content = findViewById(R.id.rv_content); 94 | rv_content.setLayoutManager(new LinearLayoutManager(this)); 95 | rv_content.setAdapter(adapter); 96 | rv_content.addItemDecoration(new RecyclerView.ItemDecoration() { 97 | @Override 98 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 99 | super.getItemOffsets(outRect, view, parent, state); 100 | outRect.top = 10; 101 | } 102 | }); 103 | } 104 | 105 | public void startAt(Class zClass) { 106 | Intent intent = new Intent(this, zClass); 107 | startActivity(intent); 108 | } 109 | 110 | public void startFragment(Class zClass) { 111 | try { 112 | Fragment fragment = zClass.newInstance(); 113 | FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 114 | fragmentTransaction.add(android.R.id.content, fragment, null); 115 | fragmentTransaction.addToBackStack(null); 116 | fragmentTransaction.commitAllowingStateLoss(); 117 | } catch (InstantiationException e) { 118 | e.printStackTrace(); 119 | } catch (IllegalAccessException e) { 120 | e.printStackTrace(); 121 | } 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/activity/SortAt.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.widget.TextView; 8 | 9 | import com.baozi.demo.R; 10 | import com.baozi.demo.item.sort.IndexBar; 11 | import com.baozi.demo.item.sort.SortGroupItem; 12 | import com.baozi.treerecyclerview.item.TreeItem; 13 | import com.baozi.treerecyclerview.widget.TreeSortAdapter; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * Created by baozi on 2017/8/19. 20 | * 侧滑+索引 21 | */ 22 | 23 | public class SortAt extends AppCompatActivity { 24 | private static final String[] LETTERS = new String[]{"A", "B", "C", "D", 25 | "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", 26 | "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; 27 | private TreeSortAdapter mTreeSortAdapter = new TreeSortAdapter(); 28 | private LinearLayoutManager mLinearLayoutManager; 29 | 30 | @Override 31 | public void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_sort); 34 | final RecyclerView rv_content = findViewById(R.id.rv_content); 35 | TextView tv_index = findViewById(R.id.tv_index); 36 | IndexBar qb_sort = findViewById(R.id.qb_sort); 37 | qb_sort.setOnIndexChangedListener(letter -> { 38 | int sortIndex = mTreeSortAdapter.getSortIndex(letter); 39 | mLinearLayoutManager.scrollToPositionWithOffset(sortIndex, 0); 40 | }); 41 | qb_sort.setIndexs(LETTERS); 42 | qb_sort.setSelectedIndexTextView(tv_index); 43 | 44 | mLinearLayoutManager = new LinearLayoutManager(this); 45 | rv_content.setLayoutManager(mLinearLayoutManager); 46 | rv_content.setAdapter(mTreeSortAdapter); 47 | initData(); 48 | } 49 | 50 | 51 | private void initData() { 52 | List groupItems = new ArrayList<>(); 53 | for (String str : LETTERS) { 54 | SortGroupItem sortGroupItem = new SortGroupItem(); 55 | sortGroupItem.setSortKey(str); 56 | sortGroupItem.setData(null); 57 | groupItems.add(sortGroupItem); 58 | } 59 | mTreeSortAdapter.getItemManager().replaceAllItem(groupItems); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/activity/SwipeSortAt.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.LinearLayoutCompat; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.Gravity; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import com.baozi.demo.R; 14 | import com.baozi.demo.item.sort.IndexBar; 15 | import com.baozi.demo.item.sort.SortGroupItem; 16 | import com.baozi.treerecyclerview.adpater.wrapper.HeaderWrapper; 17 | import com.baozi.treerecyclerview.adpater.wrapper.SwipeWrapper; 18 | import com.baozi.treerecyclerview.adpater.wrapper.TreeLoadWrapper; 19 | import com.baozi.treerecyclerview.item.SimpleTreeItem; 20 | import com.baozi.treerecyclerview.item.TreeItem; 21 | import com.baozi.treerecyclerview.widget.TreeSortAdapter; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * Created by baozi on 2017/8/19. 28 | * 在SortActivity的代码逻辑上,加少部分代码实现 29 | */ 30 | 31 | public class SwipeSortAt extends AppCompatActivity { 32 | private static final String[] LETTERS = new String[]{"A", "B", "C", "D", 33 | "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", 34 | "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; 35 | private TreeSortAdapter mTreeSortAdapter; 36 | private LinearLayoutManager mLinearLayoutManager; 37 | private TreeLoadWrapper mWrapper; 38 | 39 | @Override 40 | public void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_sort); 43 | RecyclerView rv_content = (RecyclerView) findViewById(R.id.rv_content); 44 | TextView tv_index = (TextView) findViewById(R.id.tv_index); 45 | IndexBar qb_sort = (IndexBar) findViewById(R.id.qb_sort); 46 | qb_sort.setOnIndexChangedListener(new IndexBar.OnIndexChangedListener() { 47 | @Override 48 | public void onIndexChanged(String letter) { 49 | int sortIndex = mTreeSortAdapter.getSortIndex(letter); 50 | mLinearLayoutManager.scrollToPositionWithOffset(sortIndex, 0); 51 | } 52 | }); 53 | qb_sort.setIndexs(LETTERS); 54 | qb_sort.setSelectedIndexTextView(tv_index); 55 | 56 | mLinearLayoutManager = new GridLayoutManager(this, 2); 57 | rv_content.setLayoutManager(mLinearLayoutManager); 58 | //创建索引adapter 59 | mTreeSortAdapter = new TreeSortAdapter(); 60 | mTreeSortAdapter.getItemManager().setOpenAnim(true); 61 | HeaderWrapper headerWrapper = new HeaderWrapper<>(mTreeSortAdapter); 62 | addHeadView(headerWrapper); 63 | //包装成侧滑删除列表 64 | SwipeWrapper adapter = new SwipeWrapper(headerWrapper); 65 | mWrapper = new TreeLoadWrapper(adapter); 66 | mWrapper.setEmptyView(new SimpleTreeItem(R.layout.layout_empty)); 67 | mWrapper.setLoadingView(R.layout.layout_loading); 68 | 69 | rv_content.setAdapter(mWrapper); 70 | 71 | initData(); 72 | } 73 | 74 | private void addHeadView(HeaderWrapper headerWrapper) { 75 | for (int i = 0; i < 5; i++) { 76 | //添加头部View1 77 | TextView headView = new TextView(this); 78 | headView.setText("headView" + i); 79 | headView.setGravity(Gravity.CENTER); 80 | headView.setLayoutParams(new LinearLayoutCompat.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 320)); 81 | headerWrapper.addHeaderView(headView); 82 | } 83 | } 84 | 85 | private void initData() { 86 | final List groupItems = new ArrayList<>(); 87 | for (int i = 0; i < LETTERS.length; i++) { 88 | SortGroupItem sortGroupItem = new SortGroupItem(); 89 | sortGroupItem.setSortKey(LETTERS[i]); 90 | sortGroupItem.setData(i); 91 | groupItems.add(sortGroupItem); 92 | } 93 | new Thread(new Runnable() { 94 | @Override 95 | public void run() { 96 | try { 97 | Thread.sleep(1000); 98 | } catch (InterruptedException e) { 99 | e.printStackTrace(); 100 | } 101 | runOnUiThread(new Runnable() { 102 | @Override 103 | public void run() { 104 | mWrapper.setType(TreeLoadWrapper.Type.REFRESH_OVER); 105 | mWrapper.getItemManager().notifyDataChanged(); 106 | } 107 | }); 108 | try { 109 | Thread.sleep(1000); 110 | } catch (InterruptedException e) { 111 | e.printStackTrace(); 112 | } 113 | runOnUiThread(new Runnable() { 114 | @Override 115 | public void run() { 116 | mWrapper.setType(TreeLoadWrapper.Type.LOADING); 117 | } 118 | }); 119 | try { 120 | Thread.sleep(2000); 121 | } catch (InterruptedException e) { 122 | e.printStackTrace(); 123 | } 124 | runOnUiThread(new Runnable() { 125 | @Override 126 | public void run() { 127 | mWrapper.setType(TreeLoadWrapper.Type.REFRESH_OVER); 128 | mWrapper.getItemManager().replaceAllItem(groupItems); 129 | } 130 | }); 131 | } 132 | }).start(); 133 | 134 | 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/activity/TBActivity.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.design.widget.TabLayout; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.app.FragmentPagerAdapter; 9 | import android.support.v4.view.ViewPager; 10 | import android.support.v7.app.AppCompatActivity; 11 | import com.baozi.demo.R; 12 | import com.baozi.demo.fragment.MineFg; 13 | 14 | public class TBActivity extends AppCompatActivity { 15 | 16 | @Override 17 | protected void onCreate(@Nullable Bundle savedInstanceState){ 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_tb_home); 20 | ViewPager content = findViewById(R.id.content); 21 | content.setAdapter(new FragmentPagerAdapter(this.getSupportFragmentManager()) { 22 | @Override 23 | public Fragment getItem(int i) { 24 | return new MineFg(); 25 | } 26 | 27 | @Override 28 | public int getCount() { 29 | return 5; 30 | } 31 | 32 | @NonNull 33 | @Override 34 | public CharSequence getPageTitle(int position) { 35 | return position + ""; 36 | } 37 | }); 38 | TabLayout tb_title = findViewById(R.id.tb_title); 39 | tb_title.setupWithViewPager(content); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/fragment/ClickLoadFg.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.fragment; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v7.widget.GridLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import com.baozi.demo.R; 15 | import com.baozi.demo.item.clickload.ClickLoadGroupItem; 16 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 17 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 18 | import com.baozi.treerecyclerview.item.TreeItem; 19 | 20 | import java.util.Arrays; 21 | 22 | /** 23 | * 点击懒加载的demo 24 | */ 25 | public class ClickLoadFg extends Fragment { 26 | RecyclerView view; 27 | private TreeRecyclerAdapter adapter = new TreeRecyclerAdapter(); 28 | 29 | @Nullable 30 | @Override 31 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 32 | if (view == null) { 33 | view = (RecyclerView) inflater.inflate(R.layout.layout_rv_content, container, false); 34 | view.setBackgroundColor(Color.GRAY); 35 | } 36 | return view; 37 | } 38 | 39 | @Override 40 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 41 | super.onActivityCreated(savedInstanceState); 42 | //初始化recyclerView 43 | view.setLayoutManager(new GridLayoutManager(view.getContext(), 4)); 44 | view.setAdapter(adapter); 45 | TreeItem treeItem = ItemHelperFactory.createItem(new String[]{}, ClickLoadGroupItem.class, null); 46 | adapter.getItemManager().replaceAllItem(Arrays.asList(treeItem)); 47 | adapter.setOnItemClickListener((viewHolder, position) -> { 48 | TreeItem item = adapter.getData(position); 49 | if (item == null || item.getData() == null) { 50 | return; 51 | } 52 | if (item instanceof ClickLoadGroupItem) { 53 | ClickLoadGroupItem clickLoadGroupItem = (ClickLoadGroupItem) item; 54 | if (clickLoadGroupItem.getChild() == null || clickLoadGroupItem.getChild().isEmpty()) { 55 | clickLoadGroupItem.setData(new String[]{"1", "2", "3"}); 56 | clickLoadGroupItem.setExpand(true); 57 | } 58 | } 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/fragment/GalleryFg.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.fragment; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.animation.ValueAnimator; 5 | import android.graphics.Rect; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.LinearSnapHelper; 11 | import android.support.v7.widget.PagerSnapHelper; 12 | import android.support.v7.widget.RecyclerView; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | 18 | import com.baozi.demo.R; 19 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 20 | import com.baozi.treerecyclerview.item.SimpleTreeItem; 21 | import com.baozi.treerecyclerview.item.TreeItem; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class GalleryFg extends SimpleRecyclerViewFg { 27 | private LinearSnapHelper snapHelper = new LinearSnapHelper(); 28 | LinearLayoutManager linearLayoutManager; 29 | 30 | @Override 31 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 32 | super.onActivityCreated(savedInstanceState); 33 | 34 | linearLayoutManager = new LinearLayoutManager(context, 0, false); 35 | recyclerView.setLayoutManager(linearLayoutManager); 36 | snapHelper.attachToRecyclerView(recyclerView); 37 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 38 | @Override 39 | public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { 40 | super.onScrolled(recyclerView, dx, dy); 41 | scaleItem(); 42 | } 43 | }); 44 | adapter.getItemManager().replaceAllItem(getItems()); 45 | } 46 | 47 | public void scaleItem() { 48 | int first = linearLayoutManager.findFirstVisibleItemPosition(); 49 | int last = linearLayoutManager.findLastVisibleItemPosition(); 50 | int center = first + (last - first) / 2; 51 | int range = last - first; 52 | Log.i("position", first + ":" + last + ":" + center + ":" + range); 53 | for (int i = 0; i < range; i++) { 54 | RecyclerView.ViewHolder item = recyclerView.findViewHolderForLayoutPosition(first + i); 55 | if (item == null) { 56 | return; 57 | } 58 | if ((first + i) == center) { 59 | item.itemView.setScaleY(1.2f); 60 | continue; 61 | } 62 | item.itemView.setScaleY(1f); 63 | } 64 | } 65 | 66 | public List getItems() { 67 | ArrayList list = new ArrayList<>(); 68 | for (int i = 0; i < 20; i++) { 69 | list.add( 70 | new SimpleTreeItem(R.layout.item_grallery) 71 | .setTreeOffset(new Rect(20, 20, 20, 20)) 72 | .onItemBind(viewHolder -> { 73 | TextView itemView = (TextView) viewHolder.itemView; 74 | itemView.setText(viewHolder.getLayoutPosition() + ""); 75 | viewHolder.itemView.setScaleY(1); 76 | }) 77 | ); 78 | } 79 | return list; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/fragment/MineFg.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.fragment; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.Rect; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.app.Fragment; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | 15 | import com.baozi.demo.R; 16 | import com.baozi.demo.item.mine.MineCategoryBean; 17 | import com.baozi.demo.item.mine.MineItem; 18 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 19 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 20 | import com.baozi.treerecyclerview.item.SimpleTreeItem; 21 | import com.baozi.treerecyclerview.item.TreeItem; 22 | 23 | import java.util.Arrays; 24 | import java.util.List; 25 | 26 | //RecyclerView实现首页我的页面 27 | public class MineFg extends Fragment { 28 | 29 | private RecyclerView view; 30 | private TreeRecyclerAdapter adapter = new TreeRecyclerAdapter(); 31 | private List heads = Arrays.asList( 32 | new MineCategoryBean("公开文章", null, "39", true), 33 | new MineCategoryBean("关注", null, "57", true), 34 | new MineCategoryBean("粉丝", null, "501", true), 35 | new MineCategoryBean("每日签到", "1", null, true) 36 | ); 37 | private List category = Arrays.asList( 38 | new MineCategoryBean("私密文章", "1", null), 39 | new MineCategoryBean("我的收藏", "1", null), 40 | new MineCategoryBean("我的喜欢", "1", null), 41 | new MineCategoryBean("已购内容", "1", null), 42 | new MineCategoryBean("我的专题", "1", null, true), 43 | new MineCategoryBean("我的文集", "1", null, true), 44 | new MineCategoryBean("关注内容", "1", null, true), 45 | new MineCategoryBean("我的钱包", "1", null, true) 46 | ); 47 | private List item = Arrays.asList("条目1", "条目2", "条目3", "条目4", "条目5", "条目6"); 48 | 49 | @Nullable 50 | @Override 51 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 52 | if (view == null) { 53 | view = (RecyclerView) inflater.inflate(R.layout.layout_rv_content, container, false); 54 | view.setBackgroundColor(Color.GRAY); 55 | } 56 | return view; 57 | } 58 | 59 | @Override 60 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 61 | super.onActivityCreated(savedInstanceState); 62 | //初始化recyclerView 63 | view.setLayoutManager(new GridLayoutManager(view.getContext(), 4)); 64 | view.setAdapter(adapter); 65 | adapter.getItemManager().clean(); 66 | //添加头部 67 | adapter.getItemManager().addItem( 68 | new SimpleTreeItem(R.layout.item_mine_head) 69 | .setTreeOffset(new Rect(0, 0, 0, 2)) 70 | ); 71 | //添加头部分类item 72 | adapter.getItemManager().addItems(ItemHelperFactory.createItems(heads)); 73 | //添加分类item 74 | adapter.getItemManager().addItems(ItemHelperFactory.createItems(category)); 75 | //添加横条item 76 | adapter.getItemManager().addItems(ItemHelperFactory.createItems(item, MineItem.class)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/fragment/NewsFg.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | 10 | import com.baozi.demo.R; 11 | import com.baozi.demo.fragment.SimpleRecyclerViewFg; 12 | import com.baozi.demo.item.news.NewsItemBean; 13 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 14 | import com.baozi.treerecyclerview.adpater.TreeRecyclerType; 15 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 16 | import com.baozi.treerecyclerview.item.TreeItem; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Random; 21 | 22 | /** 23 | * @author jlanglang 2017/7/5 10:22 24 | * @版本 2017-8-19;有点勉强,不建议这样使用- - 25 | */ 26 | 27 | public class NewsFg extends SimpleRecyclerViewFg { 28 | protected TreeRecyclerAdapter adapter = new TreeRecyclerAdapter(TreeRecyclerType.SHOW_ALL); 29 | 30 | @Override 31 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 32 | super.onActivityCreated(savedInstanceState); 33 | recyclerView.setLayoutManager(new GridLayoutManager(context, 6)); 34 | recyclerView.setAdapter(adapter); 35 | ArrayList list = new ArrayList<>(); 36 | for (int i = 0; i < 5; i++) { 37 | NewsItemBean newsItemBean = new NewsItemBean(); 38 | newsItemBean.title = "123"; 39 | newsItemBean.images = new Random().nextInt(9) + 1; 40 | list.add(newsItemBean); 41 | } 42 | List itemList = ItemHelperFactory.createItems(list); 43 | adapter.getItemManager().replaceAllItem(itemList); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/fragment/SimpleRecyclerViewFg.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.fragment; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.app.Fragment; 9 | import android.support.v7.widget.DefaultItemAnimator; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | 16 | import com.baozi.demo.R; 17 | import com.baozi.treerecyclerview.adpater.TreeRecyclerAdapter; 18 | import com.baozi.treerecyclerview.base.BaseRecyclerAdapter; 19 | 20 | 21 | public abstract class SimpleRecyclerViewFg extends Fragment { 22 | protected RecyclerView recyclerView; 23 | protected Context context; 24 | protected TreeRecyclerAdapter adapter = new TreeRecyclerAdapter(); 25 | 26 | @Override 27 | public void onAttach(Context context) { 28 | super.onAttach(context); 29 | this.context = context; 30 | } 31 | 32 | @Nullable 33 | @Override 34 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 35 | if (recyclerView == null) { 36 | recyclerView = (RecyclerView) inflater.inflate(R.layout.layout_rv_content, container, false); 37 | recyclerView.setBackgroundColor(Color.GRAY); 38 | } 39 | return recyclerView; 40 | } 41 | 42 | @Override 43 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 44 | super.onActivityCreated(savedInstanceState); 45 | recyclerView.setItemAnimator(new DefaultItemAnimator()); 46 | recyclerView.setLayoutManager(new LinearLayoutManager(context)); 47 | recyclerView.setAdapter(adapter); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/cart/CartBean.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.cart; 2 | 3 | import com.baozi.treerecyclerview.annotation.TreeDataType; 4 | 5 | 6 | @TreeDataType(bindField = "type") 7 | public class CartBean { 8 | int childSum; //子条目数量 9 | public int type = 1; 10 | 11 | public CartBean(int childSum) { 12 | this.childSum = childSum; 13 | } 14 | 15 | @TreeDataType(iClass = CartGroupItem2.class) 16 | public static class CartBean2 { 17 | int childSum; //子条目数量 18 | 19 | public CartBean2(int childSum) { 20 | this.childSum = childSum; 21 | } 22 | 23 | @TreeDataType(iClass = CartGroupItem3.class) 24 | public static class CartBean3 { 25 | int childSum; //子条目数量 26 | 27 | public CartBean3(int childSum) { 28 | this.childSum = childSum; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/cart/CartGroupItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.cart; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.view.View; 6 | import android.widget.CheckBox; 7 | 8 | import com.baozi.demo.R; 9 | import com.baozi.demo.activity.CartAt; 10 | import com.baozi.treerecyclerview.annotation.TreeItemType; 11 | import com.baozi.treerecyclerview.base.ViewHolder; 12 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 13 | import com.baozi.treerecyclerview.item.TreeItem; 14 | import com.baozi.treerecyclerview.item.TreeSelectItemGroup; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by a123 on 2018/6/5. 21 | */ 22 | @TreeItemType(type = {"1"}) 23 | public class CartGroupItem extends TreeSelectItemGroup { 24 | 25 | @Nullable 26 | @Override 27 | protected List initChild(CartBean data) { 28 | ArrayList list = new ArrayList<>(); 29 | for (int i = 0; i < data.childSum; i++) { 30 | list.add(new CartBean.CartBean2(2)); 31 | } 32 | return ItemHelperFactory.createItems(list, this); 33 | } 34 | 35 | @Override 36 | public int getLayoutId() { 37 | return R.layout.item_cart_group; 38 | } 39 | 40 | @Override 41 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 42 | viewHolder.setText(R.id.cb_ischeck, "电脑(一级)"); 43 | viewHolder.setChecked(R.id.cb_ischeck, isSelect()); 44 | viewHolder.getView(R.id.cb_ischeck).setOnClickListener((v) -> { 45 | selectAll(!isSelectAll(), true); 46 | ((CartAt) viewHolder.itemView.getContext()).notifyPrice(); 47 | }); 48 | viewHolder.itemView.setPadding(0, 0, 0, 0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/cart/CartGroupItem2.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.cart; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.widget.CheckBox; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.demo.activity.CartAt; 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 11 | import com.baozi.treerecyclerview.item.TreeItem; 12 | import com.baozi.treerecyclerview.item.TreeSelectItemGroup; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by a123 on 2018/6/5. 19 | */ 20 | public class CartGroupItem2 extends TreeSelectItemGroup { 21 | 22 | @Nullable 23 | @Override 24 | protected List initChild(CartBean.CartBean2 data) { 25 | ArrayList list = new ArrayList<>(); 26 | for (int i = 0; i < data.childSum; i++) { 27 | list.add(new CartBean.CartBean2.CartBean3(3)); 28 | } 29 | return ItemHelperFactory.createItems(list, this); 30 | } 31 | 32 | @Override 33 | public int getLayoutId() { 34 | return R.layout.item_cart_group; 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 39 | viewHolder.setText(R.id.cb_ischeck, "笔记本(二级)"); 40 | viewHolder.setChecked(R.id.cb_ischeck, isSelect()); 41 | viewHolder.getView(R.id.cb_ischeck).setOnClickListener((v) -> { 42 | selectAll(!isSelectAll(), true); 43 | ((CartAt) viewHolder.itemView.getContext()).notifyPrice(); 44 | }); 45 | viewHolder.itemView.setPadding(20, 0, 0, 0); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/cart/CartGroupItem3.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.cart; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | import android.widget.CheckBox; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.demo.activity.CartAt; 9 | import com.baozi.treerecyclerview.annotation.TreeItemType; 10 | import com.baozi.treerecyclerview.base.ViewHolder; 11 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 12 | import com.baozi.treerecyclerview.item.TreeItem; 13 | import com.baozi.treerecyclerview.item.TreeSelectItemGroup; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Random; 18 | 19 | /** 20 | * Created by a123 on 2018/6/5. 21 | */ 22 | @TreeItemType(type = "1") 23 | public class CartGroupItem3 extends TreeSelectItemGroup { 24 | 25 | @Nullable 26 | @Override 27 | protected List initChild(CartBean.CartBean2.CartBean3 data) { 28 | ArrayList list = new ArrayList<>(); 29 | for (int i = 0; i < data.childSum; i++) { 30 | list.add(new Random().nextInt(300)); 31 | } 32 | return ItemHelperFactory.createItems(list, CartItem.class, this); 33 | } 34 | 35 | @Override 36 | public int getLayoutId() { 37 | return R.layout.item_cart_group; 38 | } 39 | 40 | @Override 41 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 42 | viewHolder.setText(R.id.cb_ischeck, "联想(三级)"); 43 | viewHolder.setChecked(R.id.cb_ischeck, isSelect()); 44 | viewHolder.getView(R.id.cb_ischeck).setOnClickListener((v) -> { 45 | selectAll(!isSelectAll(), true); 46 | ((CartAt) viewHolder.itemView.getContext()).notifyPrice(); 47 | }); 48 | viewHolder.itemView.setPadding(40, 0, 0, 0); 49 | } 50 | 51 | @Override 52 | public boolean onInterceptClick(TreeItem child) { 53 | selectItem(child, true); 54 | return super.onInterceptClick(child); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/cart/CartItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.cart; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.base.ViewHolder; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | import com.baozi.treerecyclerview.item.TreeItemGroup; 11 | 12 | /** 13 | * Created by a123 on 2018/6/5. 14 | */ 15 | 16 | public class CartItem extends TreeItem { 17 | 18 | 19 | @Override 20 | public int getLayoutId() { 21 | return R.layout.item_cart_child; 22 | } 23 | 24 | @Override 25 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 26 | TreeItemGroup parentItem = getParentItem(); 27 | if (parentItem instanceof CartGroupItem3) { 28 | viewHolder.setChecked(R.id.cb_ischeck, ((CartGroupItem3) parentItem).isSelect(this)); 29 | } 30 | viewHolder.setText(R.id.tv_price, data + ""); 31 | viewHolder.itemView.setPadding(50, 0, 0, 0); 32 | 33 | } 34 | 35 | 36 | @Override 37 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 38 | super.getItemOffsets(outRect, layoutParams, position); 39 | outRect.bottom = 1; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/city/AreaItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.city; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.annotation.TreeItemType; 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.item.TreeItem; 11 | 12 | /** 13 | * 14 | */ 15 | public class AreaItem extends TreeItem { 16 | 17 | @Override 18 | public int getLayoutId() { 19 | return R.layout.item_three; 20 | } 21 | 22 | @Override 23 | public void onBindViewHolder(@NonNull ViewHolder holder) { 24 | holder.setText(R.id.tv_content, data.areaName); 25 | } 26 | 27 | @Override 28 | public int getSpanSize(int maxSpan) { 29 | return maxSpan / 3; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/city/CountyItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.city; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.item.TreeItem; 11 | import com.baozi.treerecyclerview.item.TreeItemGroup; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * 17 | */ 18 | public class CountyItem extends TreeItemGroup { 19 | 20 | @Override 21 | public List initChild(ProvinceBean.CityBean data) { 22 | return ItemHelperFactory.createItems(data.areas, this); 23 | } 24 | 25 | @Override 26 | public int getLayoutId() { 27 | return R.layout.item_two; 28 | } 29 | 30 | @Override 31 | public void onBindViewHolder(@NonNull ViewHolder holder) { 32 | holder.setText(R.id.tv_content, data.cityName); 33 | } 34 | 35 | @Override 36 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 37 | super.getItemOffsets(outRect, layoutParams, position); 38 | outRect.top = 1; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/city/ProvinceItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.city; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | import com.baozi.treerecyclerview.base.ViewHolder; 11 | import com.baozi.treerecyclerview.item.TreeItemGroup; 12 | import com.baozi.treerecyclerview.manager.ItemManager; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by baozi on 2016/12/8. 18 | */ 19 | public class ProvinceItem extends TreeItemGroup { 20 | @Override 21 | protected void init() { 22 | super.init(); 23 | setExpand(false); 24 | } 25 | 26 | @Override 27 | public List initChild(ProvinceBean data) { 28 | List items = ItemHelperFactory.createItems(data.citys, this); 29 | for (int i = 0; i < items.size(); i++) { 30 | TreeItemGroup treeItem = (TreeItemGroup) items.get(i); 31 | treeItem.setExpand(false); 32 | } 33 | return items; 34 | } 35 | 36 | @Override 37 | public int getLayoutId() { 38 | return R.layout.itme_one; 39 | } 40 | 41 | @Override 42 | public boolean isCanExpand() { 43 | return true; 44 | } 45 | 46 | @Override 47 | public void onBindViewHolder(@NonNull ViewHolder holder) { 48 | holder.setText(R.id.tv_content, data.provinceName); 49 | } 50 | 51 | @Override 52 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 53 | super.getItemOffsets(outRect, layoutParams, position); 54 | outRect.bottom = 1; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/clickload/ClickLoadChildItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.clickload; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.baozi.demo.R; 7 | import com.baozi.treerecyclerview.base.ViewHolder; 8 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | import com.baozi.treerecyclerview.item.TreeItemGroup; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class ClickLoadChildItem extends TreeItem { 16 | @Override 17 | public int getLayoutId() { 18 | return R.layout.item_sort_child; 19 | } 20 | 21 | @Override 22 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/clickload/ClickLoadGroupItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.clickload; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.baozi.demo.R; 7 | import com.baozi.treerecyclerview.base.ViewHolder; 8 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | import com.baozi.treerecyclerview.item.TreeItemGroup; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class ClickLoadGroupItem extends TreeItemGroup { 16 | @Override 17 | public int getLayoutId() { 18 | return R.layout.item_sort_group; 19 | } 20 | 21 | @Nullable 22 | @Override 23 | protected List initChild(String[] data) { 24 | return ItemHelperFactory.createItems(Arrays.asList(data), ClickLoadChildItem.class, this); 25 | } 26 | 27 | @Override 28 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/mine/MineCategoryBean.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.mine; 2 | 3 | import com.baozi.treerecyclerview.annotation.TreeDataType; 4 | 5 | @TreeDataType(iClass = MineCategoryItem.class) 6 | public class MineCategoryBean { 7 | public String title; 8 | public String url;// 9 | public String content; 10 | public boolean isEnd; 11 | 12 | /** 13 | * @param content 内容 14 | * @param url 图片,如果为null则隐藏 15 | * @param title 如果为null则隐藏 16 | */ 17 | public MineCategoryBean(String content, String url, String title) { 18 | this(content, url, title, false); 19 | } 20 | 21 | /** 22 | * @param content 内容 23 | * @param url 图片,如果为null则隐藏 24 | * @param title 如果为null则隐藏 25 | * @param isEnd 是否是该组最后一排 26 | */ 27 | public MineCategoryBean(String content, String url, String title, boolean isEnd) { 28 | this.title = title; 29 | this.url = url; 30 | this.content = content; 31 | this.isEnd = isEnd; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/mine/MineCategoryItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.mine; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.text.TextUtils; 7 | 8 | import com.baozi.demo.R; 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.item.TreeItem; 11 | 12 | /** 13 | * 分类 14 | */ 15 | public class MineCategoryItem extends TreeItem { 16 | @Override 17 | public int getLayoutId() { 18 | return R.layout.item_mine_category; 19 | } 20 | 21 | @Override 22 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 23 | viewHolder.setText(R.id.tv_content, data.content); 24 | 25 | viewHolder.setVisible(R.id.tv_title, !TextUtils.isEmpty(data.title)); 26 | viewHolder.setText(R.id.tv_title, data.title); 27 | 28 | viewHolder.setVisible(R.id.iv_content, !TextUtils.isEmpty(data.url)); 29 | 30 | } 31 | 32 | @Override 33 | public int getSpanSize(int maxSpan) { 34 | return maxSpan / 4; 35 | } 36 | 37 | @Override 38 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 39 | super.getItemOffsets(outRect, layoutParams, position); 40 | if (data.isEnd){ 41 | outRect.bottom = 20; 42 | }else { 43 | outRect.bottom = 0; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/mine/MineHeadItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.mine; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.base.ViewHolder; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | 11 | public class MineHeadItem extends TreeItem { 12 | @Override 13 | public int getLayoutId() { 14 | return R.layout.item_mine_head; 15 | } 16 | 17 | @Override 18 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 19 | } 20 | 21 | @Override 22 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 23 | super.getItemOffsets(outRect, layoutParams, position); 24 | outRect.bottom = 1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/mine/MineItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.mine; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.base.ViewHolder; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | 11 | public class MineItem extends TreeItem { 12 | @Override 13 | public int getLayoutId() { 14 | return R.layout.item_mine; 15 | } 16 | 17 | @Override 18 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 19 | viewHolder.setText(R.id.tv_name, data); 20 | } 21 | 22 | @Override 23 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 24 | super.getItemOffsets(outRect, layoutParams, position); 25 | outRect.top = 2; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/news/NewsImageItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.news; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.base.ViewHolder; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | 11 | /** 12 | * @author jlanglang 2017/7/5 17:15 13 | * @版本 2.0 14 | * @Change 15 | */ 16 | 17 | public class NewsImageItem extends TreeItem { 18 | @Override 19 | public int getLayoutId() { 20 | return R.layout.item_news_image; 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan / 3; 26 | } 27 | 28 | @Override 29 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 30 | 31 | } 32 | 33 | @Override 34 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 35 | super.getItemOffsets(outRect, layoutParams, position); 36 | outRect.set(1, 1, 1, 1); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/news/NewsItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.news; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | 6 | import com.baozi.demo.R; 7 | import com.baozi.treerecyclerview.base.ViewHolder; 8 | import com.baozi.treerecyclerview.factory.ItemHelperFactory; 9 | import com.baozi.treerecyclerview.item.SimpleTreeItem; 10 | import com.baozi.treerecyclerview.item.TreeItem; 11 | import com.baozi.treerecyclerview.item.TreeItemGroup; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author jlanglang 2017/7/5 17:15 18 | * @版本 2.0 19 | * @Change 20 | */ 21 | //新闻列表,一级父 22 | public class NewsItem extends TreeItemGroup { 23 | @Override 24 | protected List initChild(NewsItemBean data) { 25 | //添加图片 26 | int images = data.images; 27 | ArrayList child = new ArrayList<>(); 28 | for (int i = 0; i < images; i++) { 29 | child.add(""); 30 | } 31 | List treeItemList = ItemHelperFactory.createItems(child, NewsImageItem.class, this); 32 | 33 | //添加尾部 34 | treeItemList.add(new SimpleTreeItem(R.layout.item_news_foot) 35 | .onItemClick(viewHolder -> { 36 | //点击跳转 37 | }).setTreeOffset(new Rect(0, 0, 0, 20))); 38 | return treeItemList; 39 | } 40 | 41 | @Override 42 | public int getLayoutId() { 43 | return R.layout.item_news_title; 44 | } 45 | 46 | @Override 47 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 48 | viewHolder.setText(R.id.tv_title, data.title); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/news/NewsItemBean.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.news; 2 | 3 | import com.baozi.treerecyclerview.annotation.TreeDataType; 4 | 5 | /** 6 | * @author jlanglang 2017/7/5 17:34 7 | * @版本 2.0 8 | * @Change 9 | */ 10 | @TreeDataType(iClass = NewsItem.class) 11 | public class NewsItemBean { 12 | public String title; 13 | public int images; 14 | } 15 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/sort/IndexBar.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.sort; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.util.AttributeSet; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | 13 | /** 14 | * Created by SouthernBox on 2016/10/25 0025. 15 | * 侧边索引栏控件 16 | */ 17 | 18 | public class IndexBar extends View { 19 | 20 | /** 21 | * 索引字母颜色 22 | */ 23 | private static final int LETTER_COLOR = 0xFF2e2e2e; 24 | /** 25 | * 按下颜色 26 | */ 27 | private static final int DOWN_COLOR = 0x11000000; 28 | /** 29 | * 抬起颜色 30 | */ 31 | private static final int UP_COLOR = 0x00000000; 32 | /** 33 | * 索引字母数组 34 | */ 35 | public String[] indexs = {}; 36 | 37 | /** 38 | * 控件的宽高 39 | */ 40 | private int mWidth; 41 | private int mHeight; 42 | 43 | /** 44 | * 单元格的高度 45 | */ 46 | private float mCellHeight; 47 | 48 | /** 49 | * 顶部间距 50 | */ 51 | private float mMarginTop; 52 | 53 | private Paint mPaint; 54 | 55 | public IndexBar(Context context) { 56 | super(context); 57 | init(); 58 | } 59 | 60 | public IndexBar(Context context, AttributeSet attrs) { 61 | super(context, attrs); 62 | init(); 63 | } 64 | 65 | private void init() { 66 | mPaint = new Paint(); 67 | mPaint.setColor(LETTER_COLOR); 68 | mPaint.setTextSize(36); 69 | mPaint.setAntiAlias(true); // 去掉锯齿,让字体边缘变得平滑 70 | } 71 | 72 | public void setIndexs(String[] indexs) { 73 | this.indexs = indexs; 74 | mMarginTop = (mHeight - mCellHeight * indexs.length) / 2; 75 | invalidate(); 76 | } 77 | 78 | @Override 79 | protected void onDraw(Canvas canvas) { 80 | //字母的坐标点:(x,y) 81 | if (indexs.length <= 0) { 82 | return; 83 | } 84 | for (int i = 0; i < indexs.length; i++) { 85 | String letter = indexs[i]; 86 | float x = mWidth / 2 - getTextWidth(letter) / 2; 87 | float y = mCellHeight / 2 + getTextHeight(letter) / 2 + mCellHeight * i + mMarginTop; 88 | canvas.drawText(letter, x, y, mPaint); 89 | } 90 | } 91 | 92 | /** 93 | * 获取字符的宽度 94 | * 95 | * @param text 需要测量的字母 96 | * @return 对应字母的高度 97 | */ 98 | public float getTextWidth(String text) { 99 | Rect bounds = new Rect(); 100 | mPaint.getTextBounds(text, 0, text.length(), bounds); 101 | return bounds.width(); 102 | } 103 | 104 | /** 105 | * 获取字符的高度 106 | * 107 | * @param text 需要测量的字母 108 | * @return 对应字母的高度 109 | */ 110 | public float getTextHeight(String text) { 111 | Rect bounds = new Rect(); 112 | mPaint.getTextBounds(text, 0, text.length(), bounds); 113 | return bounds.height(); 114 | } 115 | 116 | 117 | @Override 118 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 119 | super.onSizeChanged(w, h, oldw, oldh); 120 | mWidth = getMeasuredWidth(); 121 | mHeight = getMeasuredHeight(); 122 | mCellHeight = (mHeight * 0.8f / 27); //26个字母加上“#” 123 | mMarginTop = (mHeight - mCellHeight * indexs.length) / 2; 124 | } 125 | 126 | // 处理Touch事件 127 | @Override 128 | public boolean onTouchEvent(MotionEvent event) { 129 | switch (event.getAction()) { 130 | case MotionEvent.ACTION_DOWN: 131 | case MotionEvent.ACTION_MOVE: 132 | setBackgroundColor(DOWN_COLOR); 133 | // 按下字母的下标 134 | int letterIndex = (int) ((event.getY() - mMarginTop) / mCellHeight); 135 | // 判断是否越界 136 | if (letterIndex >= 0 && letterIndex < indexs.length) { 137 | // 显示按下的字母 138 | if (textView != null) { 139 | textView.setVisibility(View.VISIBLE); 140 | textView.setText(indexs[letterIndex]); 141 | } 142 | //通过回调方法通知列表定位 143 | if (mOnIndexChangedListener != null) { 144 | mOnIndexChangedListener.onIndexChanged(indexs[letterIndex]); 145 | } 146 | } 147 | break; 148 | case MotionEvent.ACTION_UP: 149 | case MotionEvent.ACTION_CANCEL: 150 | setBackgroundColor(UP_COLOR); 151 | if (textView != null) { 152 | textView.setVisibility(View.GONE); 153 | } 154 | break; 155 | } 156 | 157 | return true; 158 | } 159 | 160 | public interface OnIndexChangedListener { 161 | /** 162 | * 按下字母改变了 163 | * 164 | * @param letter 按下的字母 165 | */ 166 | void onIndexChanged(String letter); 167 | } 168 | 169 | private OnIndexChangedListener mOnIndexChangedListener; 170 | 171 | private TextView textView; 172 | 173 | public void setOnIndexChangedListener(OnIndexChangedListener onIndexChangedListener) { 174 | this.mOnIndexChangedListener = onIndexChangedListener; 175 | } 176 | 177 | /** 178 | * 设置显示按下首字母的TextView 179 | */ 180 | public void setSelectedIndexTextView(TextView textView) { 181 | this.textView = textView; 182 | } 183 | } -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/sort/SortChildItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.sort; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.treerecyclerview.base.ViewHolder; 9 | import com.baozi.treerecyclerview.item.TreeItem; 10 | 11 | /** 12 | * Created by baozi on 2017/8/19. 13 | */ 14 | 15 | public class SortChildItem extends TreeItem { 16 | @Override 17 | public int getLayoutId() { 18 | return R.layout.item_sort_child; 19 | } 20 | 21 | @Override 22 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 23 | viewHolder.setText(R.id.tv_content, data); 24 | } 25 | 26 | @Override 27 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 28 | super.getItemOffsets(outRect, layoutParams, position); 29 | outRect.top = 1; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/sort/SortGroupItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.sort; 2 | 3 | import android.graphics.Rect; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.demo.item.swipe.SwipeSortItem; 9 | import com.baozi.treerecyclerview.base.ViewHolder; 10 | import com.baozi.treerecyclerview.item.TreeItem; 11 | import com.baozi.treerecyclerview.item.TreeSortItem; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by baozi on 2017/8/19. 18 | */ 19 | 20 | public class SortGroupItem extends TreeSortItem { 21 | @Override 22 | protected List initChild(Object childs) { 23 | ArrayList treeItems = new ArrayList<>(); 24 | for (int i = 0; i < 5; i++) { 25 | SwipeSortItem sortChildItem = new SwipeSortItem(); 26 | sortChildItem.setData(i + ""); 27 | treeItems.add(sortChildItem); 28 | } 29 | return treeItems; 30 | } 31 | 32 | 33 | @Override 34 | public int getLayoutId() { 35 | return R.layout.item_sort_group; 36 | } 37 | 38 | @Override 39 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 40 | if (isExpand()) { 41 | viewHolder.setImageResource(R.id.iv_right, R.drawable.ic_keyboard_arrow_down_black_24dp); 42 | } else { 43 | viewHolder.setImageResource(R.id.iv_right, R.drawable.ic_keyboard_arrow_right_black_24dp); 44 | } 45 | viewHolder.setText(R.id.tv_content, (String) getSortKey()); 46 | } 47 | 48 | @Override 49 | public void onClick(ViewHolder viewHolder) { 50 | super.onClick(viewHolder); 51 | if (isExpand()) { 52 | viewHolder.setImageResource(R.id.iv_right, R.drawable.ic_keyboard_arrow_down_black_24dp); 53 | } else { 54 | viewHolder.setImageResource(R.id.iv_right, R.drawable.ic_keyboard_arrow_right_black_24dp); 55 | } 56 | } 57 | 58 | @Override 59 | public void getItemOffsets(@NonNull Rect outRect, RecyclerView.LayoutParams layoutParams, int position) { 60 | super.getItemOffsets(outRect, layoutParams, position); 61 | outRect.top = 10; 62 | if (position == 0) { 63 | outRect.top = 0; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/swipe/SwipeSortItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.swipe; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.baozi.demo.R; 8 | import com.baozi.demo.item.sort.SortChildItem; 9 | import com.baozi.treerecyclerview.item.SwipeItem; 10 | import com.baozi.treerecyclerview.widget.swipe.SwipeItemMangerInterface; 11 | import com.baozi.treerecyclerview.widget.swipe.SwipeLayout; 12 | import com.baozi.treerecyclerview.base.ViewHolder; 13 | 14 | /** 15 | * Created by baozi on 2017/8/20. 16 | */ 17 | 18 | public class SwipeSortItem extends SortChildItem implements SwipeItem { 19 | @Override 20 | public int getSwipeLayoutId() { 21 | return R.layout.layout_delete; 22 | } 23 | 24 | @Override 25 | public SwipeLayout.DragEdge getDragEdge() { 26 | return SwipeLayout.DragEdge.Right; 27 | } 28 | 29 | @Override 30 | public void onBindSwipeView(@NonNull ViewHolder viewHolder, int position, final SwipeItemMangerInterface swipeManger) { 31 | viewHolder.setOnClickListener(R.id.tv_delete, new View.OnClickListener() { 32 | @Override 33 | public void onClick(View v) { 34 | Toast.makeText(v.getContext(), "删除", Toast.LENGTH_SHORT).show(); 35 | swipeManger.closeAllItems(); 36 | } 37 | }); 38 | } 39 | 40 | @Override 41 | public void openCallback() { 42 | 43 | } 44 | 45 | @Override 46 | public void onClick(ViewHolder viewHolder) { 47 | super.onClick(viewHolder); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/GoodsItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板A 11 | */ 12 | public class GoodsItem extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_goods; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return super.getSpanSize(maxSpan)/3; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeCategoryItem.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | public class HomeCategoryItem extends TreeItem { 10 | @Override 11 | public int getLayoutId() { 12 | return R.layout.item_mine_category; 13 | } 14 | 15 | @Override 16 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeItemA.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板B 11 | */ 12 | public class HomeItemA extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_home_a; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan / 2; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeItemB.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板A 11 | */ 12 | public class HomeItemB extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_home_b; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan/ 3 * 2; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeItemC.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板C 11 | */ 12 | public class HomeItemC extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_home_c; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan/3; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeItemD.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板D 11 | */ 12 | public class HomeItemD extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_home_d; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan/3; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeItemE.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板E 11 | */ 12 | public class HomeItemE extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_home_e; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan/3; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/java/com/baozi/demo/item/tbhome/HomeItemF.java: -------------------------------------------------------------------------------- 1 | package com.baozi.demo.item.tbhome; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.baozi.demo.R; 6 | import com.baozi.treerecyclerview.base.ViewHolder; 7 | import com.baozi.treerecyclerview.item.TreeItem; 8 | 9 | /** 10 | * 模板F 11 | */ 12 | public class HomeItemF extends TreeItem { 13 | @Override 14 | public int getLayoutId() { 15 | return R.layout.item_tb_home_f; 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull ViewHolder viewHolder) { 20 | 21 | } 22 | 23 | @Override 24 | public int getSpanSize(int maxSpan) { 25 | return maxSpan/3; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/bg_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_keyboard_arrow_right_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_person_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_photo_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/shape_radius30_stroke1_gray_333.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |