├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetDropDown.xml ├── gradle.xml ├── jarRepositories.xml ├── markdown-navigator-enh.xml ├── markdown-navigator.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── lib-http-release.aar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── tencent │ │ └── multiadapter │ │ └── example │ │ ├── DataUtils.kt │ │ ├── bean │ │ ├── BeanA.java │ │ ├── BeanB.java │ │ ├── BeanC.java │ │ └── ItemBean.java │ │ ├── item │ │ ├── AItemType.java │ │ ├── BItemType.java │ │ ├── CItemType.java │ │ ├── ItemType00.kt │ │ ├── ItemType01.kt │ │ └── ItemType02.kt │ │ └── ui │ │ ├── MainActivity.kt │ │ ├── MultiItemDemo01Activity.kt │ │ └── MultiItemDemo02Activity.kt │ └── res │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_multi_item.xml │ ├── item_00.xml │ ├── item_01.xml │ ├── item_02.xml │ ├── item_a.xml │ ├── item_b.xml │ └── item_c.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── core ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── tencent │ │ └── lib │ │ └── multi │ │ ├── MultiAdapter.kt │ │ └── core │ │ ├── ItemManager.kt │ │ ├── ItemType.kt │ │ ├── ItemViewInflaterFactory.kt │ │ ├── MultiViewHolder.kt │ │ ├── ReceiverWrapper.kt │ │ ├── SimpleItemType.kt │ │ └── ViewClickRegistry.kt │ └── res │ └── values │ └── attrs.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── MultiAdapter问题反馈群群聊二维码.png ├── 单bean类型对应多样item类型.jpg └── 多bean类型对应多样item类型.jpg ├── paging ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── csd │ └── multi │ └── paging │ └── MultiPagingDataAdapter.kt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | xmlns:android 23 | 24 | ^$ 25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | xmlns:.* 34 | 35 | ^$ 36 | 37 | 38 | BY_NAME 39 | 40 |
41 |
42 | 43 | 44 | 45 | .*:id 46 | 47 | http://schemas.android.com/apk/res/android 48 | 49 | 50 | 51 |
52 |
53 | 54 | 55 | 56 | .*:name 57 | 58 | http://schemas.android.com/apk/res/android 59 | 60 | 61 | 62 |
63 |
64 | 65 | 66 | 67 | name 68 | 69 | ^$ 70 | 71 | 72 | 73 |
74 |
75 | 76 | 77 | 78 | style 79 | 80 | ^$ 81 | 82 | 83 | 84 |
85 |
86 | 87 | 88 | 89 | .* 90 | 91 | ^$ 92 | 93 | 94 | BY_NAME 95 | 96 |
97 |
98 | 99 | 100 | 101 | .* 102 | 103 | http://schemas.android.com/apk/res/android 104 | 105 | 106 | ANDROID_ATTRIBUTE_ORDER 107 | 108 |
109 |
110 | 111 | 112 | 113 | .* 114 | 115 | .* 116 | 117 | 118 | BY_NAME 119 | 120 |
121 |
122 |
123 |
124 | 125 | 127 |
128 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /.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 | 64 | 65 | 69 | 70 | -------------------------------------------------------------------------------- /.idea/markdown-navigator-enh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 最新版本:2.1.2 2 | # 介绍 3 | 4 | rv-multi-itemtype 是一个轻松优雅实现RecyclerView item 5 | 多样式的强大组件。它将RecyclerView 6 | item的样式抽象为一个ItemType,每一种ItemType都自己独立的点击事件处理及视图数据绑定行为,极大地降低了耦合度,极大简化了item相关点击事件处理过程。 7 | 正是因为有了上述功能支持,我们在给RecyclerView添加头布局、脚布局以及复杂多样式item布局、RecyclerView嵌套布局的时候,就简单的太多了! 8 | 9 | # 核心优势 10 | 11 | 1. **相比于BaseQuickAdapter及 MultiType库,rv-multi-itemtype 12 | 对RecyclerView 多样式item实现更优雅、更简单!尤其是在“单 bean 类型对应多样 item 13 | 类型”的用法上, 相较于MultiType 的Linker 实现,简单太多了!!** 14 | 15 | 2. **支持”单 bean 类型对应多样 item 类型“及”多 bean 类型对应多样 item 16 | 类型“用法。** 17 | 18 | 3. **相比于其他任意RecyclerView辅助组件,rv-multi-itemtype库提供的核心组件 19 | ItemManager可任意改造其他RecyclerView Adapter,可无缝兼容类似于jetpack 20 | Paging2、3系列组件提供的Adapter!** 21 | 22 | 4. **仿系统实现在xml布局文件声明android:onClick="方法名"方式实现了item 23 | view事件点击** 24 | 25 | 5. **rv-multi-itemtype 应用泛型+反射+自定义注解技术以减少模板代码创建,轻松实现 26 | item view(包括 item 子 view)点击事件监听, 大大简化开发者应用。** 27 | 28 | 6. **支持DiffUtil。** 29 | 30 | 7. **支持ViewBinding。** 31 | 32 | 33 | # 依赖 34 | 35 | 1. **在工程根目录的 build.gradle 文件添加 jitpack 仓库地址:** 36 | 37 | ``` 38 | allprojects { 39 | repositories { 40 | //... 41 | maven { url 'https://jitpack.io' } 42 | } 43 | } 44 | 45 | ``` 46 | 47 | 2. **在 app module 的 build.gradle文件添加依赖:** 48 | 49 | ``` 50 | dependencies { 51 | // 必须项 52 | implementation 'com.github.censhengde.rv-multi-itemtype:core:lastVersion' 53 | // 可选项。 当有分页需求并且引用jetpack paging3 组件时依赖。 54 | implementation 'com.github.censhengde.rv-multi-itemtype:paging:lastVersion' 55 | } 56 | ``` 57 | 58 | 59 | # 用法 60 | 61 | ## 一、预前准备 62 | 63 | **这里极力推荐 ViewBinding 的用法!** 64 | 65 | ### 1.1:在 app module build.gradle 文件中开启 ViewBinding 支持: 66 | 67 | ``` 68 | android { 69 | // ...... 70 | viewBinding { 71 | enabled true 72 | } 73 | // ...... 74 | } 75 | ``` 76 | 77 | ### 1.2:在 app module proguard-rules.pro 文件中配置忽略 ViewBinding混淆: 78 | 79 | **(不配置会导致无法反射创建ViewBinding对象,程序崩溃!当然,用户要是不嫌麻烦也可以覆盖 80 | SimpleItemType 的 onCreateViewBinding 方法手动创建 ViewBinding对象。)** 81 | 82 | ``` 83 | # 保持 ViewBinding 子类不被混淆。 84 | -keep class * implements androidx.viewbinding.ViewBinding { 85 | *; 86 | } 87 | ``` 88 | 89 | ## 二:单 bean 类型对应多样 item类型用法。 90 | 91 | ### 2.1:声明 item 实体类: 92 | 93 | ``` 94 | public class ItemBean { 95 | 96 | //所有Item类型都在这里定义 97 | public static final int TYPE_00 = 0; 98 | public static final int TYPE_01 = 1; 99 | public static final int TYPE_02 = 2; 100 | 101 | public int id; 102 | // Item类型标识 103 | public int viewType; 104 | 105 | 106 | //item具体业务数据字段 107 | public String text = ""; 108 | 109 | 110 | public ItemBean(int viewType, String text) { 111 | this.viewType = viewType; 112 | this.text = text; 113 | } 114 | 115 | } 116 | ``` 117 | 118 | ### 2.2:编写 00 号类型item 的布局文件 item_00.xml: 119 | 120 | ``` 121 | 122 | 128 | 129 | 138 | 139 | 140 | ``` 141 | 142 | ### 2.3:声明一个00号类型 item 的 ItemType,并继承自SimpleItemType: 143 | 144 | ``` 145 | class ItemType00 : SimpleItemType() { 146 | 147 | 148 | override fun isMatched(bean: Any?, position: Int): Boolean { 149 | // 如果当前 position 的bean 对象是 ItemBean 类型且 bean.viewType == ItemBean.TYPE_00 150 | // 则表明当前 position 是与“我”相匹配的,即当前 position 是 00号类型的item样式。 151 | return bean is ItemBean && bean.viewType == ItemBean.TYPE_00 152 | } 153 | 154 | // 这里其实就是 onBindViewHolder 方法的演变,只是把ViewHolder 参数 155 | // 转变成了 ViewBinding 对象,这样使用起来就特别简单了!去除一切自定义 156 | // ViewHolder及 findViewById 工作! 157 | override fun onBindView(vb: Item00Binding, bean: ItemBean, position: Int) { 158 | vb.tvA.text = bean.text 159 | } 160 | 161 | 162 | } 163 | ``` 164 | 165 | 说明:SimpleItemType 第一个 泛型参数传的是 bean 类型,第二个泛型参数传的是 166 | 该item类型的布局文件的 ViewBinding 类型(由gradle 根据 item_00.xml 167 | 文件自动生成)。 168 | 169 | ·注意看 isMatched(...) 方法的实现,它是区分 item 类型的关键! 170 | 171 | ### 2.4:同理,编写01号类型的item 布局文件:item_01.xml:(详见工程,略) 172 | 173 | ### 2.5:同理,声明 01号类型 item对应的 ItemType: 174 | 175 | ``` 176 | class ItemType01 : SimpleItemType() { 177 | 178 | override fun isMatched(bean: Any?, position: Int): Boolean { 179 | return bean is ItemBean && bean.viewType == ItemBean.TYPE_01 180 | } 181 | 182 | override fun onBindView(vb: Item01Binding, bean: ItemBean, position: Int) { 183 | vb.tvA.text = bean.text 184 | } 185 | 186 | } 187 | ``` 188 | 189 | 这里请再次体会一下 isMatched(...) 方法的含义!!! 190 | 191 | 同理,再创建一个02号类型 item 的 布局文件 item_02.xml(详见工程源码) 192 | 193 | 再创建一个 02 号类型 item 对应的 ItemType: 194 | 195 | ``` 196 | class ItemType02 : SimpleItemType() { 197 | 198 | override fun isMatched(bean: Any?, position: Int): Boolean { 199 | return bean is ItemBean && bean.viewType == ItemBean.TYPE_02 200 | } 201 | 202 | override fun onBindView(vb: Item02Binding, bean: ItemBean, position: Int) { 203 | vb.tvA.text = bean.text 204 | } 205 | } 206 | ``` 207 | 208 | 请再次再次体会 isMatched(...) 方法的含义!!还不懂?找群主!! 209 | 210 | ### 2.6:在Activity 中调用: 211 | 212 | #### 2.6.1:Activity 布局文件:activity_multi_item.xml 213 | 214 | ``` 215 | 216 | 220 | 221 | 227 | 228 | 229 | 230 | ``` 231 | 232 | #### 2.6.2:Activity 中的实现: 233 | 234 | ``` 235 | class MultiItemDemo01Activity : AppCompatActivity() { 236 | 237 | lateinit var adapter: MultiAdapter 238 | private val vb by lazy { ActivityMultiItemBinding.inflate(LayoutInflater.from(this)) } 239 | 240 | override fun onCreate(savedInstanceState: Bundle?) { 241 | super.onCreate(savedInstanceState) 242 | setContentView(vb.root) 243 | //初始化ItemType 244 | val item00 = ItemType00() 245 | val item01 = ItemType01() 246 | val item02 = ItemType02() 247 | /*初始化Adapter*/ 248 | adapter = MultiAdapter(this) 249 | /*将所有ItemType添加到Adapter中*/ 250 | adapter.addItemType(item00) 251 | .addItemType(item01) 252 | .addItemType(item02) 253 | /*设置数据*/ 254 | adapter.setDataList(getData()) 255 | vb.rvList.adapter = adapter 256 | } 257 | 258 | /** 259 | * 模拟数据 260 | */ 261 | private fun getData(): List { 262 | val beans = ArrayList() 263 | for (i in 0..5) { 264 | beans.add(ItemBean(ItemBean.TYPE_00, "我是A_00类Item$i")) 265 | beans.add(ItemBean(ItemBean.TYPE_01, "我是A_01类Item${i + 1}")) 266 | beans.add(ItemBean(ItemBean.TYPE_02, "我是A_02类Item${i + 2}")) 267 | } 268 | return beans 269 | } 270 | 271 | } 272 | 273 | ``` 274 | 275 | 点击运行之,如图: 276 | 277 | ![单bean类型对应多样item类型.jpg](image/单bean类型对应多样item类型.jpg) 278 | 279 | ## 四、多 bean 类型对应多样 item 类型用法(顺便介绍了基于 paging3 PagingDataAdapter 改造而来的MultiPagingDataAdapter 用法) 280 | 281 | ### 4.1 声明item 实体类 BeanA,BeanB,BeanC: 282 | 283 | ``` 284 | public class BeanA { 285 | 286 | //item具体业务数据字段 287 | public int id; 288 | public String text = ""; 289 | 290 | public BeanA( String text) { 291 | this.text = text; 292 | } 293 | 294 | } 295 | 296 | public class BeanB { 297 | 298 | public String text; 299 | 300 | public BeanB(String text) { 301 | this.text = text; 302 | } 303 | } 304 | 305 | public class BeanC { 306 | 307 | public String text=""; 308 | 309 | public BeanC( String text) { 310 | this.text = text; 311 | } 312 | } 313 | ``` 314 | 315 | ### 4.2 声明 A,B,C 类型item对应的布局文件(详见工程源码,略) 316 | 317 | ### 4.3 声明 A,B,C 类型item对应的 ItemType: 318 | 319 | ``` 320 | public class AItemType extends SimpleItemType { 321 | 322 | 323 | @Override 324 | public boolean isMatched(@Nullable Object bean, int position) { 325 | // 只有当前 bean 是 BeanA 类型,才能与“我”匹配。 326 | return bean instanceof BeanA; 327 | } 328 | 329 | @Override 330 | public void onBindView(@NonNull ItemABinding binding, 331 | @NotNull BeanA itemBean, 332 | int position) { 333 | binding.tvA.setText(itemBean.text); 334 | } 335 | } 336 | 337 | public class BItemType extends SimpleItemType { 338 | 339 | @Override 340 | public boolean isMatched(Object bean, int position) { 341 | // 只有当前 bean 是 BeanB 类型,才能与“我”匹配。 342 | return bean instanceof BeanB; 343 | } 344 | 345 | @Override 346 | public void onBindView(@NonNull ItemBBinding binding, @NonNull BeanB data, int position) { 347 | 348 | binding.tvB.setText(data.text) 349 | } 350 | 351 | } 352 | 353 | public class CItemType extends SimpleItemType { 354 | 355 | @Override 356 | public boolean isMatched(Object bean, int position) { 357 | // 只有当前 bean 是 BeanC 类型,才能与“我”匹配。 358 | return bean instanceof BeanC; 359 | } 360 | 361 | @Override 362 | public void onBindView(@NonNull ItemCBinding binding, 363 | @NonNull BeanC bean, int position) { 364 | binding.tvC.setText(bean.text); 365 | } 366 | } 367 | 368 | ``` 369 | 370 | ### 4.4 在Activity中的实现: 371 | 372 | ``` 373 | class MultiItemDemo02Activity : AppCompatActivity() { 374 | 375 | private lateinit var adapter: MultiPagingDataAdapter 376 | private val vb by lazy { ActivityMultiItemBinding.inflate(LayoutInflater.from(this)) } 377 | 378 | override fun onCreate(savedInstanceState: Bundle?) { 379 | super.onCreate(savedInstanceState) 380 | setContentView(vb.root) 381 | //初始化ItemType 382 | val aItemType = AItemType() 383 | val bItemType = BItemType() 384 | val cItemType = CItemType() 385 | /*初始化Adapter*/ 386 | adapter = MultiPagingDataAdapter(this, diffCallback = object : DiffUtil.ItemCallback() { 387 | override fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean =false 388 | override fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean =false 389 | 390 | }) 391 | /*将所有ItemType添加到Adapter中*/ 392 | adapter.addItemType(aItemType) 393 | .addItemType(bItemType) 394 | .addItemType(cItemType) 395 | vb.rvList.adapter = adapter 396 | /*设置数据*/ 397 | lifecycleScope.launch { 398 | adapter.submitData(PagingData.from(getData())) 399 | } 400 | 401 | } 402 | 403 | /** 404 | * 模拟数据 405 | */ 406 | private fun getData(): List { 407 | val beans = ArrayList() 408 | for (i in 0..5) { 409 | beans.add(BeanA( "我是A类Item$i")) 410 | beans.add(BeanB("我是B类Item${i + 1}")) 411 | beans.add(BeanC( "我是C类Item${i + 2}")) 412 | } 413 | return beans 414 | } 415 | 416 | } 417 | 418 | ``` 419 | 420 | 点击运行之,如图: 421 | 422 | ![多bean类型对应多样item类型.jpg](image/多bean类型对应多样item类型.jpg) 423 | 424 | ## 五.item view(包括 item 子 view)点击事件处理。 425 | 426 | item view 点击事件处理是模仿了系统在xml 布局文件中声明 android:onClick="方法名" 427 | 属性实现方式实现。rv-multi-itemtype 自定义了 "linkClick"和”linkLongClick“ 428 | 这两个xml 属性,其值含义与系统 android:onClick="方法名"相同,并通过自定义 429 | LayoutInflater.Factory2 430 | 实现这两个属性值的捕获,最后通过反射技术获取到对应的目标方法实现点击事件回调。其原理与系统 431 | android:onClick="方法名" 实现方式如出一辙! 432 | 以“多bean类型对应多样item类型”实现为例: 433 | 434 | **第一步**:在 AItemType 构造方法中调用 435 | SimpleItemtype.bind(clickEventReceiver Any) 436 | 方法绑定点击事件接收者(此时可以对比一下系统 437 | android:onClick="方法名"实现,其默认的点击事件接收者是当前xml 438 | 布局对应的Activity。),并声明点击事件回调方法,代码如下: 439 | 440 | ``` 441 | public class AItemType extends SimpleItemType { 442 | 443 | public AItemType() { 444 | bind(this);// 绑定点击事件接收者。 445 | } 446 | 447 | @Override 448 | public boolean isMatched(@Nullable Object bean, int position) { 449 | return bean instanceof BeanA; 450 | } 451 | 452 | 453 | @Override 454 | public void onBindView(@NonNull ItemABinding binding, 455 | @NotNull BeanA itemBean, 456 | int position) { 457 | binding.tvA.setText(itemBean.text); 458 | } 459 | 460 | /** 461 | * item点击事件回调 462 | * 注意 bean 类型,一定要与当前 ItemType 的 bean 类型对应。 463 | */ 464 | @Keep 465 | private void onClickItem(View view, BeanA bean, int position) { 466 | Toast.makeText(view.getContext(), "点击事件:" + bean.text, Toast.LENGTH_SHORT).show(); 467 | } 468 | } 469 | 470 | ``` 471 | 472 | 这里要注意点击事件回调方法的书写,返回值为 void ,形参列表顺序及含义分别是: 473 | 点击的那个 View 对象、当前 position 对应的item bean 对象、当前 position。 **( 474 | @Keep 注解是防止代码混淆,否则反射不到回调方法)** 475 | 476 | **第二步**:在 AItemType 对应的 item_a.xml 布局中将要注册点击事件的 view 声明 477 | “app:linkClick" 属性,并将点击事件回调的方法名注册进去,代码如下: 478 | 479 | ``` 480 | 487 | 488 | 497 | 498 | 499 | ``` 500 | 501 | 再次编译运行APP 就可以看到效果了! 502 | 503 | **(item view 504 | 长点击事件实现同理,只需要注意的是长点击事件回调方法的书写 必须要有 boolean 505 | 返回值!)** 506 | 507 | 以上就是本框架的主要用法了,有不明白之处找群主,虽忙必复! 508 | 509 | # 问题反馈 510 | 511 | 1 请加群: 512 | 513 | ![问题反馈群群聊二维码.png](image/MultiAdapter问题反馈群群聊二维码.png) 514 | 515 | 516 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion 30 6 | buildToolsVersion "30.0.3" 7 | viewBinding { 8 | enabled true 9 | } 10 | defaultConfig { 11 | applicationId "com.tencent.itemtype" 12 | minSdkVersion 19 13 | targetSdkVersion 30 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | 19 | javaCompileOptions { 20 | annotationProcessorOptions { 21 | arguments += [ 22 | "room.schemaLocation" : "$projectDir/schemas".toString(), 23 | "room.incremental" : "true", 24 | "room.expandProjection": "true"] 25 | } 26 | } 27 | } 28 | 29 | buildTypes { 30 | release { 31 | minifyEnabled true 32 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 33 | } 34 | debug{ 35 | minifyEnabled false 36 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 37 | } 38 | } 39 | compileOptions { 40 | sourceCompatibility = 1.8 41 | targetCompatibility = 1.8 42 | } 43 | 44 | } 45 | repositories { 46 | flatDir { 47 | dirs('libs') 48 | } 49 | } 50 | dependencies { 51 | implementation fileTree(dir: 'libs', include: ['*.jar']) 52 | 53 | implementation 'androidx.appcompat:appcompat:1.2.0' 54 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 55 | implementation 'com.google.android.material:material:1.4.0' 56 | implementation project(path: ':core') 57 | implementation 'com.drakeet.multitype:multitype:4.3.0' 58 | api ('androidx.paging:paging-runtime:3.0.1'){ 59 | exclude group: "org.jetbrains.kotlinx" 60 | } 61 | //kotlin 协程 62 | api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2" 63 | api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2" 64 | implementation project(path: ':paging') 65 | implementation 'androidx.recyclerview:recyclerview:1.2.1' 66 | 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /app/libs/lib-http-release.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/censhengde/rv-multi-itemtype/51ff5779293d1171464d95377a509cbdca61c688/app/libs/lib-http-release.aar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | 24 | # 保持 ViewBinding 子类不被混淆。 25 | -keep class * implements androidx.viewbinding.ViewBinding { 26 | *; 27 | } 28 | -keepclassmembers class * { 29 | @com.tencent.lib.multi.core.annotation.OnClickItemView ; 30 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/DataUtils.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example 2 | 3 | /** 4 | 5 | * Author:岑胜德 on 2021/8/30 15:19 6 | 7 | * 说明: 8 | 9 | */ 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/bean/BeanA.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.bean; 2 | 3 | /** 4 | * Author:岑胜德 on 2021/2/22 17:17 5 | * 6 | * 说明: 7 | */ 8 | public class BeanA { 9 | 10 | public String text; 11 | 12 | public BeanA(String text) { 13 | this.text = text; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/bean/BeanB.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.bean; 2 | 3 | /** 4 | * Author:岑胜德 on 2021/2/22 17:17 5 | * 6 | * 说明: 7 | */ 8 | public class BeanB { 9 | 10 | public String text; 11 | 12 | public BeanB(String text) { 13 | this.text = text; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/bean/BeanC.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.bean; 2 | 3 | /** 4 | * Author:岑胜德 on 2021/5/12 17:24 5 | * 6 | * 说明:简单的列表单选/多选直接继承 SimpleCheckable 即可, 7 | * 更复杂的列表选择请实现Checkable接口 8 | * */ 9 | public class BeanC { 10 | 11 | public String text=""; 12 | 13 | public BeanC( String text) { 14 | this.text = text; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/bean/ItemBean.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.bean; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.util.Objects; 6 | 7 | /** 8 | * Author:岑胜德 on 2021/1/6 18:05 9 | *

10 | * 说明: 11 | */ 12 | public class ItemBean { 13 | 14 | //所有Item类型都在这里定义 15 | public static final int TYPE_00 = 0; 16 | public static final int TYPE_01 = 1; 17 | public static final int TYPE_02 = 2; 18 | 19 | public int id; 20 | // Item类型标识(很关键!) 21 | public int viewType; 22 | 23 | 24 | //item具体业务数据字段 25 | public String text = ""; 26 | 27 | 28 | public ItemBean(int viewType, String text) { 29 | this.viewType = viewType; 30 | this.text = text; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/item/AItemType.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.item; 2 | 3 | import android.view.View; 4 | import android.widget.Toast; 5 | 6 | import androidx.annotation.Keep; 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | import com.tencent.lib.multi.core.MultiViewHolder; 11 | import com.tencent.lib.multi.core.SimpleItemType; 12 | import com.tencent.multiadapter.databinding.ItemABinding; 13 | import com.tencent.multiadapter.example.bean.BeanA; 14 | 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | /** 18 | * Author:岑胜德 on 2021/1/6 18:04 19 | *

20 | * 说明: 21 | */ 22 | public class AItemType extends SimpleItemType { 23 | 24 | public AItemType() { 25 | bind(this); 26 | } 27 | 28 | @Override 29 | public boolean isMatched(@Nullable Object bean, int position) { 30 | return bean instanceof BeanA; 31 | } 32 | 33 | 34 | @Override 35 | public void onBindView(@NonNull ItemABinding binding, 36 | @NotNull BeanA itemBean, 37 | int position) { 38 | binding.tvA.setText(itemBean.text); 39 | } 40 | 41 | /** 42 | * item点击事件 43 | * 注意 bean 类型,一定要与当前 ItemType 的 bean 类型对应。 44 | */ 45 | @Keep 46 | private void onClickItem(View view, BeanA bean, int position) { 47 | Toast.makeText(view.getContext(), "点击事件:" + bean.text, Toast.LENGTH_SHORT).show(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/item/BItemType.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.item; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import com.tencent.lib.multi.core.MultiViewHolder; 10 | import com.tencent.lib.multi.core.SimpleItemType; 11 | import com.tencent.multiadapter.databinding.ItemBBinding; 12 | import com.tencent.multiadapter.example.bean.BeanB; 13 | 14 | /** 15 | * Author:岑胜德 on 2021/1/6 18:04 16 | *

17 | * 说明: 18 | */ 19 | public class BItemType extends SimpleItemType { 20 | 21 | public BItemType() { 22 | bind(this); 23 | } 24 | 25 | @Override 26 | public boolean isMatched(Object bean, int position) { 27 | return bean instanceof BeanB; 28 | } 29 | 30 | 31 | @Override 32 | public void onBindView(@NonNull ItemBBinding binding, @NonNull BeanB data, int position) { 33 | binding.tvB.setText(data.text); 34 | 35 | } 36 | 37 | /** 38 | * item点击事件 39 | * 注意 bean 类型,一定要与当前 ItemType 的 bean 类型对应。 40 | */ 41 | private boolean onLongClick(View view, BeanB bean, int position) { 42 | Toast.makeText(view.getContext(), "长点击事件:" + bean.text, Toast.LENGTH_SHORT).show(); 43 | return true; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/item/CItemType.java: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.item; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.util.Log; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.tencent.lib.multi.core.SimpleItemType; 9 | import com.tencent.lib.multi.core.MultiViewHolder; 10 | import com.tencent.multiadapter.databinding.ItemCBinding; 11 | import com.tencent.multiadapter.example.bean.BeanC; 12 | 13 | /** 14 | * Author:岑胜德 on 2021/1/6 18:04 15 | *

16 | * 说明: 17 | */ 18 | public class CItemType extends SimpleItemType { 19 | 20 | @Override 21 | public boolean isMatched(Object bean, int position) { 22 | return bean instanceof BeanC; 23 | } 24 | 25 | @Override 26 | public void onBindView(@NonNull ItemCBinding binding, 27 | @NonNull BeanC bean, int position) { 28 | binding.tvC.setText(bean.text); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/item/ItemType00.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.item 2 | 3 | import android.view.View 4 | import android.widget.Toast 5 | import androidx.annotation.Keep 6 | import com.tencent.lib.multi.core.MultiViewHolder 7 | import com.tencent.lib.multi.core.SimpleItemType 8 | import com.tencent.multiadapter.databinding.Item00Binding 9 | import com.tencent.multiadapter.example.bean.ItemBean 10 | 11 | /** 12 | 13 | * Author:岑胜德 on 2021/12/5 20:31 14 | 15 | * 说明: 16 | 17 | */ 18 | class ItemType00 : SimpleItemType() { 19 | 20 | init { 21 | bind(this) 22 | } 23 | 24 | override fun isMatched(bean: Any?, position: Int): Boolean { 25 | return bean is ItemBean && bean.viewType == ItemBean.TYPE_00 26 | } 27 | 28 | 29 | override fun onBindView(vb: Item00Binding, bean: ItemBean, position: Int) { 30 | vb.tvA.text = bean.text 31 | } 32 | 33 | /** 34 | *item点击事件 35 | */ 36 | @Keep 37 | private fun onClickItem(view: View, itemBean: ItemBean, position: Int) { 38 | Toast.makeText( 39 | view.context, 40 | "点击事件:ItemBean:${itemBean.text},position:$position", 41 | Toast.LENGTH_SHORT 42 | ).show() 43 | } 44 | 45 | /** 46 | * item 长点击事件 47 | */ 48 | @Keep 49 | private fun onLongClick(view: View, itemBean: ItemBean, position: Int): Boolean { 50 | Toast.makeText( 51 | view.context, 52 | "长点击事件:ItemBean:${itemBean.text},position:$position", 53 | Toast.LENGTH_SHORT 54 | ).show() 55 | return true 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/item/ItemType01.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.item 2 | 3 | import com.tencent.lib.multi.core.SimpleItemType 4 | import com.tencent.multiadapter.databinding.Item01Binding 5 | import com.tencent.multiadapter.example.bean.ItemBean 6 | 7 | /** 8 | 9 | * Author:岑胜德 on 2021/12/5 20:31 10 | 11 | * 说明: 12 | 13 | */ 14 | class ItemType01 : SimpleItemType() { 15 | 16 | override fun isMatched(bean: Any?, position: Int): Boolean { 17 | return bean is ItemBean && bean.viewType == ItemBean.TYPE_01 18 | } 19 | 20 | override fun onBindView(vb: Item01Binding, bean: ItemBean, position: Int) { 21 | vb.tvA.text = bean.text 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/item/ItemType02.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.item 2 | 3 | import com.tencent.lib.multi.core.SimpleItemType 4 | import com.tencent.multiadapter.databinding.Item02Binding 5 | import com.tencent.multiadapter.example.bean.ItemBean 6 | 7 | /** 8 | 9 | * Author:岑胜德 on 2021/12/5 20:31 10 | 11 | * 说明: 12 | 13 | */ 14 | class ItemType02 : SimpleItemType() { 15 | 16 | override fun isMatched(bean: Any?, position: Int): Boolean { 17 | return bean is ItemBean && bean.viewType == ItemBean.TYPE_02 18 | } 19 | 20 | override fun onBindView(vb: Item02Binding, bean: ItemBean, position: Int) { 21 | vb.tvA.text = bean.text 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/ui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.ui 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.View 7 | import android.widget.Button 8 | import androidx.appcompat.app.AppCompatActivity 9 | import com.tencent.multiadapter.R 10 | 11 | class MainActivity : AppCompatActivity() { 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_main) 16 | } 17 | 18 | fun onClickBtn(view: View) { 19 | val btn = (view as Button) 20 | when (btn.id) { 21 | R.id.demo_01 -> { 22 | goTo(MultiItemDemo01Activity::class.java) 23 | } 24 | R.id.demo_02 -> { 25 | goTo(MultiItemDemo02Activity::class.java) 26 | } 27 | 28 | } 29 | 30 | } 31 | 32 | private fun goTo(clazz: Class) { 33 | startActivity(Intent(this, clazz)) 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/ui/MultiItemDemo01Activity.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.ui 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import androidx.appcompat.app.AppCompatActivity 6 | import com.tencent.lib.multi.MultiAdapter 7 | import com.tencent.multiadapter.databinding.ActivityMultiItemBinding 8 | import com.tencent.multiadapter.example.bean.ItemBean 9 | import com.tencent.multiadapter.example.item.ItemType00 10 | import com.tencent.multiadapter.example.item.ItemType01 11 | import com.tencent.multiadapter.example.item.ItemType02 12 | import java.util.* 13 | 14 | /** 15 | * 单 bean 类型对应多样 item。 16 | */ 17 | class MultiItemDemo01Activity : AppCompatActivity() { 18 | 19 | lateinit var adapter: MultiAdapter 20 | private val vb by lazy { ActivityMultiItemBinding.inflate(LayoutInflater.from(this)) } 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | setContentView(vb.root) 25 | //初始化ItemType 26 | val item00 = ItemType00() 27 | val item01 = ItemType01() 28 | val item02 = ItemType02() 29 | /*初始化Adapter*/ 30 | adapter = MultiAdapter(initialCapacity = 3) 31 | adapter.clearAllItemTypes() 32 | /*将所有ItemType添加到Adapter中*/ 33 | adapter.addItemType(item00) 34 | .addItemType(item01) 35 | .addItemType(item02) 36 | /*设置数据*/ 37 | adapter.setDataList(getData()) 38 | vb.rvList.adapter = adapter 39 | } 40 | 41 | /** 42 | * 模拟数据 43 | */ 44 | private fun getData(): List { 45 | val beans = ArrayList() 46 | for (i in 0..5) { 47 | beans.add(ItemBean(ItemBean.TYPE_00, "我是A_00类Item$i")) 48 | beans.add(ItemBean(ItemBean.TYPE_01, "我是A_01类Item${i + 1}")) 49 | beans.add(ItemBean(ItemBean.TYPE_02, "我是A_02类Item${i + 2}")) 50 | } 51 | return beans 52 | } 53 | 54 | override fun onDestroy() { 55 | adapter.clearDataList() 56 | super.onDestroy() 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/tencent/multiadapter/example/ui/MultiItemDemo02Activity.kt: -------------------------------------------------------------------------------- 1 | package com.tencent.multiadapter.example.ui 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.lifecycle.lifecycleScope 7 | import androidx.paging.PagingData 8 | import androidx.recyclerview.widget.DiffUtil 9 | import com.csd.multi.paging.MultiPagingDataAdapter 10 | import com.tencent.multiadapter.databinding.ActivityMultiItemBinding 11 | import com.tencent.multiadapter.example.bean.BeanA 12 | import com.tencent.multiadapter.example.bean.BeanB 13 | import com.tencent.multiadapter.example.bean.BeanC 14 | import com.tencent.multiadapter.example.item.AItemType 15 | import com.tencent.multiadapter.example.item.BItemType 16 | import com.tencent.multiadapter.example.item.CItemType 17 | import kotlinx.coroutines.launch 18 | import java.util.* 19 | /** 20 | * 多 bean 类型对应多样 item。 21 | */ 22 | class MultiItemDemo02Activity : AppCompatActivity() { 23 | 24 | private lateinit var adapter: MultiPagingDataAdapter 25 | private val vb by lazy { ActivityMultiItemBinding.inflate(LayoutInflater.from(this)) } 26 | 27 | override fun onCreate(savedInstanceState: Bundle?) { 28 | super.onCreate(savedInstanceState) 29 | setContentView(vb.root) 30 | //初始化ItemType 31 | val aItemType = AItemType() 32 | val bItemType = BItemType() 33 | val cItemType = CItemType() 34 | /*初始化Adapter*/ 35 | adapter = MultiPagingDataAdapter(diffCallback = object : 36 | DiffUtil.ItemCallback() { 37 | override fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean = false 38 | override fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean = false 39 | 40 | }, 3) 41 | adapter.clearAllItemTypes() 42 | /*将所有ItemType添加到Adapter中*/ 43 | adapter.addItemType(aItemType) 44 | .addItemType(bItemType) 45 | .addItemType(cItemType) 46 | vb.rvList.adapter = adapter 47 | /*设置数据*/ 48 | lifecycleScope.launch { 49 | adapter.submitData(PagingData.from(getData())) 50 | } 51 | 52 | } 53 | 54 | /** 55 | * 模拟数据 56 | */ 57 | private fun getData(): List { 58 | val beans = ArrayList() 59 | for (i in 0..5) { 60 | beans.add(BeanA( "我是A类Item$i")) 61 | beans.add(BeanB("我是B类Item${i + 1}")) 62 | beans.add(BeanC( "我是C类Item${i + 2}")) 63 | } 64 | return beans 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |