onItemClickListener) {
- this.mOnItemClickListener = onItemClickListener;
- }
-}
diff --git a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/adapter/RcvMultipleBaseAdapter.java b/app/src/main/java/com/qinshou/rcvbaseadapterdemo/adapter/RcvMultipleBaseAdapter.java
deleted file mode 100644
index 589775a..0000000
--- a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/adapter/RcvMultipleBaseAdapter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.qinshou.rcvbaseadapterdemo.adapter;
-
-import android.content.Context;
-import android.util.SparseArray;
-import android.view.ViewGroup;
-
-import com.qinshou.rcvbaseadapterdemo.holder.BaseViewHolder;
-import com.qinshou.rcvbaseadapterdemo.itemview.BaseItemView;
-
-
-/**
- * Description:item 为多布局类型的 RecyclerView 的适配器
- * 可以实现一对多(一个实体类对应多种布局)和多对多(多个实体类对应多个布局)
- * 使用时创建该适配器实例,创建不同的 ItemView 继承 BaseItemView,
- * 然后调用 addItemView() 方法传入 ItemView 即可
- * {@link com.qinshou.rcvbaseadapterdemo.itemview.BaseItemView}
- * BaseItemView 中有一个方法 isForViewType() 用来判断何时引入哪种子布局,多对多时不用覆盖该方法,内部会根据泛型的真实类型和
- * 该 position 的数据的类型判断,一对多时需覆盖该方法加入自己的逻辑判断,否则同一类型只会使用传入的第一个 ItemView
- *
- * Created by 禽兽先生
- * Created on 2018/4/9
- */
-
-public class RcvMultipleBaseAdapter extends RcvBaseAdapter {
- private SparseArray itemViewSparseArray;
-
- public RcvMultipleBaseAdapter(Context context) {
- super(context, 0);
- itemViewSparseArray = new SparseArray<>();
- }
-
- @Override
- public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return itemViewSparseArray.get(viewType).onCreateViewHolder(parent);
- }
-
- @Override
- public int getItemViewType(int position) {
- for (int i = 0; i < itemViewSparseArray.size(); i++) {
- BaseItemView baseItemView = itemViewSparseArray.valueAt(i);
- if (baseItemView.isForViewType(getDataList().get(position), position)) {
- return itemViewSparseArray.keyAt(i);
- }
- }
- throw new IllegalArgumentException("No ItemView added that matches position=" + position + " in data source");
- }
-
- @Override
- public void bindViewHolder(BaseViewHolder holder, Object itemData, int position) {
- for (int i = 0; i < itemViewSparseArray.size(); i++) {
- BaseItemView baseItemView = itemViewSparseArray.valueAt(i);
- if (baseItemView.isForViewType(itemData, position)) {
- baseItemView.bindViewHolder(holder, itemData, position);
- return;
- }
- }
- }
-
- public void addItemView(BaseItemView baseItemView) {
- itemViewSparseArray.put(baseItemView.hashCode(), baseItemView);
- }
-
- public void removeItemView(BaseItemView baseItemView) {
- itemViewSparseArray.remove(baseItemView.hashCode());
- }
-}
diff --git a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/adapter/RcvSingleBaseAdapter.java b/app/src/main/java/com/qinshou/rcvbaseadapterdemo/adapter/RcvSingleBaseAdapter.java
deleted file mode 100644
index c4cf92d..0000000
--- a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/adapter/RcvSingleBaseAdapter.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.qinshou.rcvbaseadapterdemo.adapter;
-
-import android.content.Context;
-
-/**
- * Description:item 为单布局的 RecyclerView 的适配器,只是简单继承了 RcvBaseAdapter
- * 如果列表只是相同布局的 item,只需要继承该适配器,实现 public abstract void bindViewHolder(BaseViewHolder holder, T t) 这一个方法即可.
- * Created by 禽兽先生
- * Created on 2017/12/14
- */
-
-public abstract class RcvSingleBaseAdapter extends RcvBaseAdapter {
- public RcvSingleBaseAdapter(Context context, int layoutId) {
- super(context, layoutId);
- }
-}
diff --git a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/entity/MessageEntity.java b/app/src/main/java/com/qinshou/rcvbaseadapterdemo/entity/MessageEntity.java
deleted file mode 100644
index fa90d08..0000000
--- a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/entity/MessageEntity.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.qinshou.rcvbaseadapterdemo.entity;
-
-/**
- * Description:
- * Created by 禽兽先生
- * Created on 2018/10/9
- */
-public class MessageEntity {
- private String message;
- private int userType; //0 表示发送的消息,1 表示接收的消息
-
- public MessageEntity() {
-
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public int getUserType() {
- return userType;
- }
-
- public void setUserType(int userType) {
- this.userType = userType;
- }
-
- @Override
- public String toString() {
- return "MessageEntity{" +
- "message='" + message + '\'' +
- ", userType=" + userType +
- '}';
- }
-}
diff --git a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/holder/BaseViewHolder.java b/app/src/main/java/com/qinshou/rcvbaseadapterdemo/holder/BaseViewHolder.java
deleted file mode 100644
index b63665f..0000000
--- a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/holder/BaseViewHolder.java
+++ /dev/null
@@ -1,193 +0,0 @@
-package com.qinshou.rcvbaseadapterdemo.holder;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.StringRes;
-import android.support.v7.widget.RecyclerView;
-import android.util.SparseArray;
-import android.view.View;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-/**
- * Description:RecyclerView 的 ViewHolder 的基类,可以封装各种通用的方法
- * 比如 View 的背景设置,是否选中的状态设置
- * TextView 的文字设置,字体大小设置,字体颜色设置
- * ImageView 的图片设置,当然,如果一般是网络加载的话,需要获得 ImageView 自己异步加载,也可以在该类中内置 Glide 等第三方库异步加载网络图片
- * 设置 OnClickListener,OnLongClickListener 等
- * Created by 禽兽先生
- * Created on 2017/11/22
- */
-
-public class BaseViewHolder extends RecyclerView.ViewHolder {
- private Context context;
- private View itemView;
- private SparseArray viewSparseArray;
-
- public BaseViewHolder(Context context, View itemView) {
- super(itemView);
- this.context = context;
- this.itemView = itemView;
- this.viewSparseArray = new SparseArray();
- }
-
- public View getItemView() {
- return itemView;
- }
-
- public T findViewById(int viewId) {
- View view = viewSparseArray.get(viewId);
- if (view == null) {
- view = itemView.findViewById(viewId);
- viewSparseArray.put(viewId, view);
- }
- return (T) view;
- }
-
- /**
- * Description:设置控件是否可见
- * Date:2018/3/9
- */
- public BaseViewHolder setVisibility(int viewId, int visibility) {
- View mView = findViewById(viewId);
- if (mView != null) {
- mView.setVisibility(visibility);
- }
- return this;
- }
-
- /**
- * Description:设置 TextView 文本
- * Date:2018/3/9
- */
- public BaseViewHolder setTvText(int viewId, String text) {
- TextView mTextView = findViewById(viewId);
- if (mTextView != null) {
- mTextView.setText(text);
- }
- return this;
- }
-
- /**
- * Description:设置 TextView 文本
- * Date:2018/3/9
- */
- public BaseViewHolder setTvText(int viewId, @StringRes int resId) {
- TextView mTextView = findViewById(viewId);
- if (mTextView != null) {
- mTextView.setText(context.getResources().getString(resId));
- }
- return this;
- }
-
- /**
- * Description:设置 TextView 文本
- * Date:2018/3/9
- */
- public BaseViewHolder setTvText(int viewId, CharSequence text) {
- TextView mTextView = findViewById(viewId);
- if (mTextView != null) {
- mTextView.setText(text);
- }
- return this;
- }
-
- /**
- * Description:设置 Button 文本
- * Date:2018/3/9
- */
- public BaseViewHolder setBtnText(int viewId, String text) {
- Button mButton = findViewById(viewId);
- if (mButton != null) {
- mButton.setText(text);
- }
- return this;
- }
-
- /**
- * Description:设置 Button 文本
- * Date:2018/3/9
- */
- public BaseViewHolder setBtnText(int viewId, @StringRes int resId) {
- Button mButton = findViewById(viewId);
- if (mButton != null) {
- mButton.setText(context.getResources().getString(resId));
- }
- return this;
- }
-
- /**
- * Description:设置 ImageView 图片
- * Date:2018/3/9
- */
- public BaseViewHolder setIvImage(int viewId, Bitmap bitmap) {
- ImageView mImageView = findViewById(viewId);
- if (mImageView != null) {
- mImageView.setImageBitmap(bitmap);
- }
- return this;
- }
-
- /**
- * Description:设置 ImageView 图片
- * Date:2018/3/9
- */
- public BaseViewHolder setIvImage(int viewId, @DrawableRes int resId) {
- ImageView mImageView = findViewById(viewId);
- if (mImageView != null) {
- mImageView.setImageResource(resId);
- }
- return this;
- }
-
- /**
- * Description:设置 View 的点击事件监听器
- * Date:2018/3/9
- */
- public BaseViewHolder setOnClickListener(int viewId, View.OnClickListener onClickListener) {
- View mView = findViewById(viewId);
- if (mView != null) {
- mView.setOnClickListener(onClickListener);
- }
- return this;
- }
-
- /**
- * Description:设置 View 的 selected 状态
- * Date:2018/3/9
- */
- public BaseViewHolder setSelected(int viewId, boolean selected) {
- View mView = findViewById(viewId);
- if (mView != null) {
- mView.setSelected(selected);
- }
- return this;
- }
-
- /**
- * Description:设置 View 的背景色
- * Date:2018/3/9
- */
- public BaseViewHolder setBackgroundColor(int viewId, @ColorInt int color) {
- View mView = findViewById(viewId);
- if (mView != null) {
- mView.setBackgroundColor(color);
- }
- return this;
- }
-
- /**
- * Description:设置 View 的背景
- * Date:2018/3/9
- */
- public BaseViewHolder setBackgroundResource(int viewId, @DrawableRes int resId) {
- View mView = findViewById(viewId);
- if (mView != null) {
- mView.setBackgroundResource(resId);
- }
- return this;
- }
-}
diff --git a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/itemview/BaseItemView.java b/app/src/main/java/com/qinshou/rcvbaseadapterdemo/itemview/BaseItemView.java
deleted file mode 100644
index 8bfd490..0000000
--- a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/itemview/BaseItemView.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.qinshou.rcvbaseadapterdemo.itemview;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.qinshou.rcvbaseadapterdemo.holder.BaseViewHolder;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-
-/**
- * Description:RecyclerView 单数据对多类型布局,多数据对多类型布局的适配器的 BaseItemView
- * Created by 禽兽先生
- * Created on 2018/4/9
- */
-
-public abstract class BaseItemView {
- private Context context;
- private int layoutId;
-
- public BaseItemView(Context context, int layoutId) {
- this.context = context;
- this.layoutId = layoutId;
- }
-
- public BaseViewHolder onCreateViewHolder(ViewGroup parent) {
- View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false);
- return new BaseViewHolder(context, itemView);
- }
-
- /**
- * Description: 子类可以覆蓋此方法决定引用该子布局的时机
- * Date:2018/8/6
- *
- * @param item 该position对应的数据
- * @param position position
- * @return 是否属于子布局
- */
- public boolean isForViewType(T item, int position) {
- Type type = getClass().getGenericSuperclass();
- ParameterizedType parameterizedType = (ParameterizedType) type;
- Class clazz = (Class) parameterizedType.getActualTypeArguments()[0];
- return item.getClass() == clazz;
- }
-
- /**
- * Description:绑定 UI 和数据
- * Date:2018/8/6
- */
- public abstract void bindViewHolder(BaseViewHolder holder, T itemData, int position);
-}
diff --git a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/listener/OnItemClickListener.java b/app/src/main/java/com/qinshou/rcvbaseadapterdemo/listener/OnItemClickListener.java
deleted file mode 100644
index 03427df..0000000
--- a/app/src/main/java/com/qinshou/rcvbaseadapterdemo/listener/OnItemClickListener.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.qinshou.rcvbaseadapterdemo.listener;
-
-
-import com.qinshou.rcvbaseadapterdemo.holder.BaseViewHolder;
-
-/**
- * Description:
- * Created by 禽兽先生
- * Created on 2018/3/8
- */
-
-public interface OnItemClickListener {
- void onItemClick(BaseViewHolder holder, T t, int position);
-}
diff --git a/app/src/main/kotlin/com/qinshou/demo/MainActivity.kt b/app/src/main/kotlin/com/qinshou/demo/MainActivity.kt
new file mode 100644
index 0000000..a2a1234
--- /dev/null
+++ b/app/src/main/kotlin/com/qinshou/demo/MainActivity.kt
@@ -0,0 +1,24 @@
+package com.qinshou.demo
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.android.synthetic.main.activity_main.*
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/15 16:02
+ * Description:
+ */
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ btn_one_to_one.setOnClickListener(View.OnClickListener { startActivity(Intent(this, OneToOneActivity::class.java)) })
+ btn_many_to_many.setOnClickListener(View.OnClickListener { startActivity(Intent(this, ManyToManyActivity::class.java)) })
+ btn_one_to_many.setOnClickListener(View.OnClickListener { startActivity(Intent(this, OneToManyActivity::class.java)) })
+ btn_special_item.setOnClickListener(View.OnClickListener { startActivity(Intent(this, SpecialItemActivity::class.java)) })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/qinshou/demo/ManyToManyActivity.kt b/app/src/main/kotlin/com/qinshou/demo/ManyToManyActivity.kt
new file mode 100644
index 0000000..d3844b4
--- /dev/null
+++ b/app/src/main/kotlin/com/qinshou/demo/ManyToManyActivity.kt
@@ -0,0 +1,55 @@
+package com.qinshou.demo
+
+import android.content.Context
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.itemview.BaseItemView
+import com.qinshou.rcv.viewholder.BaseViewHolder
+import kotlinx.android.synthetic.main.activity_many_to_many.*
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/15 16:02
+ * Description:
+ */
+class ManyToManyActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_many_to_many)
+ val rcvManyToManyAdapter = RcvManyToManyAdapter(this)
+ rcv_many_to_many.adapter = rcvManyToManyAdapter
+ val list = ArrayList()
+ for (i in 0 until 100) {
+ if (i % 2 == 0) {
+ list.add(i)
+ } else {
+ list.add("测试文字$i")
+ }
+ }
+ rcvManyToManyAdapter.dataList = list
+ }
+
+ private class RcvManyToManyAdapter(context: Context) : RcvMultipleAdapter(context) {
+ init {
+ addItemView(IntegerItemView(context, this))
+ addItemView(StringItemView(context, this))
+ }
+ }
+
+ private class IntegerItemView(context: Context, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, R.layout.item_rcv_integer, rcvBaseAdapter) {
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Int?, position: Int) {
+ holder.setTvText(R.id.text_view, "" + itemData)
+ }
+ }
+
+ private class StringItemView(context: Context, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, R.layout.item_rcv_string, rcvBaseAdapter) {
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: String?, position: Int) {
+ holder.setTvText(R.id.text_view, itemData)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/qinshou/demo/NewsBean.kt b/app/src/main/kotlin/com/qinshou/demo/NewsBean.kt
new file mode 100644
index 0000000..5635776
--- /dev/null
+++ b/app/src/main/kotlin/com/qinshou/demo/NewsBean.kt
@@ -0,0 +1,39 @@
+package com.qinshou.demo
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/16 10:59
+ * Description:类描述
+ */
+class NewsBean {
+ var id: Int? = null
+ var href: String? = null
+ var imgSmall: String? = null
+ var imgBig: String? = null
+ var titleChinese: String? = null
+ var titleEnglish: String? = null
+ var publishTime: Long? = null
+ var introduction: String? = null
+ var sourceChinese: String? = null
+ var sourceEnglish: String? = null
+ var translatorAndEditor: String? = null
+ var htmlContent: String? = null
+
+ override fun toString(): String {
+ return "NewsBean{" +
+ "id=" + id +
+ ", href='" + href + '\'' +
+ ", imgSmall='" + imgSmall + '\'' +
+ ", imgBig='" + imgBig + '\'' +
+ ", titleChinese='" + titleChinese + '\'' +
+ ", titleEnglish='" + titleEnglish + '\'' +
+ ", publishTime='" + publishTime + '\'' +
+ ", introduction='" + introduction + '\'' +
+ ", sourceChinese='" + sourceChinese + '\'' +
+ ", sourceEnglish='" + sourceEnglish + '\'' +
+ ", translatorAndEditor='" + translatorAndEditor + '\'' +
+ ", htmlContent='" + htmlContent + '\'' +
+ '}'
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/qinshou/demo/OneToManyActivity.kt b/app/src/main/kotlin/com/qinshou/demo/OneToManyActivity.kt
new file mode 100644
index 0000000..06c1dc7
--- /dev/null
+++ b/app/src/main/kotlin/com/qinshou/demo/OneToManyActivity.kt
@@ -0,0 +1,58 @@
+package com.qinshou.demo
+
+import android.content.Context
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.itemview.BaseItemView
+import com.qinshou.rcv.viewholder.BaseViewHolder
+import kotlinx.android.synthetic.main.activity_one_to_many.*
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/15 16:02
+ * Description:
+ */
+class OneToManyActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_one_to_many)
+ val rcvOneToManyAdapter = RcvOneToManyAdapter(this)
+ rcv_one_to_many.adapter = rcvOneToManyAdapter
+ val list = ArrayList()
+ for (i in 0 until 100) {
+ list.add("测试文字$i")
+ }
+ rcvOneToManyAdapter.dataList = list
+ }
+
+ private class RcvOneToManyAdapter(context: Context) : RcvMultipleAdapter(context) {
+ init {
+ addItemView(OneToManyItemView1(context, this))
+ addItemView(OneToManyItemView2(context, this))
+ }
+ }
+
+ private class OneToManyItemView1(context: Context, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, R.layout.item_rcv_one_to_many_1, rcvBaseAdapter) {
+
+ override fun isForViewType(item: Any?, position: Int): Boolean {
+ return position % 2 == 0
+ }
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: String?, position: Int) {
+ holder.setTvText(R.id.text_view, itemData)
+ }
+ }
+
+ private class OneToManyItemView2(context: Context, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, R.layout.item_rcv_one_to_many_2, rcvBaseAdapter) {
+ override fun isForViewType(item: Any?, position: Int): Boolean {
+ return position % 2 != 0
+ }
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: String?, position: Int) {
+ holder.setTvText(R.id.text_view, itemData)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/qinshou/demo/OneToOneActivity.kt b/app/src/main/kotlin/com/qinshou/demo/OneToOneActivity.kt
new file mode 100644
index 0000000..ce169a3
--- /dev/null
+++ b/app/src/main/kotlin/com/qinshou/demo/OneToOneActivity.kt
@@ -0,0 +1,35 @@
+package com.qinshou.demo
+
+import android.content.Context
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.qinshou.rcv.adapter.RcvSimpleAdapter
+import com.qinshou.rcv.viewholder.BaseViewHolder
+import kotlinx.android.synthetic.main.activity_one_to_one.*
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/15 16:02
+ * Description:
+ */
+class OneToOneActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_one_to_one)
+ val rcvOneToOneAdapter = RcvOneToOneAdapter(this)
+ rcv_one_to_one.adapter = rcvOneToOneAdapter
+ val list = ArrayList()
+ for (i in 0 until 100) {
+ list.add("测试文字$i")
+ }
+ rcvOneToOneAdapter.dataList = list
+ }
+
+ private class RcvOneToOneAdapter(context: Context) : RcvSimpleAdapter(context, R.layout.item_rcv_string) {
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: String?, position: Int) {
+ holder.setTvText(R.id.text_view, itemData)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/qinshou/demo/SpecialItemActivity.kt b/app/src/main/kotlin/com/qinshou/demo/SpecialItemActivity.kt
new file mode 100644
index 0000000..4a90b72
--- /dev/null
+++ b/app/src/main/kotlin/com/qinshou/demo/SpecialItemActivity.kt
@@ -0,0 +1,108 @@
+package com.qinshou.demo
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.itemview.*
+import com.qinshou.rcv.viewholder.BaseViewHolder
+import kotlinx.android.synthetic.main.activity_one_to_one.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/15 16:02
+ * Description:
+ */
+class SpecialItemActivity : AppCompatActivity() {
+ private val rcvNewsAdapter: RcvNewsAdapter by lazy {
+ return@lazy RcvNewsAdapter(this, this)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_one_to_one)
+ rcv_one_to_one.adapter = rcvNewsAdapter
+ }
+
+ private class RcvNewsAdapter(context: Context, specialItemActivity: SpecialItemActivity) : RcvMultipleAdapter(context) {
+
+ init {
+ // EmptyItemView,需要自定义 UI,声明成员变量再重写里面的方法,否则如果有多个匿名内部类的话,kotlin 会报错
+ val emptyItemView: EmptyItemView = object : EmptyItemView(context, R.layout.layout_empty_view_of_rcv_one_to_one, this) {
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ super.bindViewHolder(holder, itemData, position)
+ holder.setOnClickListener(R.id.btn_refresh, View.OnClickListener {
+ // 刷新数据,具体怎么发送请求,可以根据自己情况来,可以传一个 v 层或 p 层的实例进来,也
+ // 可以通过 Handler 发送消息通知
+ specialItemActivity.refresh()
+ })
+ }
+ }
+ addItemView(emptyItemView)
+ // 骨架屏 item
+ addItemView(SkeletonItemView(context, R.layout.item_rcv_news, this))
+ // HeaderItemView
+ addItemView(HeaderItemView(context, R.layout.layout_header_view_of_rcv_one_to_one, this))
+ // HeaderItemView,需要自定义 UI,声明成员变量再重写里面的方法,否则如果有多个匿名内部类的话,kotlin 会报错
+ val headerItemView2: HeaderItemView = object : HeaderItemView(context, R.layout.layout_header_view_of_rcv_one_to_one, this) {
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ super.bindViewHolder(holder, itemData, position)
+ holder.setTvText(R.id.text_view, "Header View 2")
+ }
+ }
+ addItemView(headerItemView2)
+ // FooterItemView
+ addItemView(FooterItemView(context, R.layout.layout_footer_view_of_rcv_one_to_one, this))
+ // FooterItemView,需要自定义 UI,声明成员变量再重写里面的方法,否则如果有多个匿名内部类的话,kotlin 会报错
+ val footerItemView2: FooterItemView = object : FooterItemView(context, R.layout.layout_footer_view_of_rcv_one_to_one, this) {
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ super.bindViewHolder(holder, itemData, position)
+ holder.setTvText(R.id.text_view, "Footer View 2")
+ }
+ }
+ addItemView(footerItemView2)
+ // 真正要显示的数据
+ addItemView(NewsItemView(context, this))
+ }
+ }
+
+ private class NewsItemView(context: Context, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, R.layout.item_rcv_news, rcvBaseAdapter) {
+ private val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA)
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: NewsBean?, position: Int) {
+ holder.setTvText(R.id.tv_title, itemData?.titleChinese)
+ holder.setTvText(R.id.tv_source, "作者:" + itemData?.sourceChinese)
+ holder.setTvText(R.id.tv_translator, "翻译者:" + itemData?.translatorAndEditor)
+ if (itemData?.publishTime != null) {
+ holder.setTvText(R.id.tv_time, "翻译者:" + simpleDateFormat.format(Date(itemData.publishTime!!)))
+ }
+ }
+ }
+
+ private fun refresh() {
+ GlobalScope.launch(Dispatchers.Main) {
+ rcvNewsAdapter.skeletonItemViewCount = 10
+ delay(3000)
+ val list = ArrayList()
+ for (i in 0 until 100) {
+ val newsBean = NewsBean()
+ newsBean.titleChinese = "测试标题测试标题测试标题测试标题"
+ newsBean.sourceChinese = "测试来源"
+ newsBean.translatorAndEditor = "测试翻译者"
+ newsBean.publishTime = System.currentTimeMillis()
+ list.add(newsBean)
+ }
+ rcvNewsAdapter.skeletonItemViewCount = 0
+ rcvNewsAdapter.dataList = list
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity/layout/activity_main.xml b/app/src/main/res/layout/activity/layout/activity_main.xml
new file mode 100644
index 0000000..3c910da
--- /dev/null
+++ b/app/src/main/res/layout/activity/layout/activity_main.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity/layout/activity_many_to_many.xml b/app/src/main/res/layout/activity/layout/activity_many_to_many.xml
new file mode 100644
index 0000000..7f54447
--- /dev/null
+++ b/app/src/main/res/layout/activity/layout/activity_many_to_many.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity/layout/activity_one_to_many.xml b/app/src/main/res/layout/activity/layout/activity_one_to_many.xml
new file mode 100644
index 0000000..502a3a4
--- /dev/null
+++ b/app/src/main/res/layout/activity/layout/activity_one_to_many.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity/layout/activity_one_to_one.xml b/app/src/main/res/layout/activity/layout/activity_one_to_one.xml
new file mode 100644
index 0000000..e2ec992
--- /dev/null
+++ b/app/src/main/res/layout/activity/layout/activity_one_to_one.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 564c2bf..0000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/include/layout/layout_empty_view_of_rcv_one_to_one.xml b/app/src/main/res/layout/include/layout/layout_empty_view_of_rcv_one_to_one.xml
new file mode 100644
index 0000000..bfbd8a7
--- /dev/null
+++ b/app/src/main/res/layout/include/layout/layout_empty_view_of_rcv_one_to_one.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/include/layout/layout_footer_view_of_rcv_one_to_one.xml b/app/src/main/res/layout/include/layout/layout_footer_view_of_rcv_one_to_one.xml
new file mode 100644
index 0000000..d1eff07
--- /dev/null
+++ b/app/src/main/res/layout/include/layout/layout_footer_view_of_rcv_one_to_one.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/include/layout/layout_header_view_of_rcv_one_to_one.xml b/app/src/main/res/layout/include/layout/layout_header_view_of_rcv_one_to_one.xml
new file mode 100644
index 0000000..64afd83
--- /dev/null
+++ b/app/src/main/res/layout/include/layout/layout_header_view_of_rcv_one_to_one.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_rv_test.xml b/app/src/main/res/layout/item/layout/item_rcv_integer.xml
similarity index 81%
rename from app/src/main/res/layout/item_rv_test.xml
rename to app/src/main/res/layout/item/layout/item_rcv_integer.xml
index 339b928..90cc7d8 100644
--- a/app/src/main/res/layout/item_rv_test.xml
+++ b/app/src/main/res/layout/item/layout/item_rcv_integer.xml
@@ -2,15 +2,14 @@
diff --git a/app/src/main/res/layout/item/layout/item_rcv_news.xml b/app/src/main/res/layout/item/layout/item_rcv_news.xml
new file mode 100644
index 0000000..5b4beb3
--- /dev/null
+++ b/app/src/main/res/layout/item/layout/item_rcv_news.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_rv_test_message1.xml b/app/src/main/res/layout/item/layout/item_rcv_one_to_many_1.xml
similarity index 86%
rename from app/src/main/res/layout/item_rv_test_message1.xml
rename to app/src/main/res/layout/item/layout/item_rcv_one_to_many_1.xml
index 432d49e..43da026 100644
--- a/app/src/main/res/layout/item_rv_test_message1.xml
+++ b/app/src/main/res/layout/item/layout/item_rcv_one_to_many_1.xml
@@ -2,12 +2,11 @@
-
-
-
-
diff --git a/build.gradle b/build.gradle
index eccff49..d9381c0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,13 +2,17 @@
buildscript {
+ ext {
+ kotlin_version = '1.4.32'
+ }
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.1'
-
+ classpath 'com.android.tools.build:gradle:4.1.1'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle.properties b/gradle.properties
index 743d692..c73d239 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -11,3 +11,9 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e61048c..886327b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Oct 09 20:49:32 CST 2018
+#Thu Apr 15 15:52:45 CST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
diff --git a/rcvbaseadapter/.gitignore b/rcvbaseadapter/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/rcvbaseadapter/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/rcvbaseadapter/build.gradle b/rcvbaseadapter/build.gradle
new file mode 100644
index 0000000..a77ca33
--- /dev/null
+++ b/rcvbaseadapter/build.gradle
@@ -0,0 +1,51 @@
+plugins {
+ id 'com.android.library'
+ id 'kotlin-android'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+ // 资源目录
+ sourceSets {
+ main {
+ java.srcDirs('src/main/java'
+ , 'src/main/kotlin')
+ }
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ testImplementation 'junit:junit:4.+'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+ implementation 'com.google.android.material:material:1.3.0'
+ // Kotlin
+ api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/consumer-rules.pro b/rcvbaseadapter/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/rcvbaseadapter/proguard-rules.pro b/rcvbaseadapter/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/rcvbaseadapter/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/rcvbaseadapter/src/androidTest/java/com/qinshou/rcv/ExampleInstrumentedTest.kt b/rcvbaseadapter/src/androidTest/java/com/qinshou/rcv/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..b5a2635
--- /dev/null
+++ b/rcvbaseadapter/src/androidTest/java/com/qinshou/rcv/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.qinshou.rcv
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.runner.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.qinshou.rcvbaseadapter.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/AndroidManifest.xml b/rcvbaseadapter/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4e036cb
--- /dev/null
+++ b/rcvbaseadapter/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvBaseAdapter.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvBaseAdapter.kt
new file mode 100644
index 0000000..6912215
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvBaseAdapter.kt
@@ -0,0 +1,110 @@
+package com.qinshou.rcv.adapter
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.OnLongClickListener
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.qinshou.rcv.listener.OnItemClickListener
+import com.qinshou.rcv.listener.OnItemLongClickListener
+import com.qinshou.rcv.viewholder.BaseViewHolder
+import java.util.*
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/14 11:14
+ * Description:The base adapter of RecyclerView.If datum are the same type,please use
+ * {@link RcvSimpleAdapter}.If datum are different type or datum are the same type but want to use
+ * different layout,please use {@link RcvMultipleAdapter}.
+ */
+abstract class RcvBaseAdapter(val context: Context, private val layoutId: Int) : RecyclerView.Adapter() {
+ /**
+ * Collection to save data
+ */
+ var dataList: MutableList? = ArrayList()
+ set(value) {
+ if (value == null) {
+ field = ArrayList()
+ } else {
+ field = value
+ }
+ notifyDataSetChanged()
+ }
+
+ /**
+ * The Listener of item click
+ */
+ protected val onItemClickListener: OnItemClickListener? = null
+
+ /**
+ * The Listener of item long click
+ */
+ protected val onItemLongClickListener: OnItemLongClickListener? = null
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:36
+ * Description:Do bind UI operate,children only needs to implement this method for complete the
+ * adapter's tedious operate.
+ */
+ abstract fun bindViewHolder(holder: BaseViewHolder, itemData: T?, position: Int)
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
+ return BaseViewHolder(context, LayoutInflater.from(context).inflate(layoutId, parent, false))
+ }
+
+ override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
+// if (dataList == null) {
+// return
+// }
+// if (dataList?.size == 0) {
+// return
+// }
+ if (onItemClickListener != null) {
+ holder.itemView.setOnClickListener(View.OnClickListener {
+ onItemClickListener.onClick(holder, dataList?.get(position), position)
+ })
+ }
+ if (onItemLongClickListener != null) {
+ holder.itemView.setOnLongClickListener(OnLongClickListener {
+ onItemLongClickListener.onLongClick(holder, dataList?.get(position), position)
+ true
+ })
+ }
+ bindViewHolder(holder, dataList?.get(position), position)
+ }
+
+ override fun getItemCount(): Int {
+ return if (dataList == null) 0 else dataList!!.size
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return super.getItemViewType(position)
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:39
+ * Description:Add datum to collection.
+ * @param dataList The datum you want to add.
+ * @param isRefresh If true adapter will refresh all,false only refresh the added section
+ */
+ fun addDataList(dataList: List?, isRefresh: Boolean = false) {
+ if (dataList == null || dataList.isEmpty()) {
+ return
+ }
+ if (isRefresh) {
+ this.dataList?.clear()
+ }
+ this.dataList?.addAll(dataList)
+ if (isRefresh) {
+ notifyDataSetChanged()
+ } else {
+ notifyItemRangeInserted(this.dataList!!.size - dataList.size, this.dataList!!.size)
+ }
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvMultipleAdapter.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvMultipleAdapter.kt
new file mode 100644
index 0000000..165ee52
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvMultipleAdapter.kt
@@ -0,0 +1,249 @@
+package com.qinshou.rcv.adapter
+
+import android.content.Context
+import android.util.Log
+import android.util.SparseArray
+import android.view.View
+import android.view.ViewGroup
+import com.qinshou.rcv.itemview.*
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/14 13:38
+ * Description:The multiple implement of RcvBaseAdapter,used for one-to-many or many-to-many.
+ * It's only a manager of item view,The actual bind UI operate is done by the implementation
+ * of item view.
+ */
+open class RcvMultipleAdapter(context: Context) : RcvBaseAdapter(context, 0) {
+ /**
+ * Use SparseArray to save item view
+ */
+ internal val itemViewSparseArray = SparseArray>()
+ var skeletonItemViewCount = 0
+ set(value) {
+ field = value
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
+ return itemViewSparseArray.get(viewType).onCreateViewHolder(parent)
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:45
+ * Description:Override this method because the adapter conclude header and footer,must recalculate
+ * the position of data.
+ */
+ override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
+// if (dataList == null) {
+// return
+// }
+// if (dataList?.size == 0) {
+// return
+// }
+ val itemData = getItemData(position)
+ if (onItemClickListener != null) {
+ holder.itemView.setOnClickListener(View.OnClickListener {
+ onItemClickListener.onClick(holder, itemData, position)
+ })
+ }
+ if (onItemLongClickListener != null) {
+ holder.itemView.setOnLongClickListener(View.OnLongClickListener {
+ onItemLongClickListener.onLongClick(holder, itemData, position)
+ true
+ })
+ }
+ bindViewHolder(holder, itemData, position)
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ for (i in 0 until itemViewSparseArray.size()) {
+ val baseItemView: BaseItemView<*> = itemViewSparseArray.valueAt(i)
+ // 显示空布局
+ if (showEmptyItemView()) {
+ return if (baseItemView is EmptyItemView && baseItemView.isForViewType(null, position)) {
+ itemViewSparseArray.keyAt(i)
+ } else {
+ continue
+ }
+ }
+ if (showSkeletonItemView()) {
+ return if (baseItemView is SkeletonItemView && baseItemView.isForViewType(null, position)) {
+ itemViewSparseArray.keyAt(i)
+ } else {
+ continue
+ }
+ }
+ // 如果头布局数量大于 1,则判断该 position 是否是头布局
+ val headerItemViewCount = getHeaderItemViewCount()
+ if (position < headerItemViewCount) {
+ return if (baseItemView is HeaderItemView && baseItemView.isForViewType(null, position)) {
+ itemViewSparseArray.keyAt(i)
+ } else {
+ continue
+ }
+ }
+ // 如果脚布局数量大于 1,则判断该 position 是否是脚布局
+ if (position >= dataList!!.size + headerItemViewCount) {
+ return if (baseItemView is FooterItemView && baseItemView.isForViewType(null, position)) {
+ itemViewSparseArray.keyAt(i)
+ } else {
+ continue
+ }
+ }
+ // 正常布局
+ if (baseItemView.isForViewType(dataList?.get(position - headerItemViewCount), position)) {
+ return itemViewSparseArray.keyAt(i)
+ }
+ }
+ throw IllegalArgumentException("No ItemView added that matches position=$position in data source")
+ }
+
+ override fun getItemCount(): Int {
+ if (showSkeletonItemView()) {
+ return skeletonItemViewCount
+ }
+ // 如果需要显示空布局,则返回固定数量 1
+ if (showEmptyItemView()) {
+ return 1
+ }
+ // 要加上头布局和脚布局数量
+ return super.getItemCount() + getHeaderItemViewCount() + getFooterItemViewCount()
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:47
+ * Description:Iterate through the collection of BaseItemView and delegate the binding UI operate to
+ * corresponding item view
+ */
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ for (i in 0 until itemViewSparseArray.size()) {
+ val baseItemView: BaseItemView = itemViewSparseArray.valueAt(i) as BaseItemView
+ if (baseItemView.isForViewType(itemData, position)) {
+ baseItemView.bindViewHolder(holder, itemData, position)
+ break
+ }
+ }
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:50
+ * Description:Return true When the size of collection of data equal 0
+ * and added empty view.
+ * @return true if is's time to show empty view.
+ */
+ private fun showEmptyItemView(): Boolean {
+ if (dataList != null && dataList!!.size > 0) {
+ return false
+ }
+ if (skeletonItemViewCount > 0) {
+ return false
+ }
+ for (i in 0 until itemViewSparseArray.size()) {
+ if (itemViewSparseArray.valueAt(i) is EmptyItemView) {
+ return true
+ }
+ }
+ return false
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/15 10:31
+ * Description:Return true When the size of collection of data equal 0
+ * and added skeleton view and skeletonItemViewCount greater than 0.
+ * @return true if is's time to show empty view.
+ */
+ private fun showSkeletonItemView(): Boolean {
+ if (dataList != null && dataList!!.size > 0) {
+ return false
+ }
+ if (skeletonItemViewCount <= 0) {
+ return false
+ }
+ for (i in 0 until itemViewSparseArray.size()) {
+ if (itemViewSparseArray.valueAt(i) is SkeletonItemView) {
+ return true
+ }
+ }
+ return false
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:50
+ * Description:Iterate the collection of BaseItemView to get the count of header views.
+ * @return The count of header views.
+ */
+ private fun getHeaderItemViewCount(): Int {
+ var headerItemViewCount = 0
+ for (i in 0 until itemViewSparseArray.size()) {
+ if (itemViewSparseArray.valueAt(i) is HeaderItemView) {
+ headerItemViewCount++
+ }
+ }
+ return headerItemViewCount
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:50
+ * Description:Iterate the collection of BaseItemView to get the count of footer views.
+ * @return The count of footer views.
+ */
+ private fun getFooterItemViewCount(): Int {
+ var footerItemViewCount = 0
+ for (i in 0 until itemViewSparseArray.size()) {
+ if (itemViewSparseArray.valueAt(i) is FooterItemView) {
+ footerItemViewCount++
+ }
+ }
+ return footerItemViewCount
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 17:50
+ * Description:Use position minus the count of header views to get the corresponding data.
+ * @return The corresponding data.
+ */
+ private fun getItemData(position: Int): Any? {
+ if (dataList == null) {
+ return null
+ }
+ val headerItemViewCount = getHeaderItemViewCount()
+// val footerItemViewCount: Int = getFooterItemViewCount()
+ // 头布局
+ if (position < headerItemViewCount) {
+ return null
+ }
+ // 脚布局
+ if (position >= dataList!!.size + headerItemViewCount) {
+ return null
+ }
+ return dataList!![position - headerItemViewCount]
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:00
+ * Description:Add itemView
+ */
+ fun addItemView(baseItemView: BaseItemView<*>) {
+ // index 只是为了设置不同的 ViewType,所以自增即可
+ itemViewSparseArray.put(itemViewSparseArray.size(), baseItemView)
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvSimpleAdapter.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvSimpleAdapter.kt
new file mode 100644
index 0000000..70c0db4
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/adapter/RcvSimpleAdapter.kt
@@ -0,0 +1,12 @@
+package com.qinshou.rcv.adapter
+
+import android.content.Context
+
+/**
+ * Author: QinHao
+ * Email:qinhao@jeejio.com
+ * Date: 2021/4/14 13:29
+ * Description:The simple implement of RcvBaseAdapter,used for one-to-one.
+ */
+abstract class RcvSimpleAdapter(context: Context, layoutId: Int) : RcvBaseAdapter(context, layoutId) {
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/BaseItemView.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/BaseItemView.kt
new file mode 100644
index 0000000..7b4ad5c
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/BaseItemView.kt
@@ -0,0 +1,39 @@
+package com.qinshou.rcv.itemview
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.viewholder.BaseViewHolder
+import java.lang.reflect.ParameterizedType
+import java.lang.reflect.Type
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 13:47
+ * Description:The basic of item view,if want to ono-to-many or many-to-many layout,you may use it.
+ */
+abstract class BaseItemView(val context: Context, private val layoutId: Int, val rcvBaseAdapter: RcvBaseAdapter) {
+
+ abstract fun bindViewHolder(holder: BaseViewHolder, itemData: T?, position: Int)
+
+ fun onCreateViewHolder(parent: ViewGroup?): BaseViewHolder {
+ return BaseViewHolder(context, LayoutInflater.from(context).inflate(layoutId, parent, false))
+ }
+
+ open fun isForViewType(item: Any?, position: Int): Boolean {
+ if (item == null) {
+ return false
+ }
+ val genericSuperclass = javaClass.genericSuperclass
+ if (genericSuperclass !is ParameterizedType) {
+ return false
+ }
+ if (genericSuperclass.actualTypeArguments.isEmpty()) {
+ return false
+ }
+ val type: Type = genericSuperclass.actualTypeArguments[0]
+ return item::class.java == type
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/EmptyItemView.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/EmptyItemView.kt
new file mode 100644
index 0000000..e934b8c
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/EmptyItemView.kt
@@ -0,0 +1,26 @@
+package com.qinshou.rcv.itemview
+
+import android.content.Context
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 15:09
+ * Description:The item view used to quickly implement empty layout.
+ */
+open class EmptyItemView(context: Context, layoutId: Int, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, layoutId, rcvBaseAdapter) {
+ override fun isForViewType(item: Any?, position: Int): Boolean {
+ // return true when the size of the collection of data equal 0 and skeletonItemViewCount
+ // less than or equal to 0.
+ return (rcvBaseAdapter.dataList == null || rcvBaseAdapter.dataList?.size == 0)
+ && rcvBaseAdapter is RcvMultipleAdapter
+ && rcvBaseAdapter.skeletonItemViewCount <= 0
+ }
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/FooterItemView.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/FooterItemView.kt
new file mode 100644
index 0000000..45f5da3
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/FooterItemView.kt
@@ -0,0 +1,38 @@
+package com.qinshou.rcv.itemview
+
+import android.content.Context
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 15:33
+ * Description:The item view used to quickly implement footer layout.
+ */
+open class FooterItemView(context: Context, layoutId: Int, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, layoutId, rcvBaseAdapter) {
+ override fun isForViewType(item: Any?, position: Int): Boolean {
+ val list = ArrayList()
+ // record the count of header view.
+ var headerViewCount = 0
+ // calculate the count of footer view.
+ for (i in 0 until (rcvBaseAdapter as RcvMultipleAdapter).itemViewSparseArray.size()) {
+ if (rcvBaseAdapter.itemViewSparseArray.valueAt(i) is FooterItemView) {
+ list.add(rcvBaseAdapter.itemViewSparseArray.valueAt(i) as FooterItemView)
+ }
+ if (rcvBaseAdapter.itemViewSparseArray.valueAt(i) is HeaderItemView) {
+ headerViewCount++
+ }
+ }
+ // return false when position is not the bottom.
+ if (position < rcvBaseAdapter.dataList!!.size + headerViewCount) {
+ return false
+ }
+ // 判断当前 FooterView 是不是集合中按照添加顺序对应的那一个
+ return this == list[position - (rcvBaseAdapter.dataList!!.size + headerViewCount)]
+ }
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/HeaderItemView.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/HeaderItemView.kt
new file mode 100644
index 0000000..6ce0610
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/HeaderItemView.kt
@@ -0,0 +1,33 @@
+package com.qinshou.rcv.itemview
+
+import android.content.Context
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 15:33
+ * Description:The item view used to quickly implement header layout.
+ */
+open class HeaderItemView(context: Context, layoutId: Int, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, layoutId, rcvBaseAdapter) {
+ override fun isForViewType(item: Any?, position: Int): Boolean {
+ val list = ArrayList()
+ // calculate the count of header view.
+ for (i in 0 until (rcvBaseAdapter as RcvMultipleAdapter).itemViewSparseArray.size()) {
+ if (rcvBaseAdapter.itemViewSparseArray.valueAt(i) is HeaderItemView) {
+ list.add(rcvBaseAdapter.itemViewSparseArray.valueAt(i) as HeaderItemView)
+ }
+ }
+ // return false when position is not the top.
+ if (position >= list.size) {
+ return false
+ }
+ // 判断当前 HeaderView 是不是集合中按照添加顺序对应的那一个
+ return this == list[position]
+ }
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/SkeletonItemView.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/SkeletonItemView.kt
new file mode 100644
index 0000000..d82e42c
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/itemview/SkeletonItemView.kt
@@ -0,0 +1,49 @@
+package com.qinshou.rcv.itemview
+
+import android.content.Context
+import android.graphics.Color
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import com.qinshou.rcv.adapter.RcvBaseAdapter
+import com.qinshou.rcv.adapter.RcvMultipleAdapter
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/15 9:03
+ * Description:The item view used to quickly implement skeleton layout.
+ * It will iterate child view and set its background When bind UI.
+ * If the default UI effect doesn't statisfied your needs,you can override bindViewHolder method
+ * to implement your custom UI.
+ */
+open class SkeletonItemView(context: Context, layoutId: Int, rcvBaseAdapter: RcvBaseAdapter) : BaseItemView(context, layoutId, rcvBaseAdapter) {
+ override fun isForViewType(item: Any?, position: Int): Boolean {
+ // return true when the size of the collection of data equal 0 and skeletonItemViewCount
+ // greater than 0.
+ return (rcvBaseAdapter.dataList == null || rcvBaseAdapter.dataList?.size == 0)
+ && rcvBaseAdapter is RcvMultipleAdapter
+ && rcvBaseAdapter.skeletonItemViewCount > 0
+ }
+
+ override fun bindViewHolder(holder: BaseViewHolder, itemData: Any?, position: Int) {
+ setSkeleton(holder.itemView)
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/15 9:53
+ * Description:Iterate child view,if the view is ViewGroup,it will recursion call this method.
+ */
+ fun setSkeleton(view: View) {
+ if (view is ViewGroup) {
+ for (i in 0 until view.childCount) {
+ setSkeleton(view.getChildAt(i))
+ }
+ } else {
+ view.setBackgroundColor(Color.GRAY)
+ }
+ }
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/listener/OnItemClickListener.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/listener/OnItemClickListener.kt
new file mode 100644
index 0000000..1033fc1
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/listener/OnItemClickListener.kt
@@ -0,0 +1,14 @@
+package com.qinshou.rcv.listener
+
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 11:17
+ * Description:The listener of item click.
+ */
+interface OnItemClickListener {
+ fun onClick(holder: BaseViewHolder?, itemData: T?, position: Int)
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/listener/OnItemLongClickListener.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/listener/OnItemLongClickListener.kt
new file mode 100644
index 0000000..5927172
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/listener/OnItemLongClickListener.kt
@@ -0,0 +1,14 @@
+package com.qinshou.rcv.listener
+
+import com.qinshou.rcv.viewholder.BaseViewHolder
+
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 11:18
+ * Description:The listener of item long click.
+ */
+interface OnItemLongClickListener {
+ fun onLongClick(holder: BaseViewHolder?, itemData: T?, position: Int)
+}
\ No newline at end of file
diff --git a/rcvbaseadapter/src/main/java/com/qinshou/rcv/viewholder/BaseViewHolder.kt b/rcvbaseadapter/src/main/java/com/qinshou/rcv/viewholder/BaseViewHolder.kt
new file mode 100644
index 0000000..605b6f7
--- /dev/null
+++ b/rcvbaseadapter/src/main/java/com/qinshou/rcv/viewholder/BaseViewHolder.kt
@@ -0,0 +1,214 @@
+package com.qinshou.rcv.viewholder
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
+import android.util.SparseArray
+import android.view.View
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date: 2021/4/14 10:37
+ * Description:The basic of view holder,developers no longer need to care about the implementation
+ * of the ViewHolder
+ */
+class BaseViewHolder(val context: Context, view: View) : RecyclerView.ViewHolder(view) {
+ private val viewSparseArray: SparseArray = SparseArray()
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Return a view by id.
+ */
+ fun findViewById(viewId: Int): T? {
+ var view: View? = viewSparseArray.get(viewId)
+ if (view == null) {
+ view = itemView.findViewById(viewId)
+ viewSparseArray.put(viewId, view)
+ }
+ return view as T
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Return a text view by id.
+ */
+ fun getTextView(textViewId: Int): TextView? {
+ var textView: TextView? = viewSparseArray.get(textViewId) as TextView
+ if (textView == null) {
+ textView = itemView.findViewById(textViewId)
+ viewSparseArray.put(textViewId, textView)
+ }
+ return textView
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Return a image view by id.
+ */
+ fun getImageView(imageViewId: Int): ImageView? {
+ var imageView: ImageView? = viewSparseArray.get(imageViewId) as ImageView
+ if (imageView == null) {
+ imageView = itemView.findViewById(imageViewId)
+ viewSparseArray.put(imageViewId, imageView)
+ }
+ return imageView
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Set the visibility of view.
+ */
+ fun setVisibility(viewId: Int, visibility: Int): BaseViewHolder {
+ val view = findViewById(viewId)
+ if (view != null) {
+ view.visibility = visibility
+ }
+ return this
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Set the text of text view.
+ */
+ fun setTvText(viewId: Int, text: CharSequence?): BaseViewHolder {
+ val textView = findViewById(viewId)
+ if (textView != null) {
+ textView.text = text
+ }
+ return this
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Set the text of text view.
+ */
+ fun setTvText(viewId: Int, @StringRes resId: Int): BaseViewHolder {
+ findViewById(viewId)?.text = context.resources.getString(resId)
+ return this
+ }
+
+ /**
+ * Author: MrQinshou
+ * Email:cqflqinhao@126.com
+ * Date:2021/4/14 18:13
+ * Description:Set the text of button.
+ */
+ fun setBtnText(viewId: Int, text: CharSequence?): BaseViewHolder {
+ val button = findViewById