0ce4ee5eef23abd4b09ab05752d6e406aab5131b.svn-base 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. package com.hjq.base;
  2. import android.content.Context;
  3. import android.content.res.Resources;
  4. import android.graphics.drawable.Drawable;
  5. import android.os.Build;
  6. import android.support.annotation.ColorRes;
  7. import android.support.annotation.DrawableRes;
  8. import android.support.annotation.IdRes;
  9. import android.support.annotation.NonNull;
  10. import android.support.annotation.Nullable;
  11. import android.support.annotation.StringRes;
  12. import android.support.v7.widget.LinearLayoutManager;
  13. import android.support.v7.widget.RecyclerView;
  14. import android.util.SparseArray;
  15. import android.view.LayoutInflater;
  16. import android.view.View;
  17. import android.view.ViewGroup;
  18. import java.lang.ref.WeakReference;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. /**
  22. * desc : RecyclerView 适配器基类
  23. */
  24. public abstract class BaseRecyclerViewAdapter
  25. <T, VH extends BaseRecyclerViewAdapter.ViewHolder>
  26. extends RecyclerView.Adapter<VH> {
  27. // 列表数据
  28. private List<T> mDataSet;
  29. // RecyclerView 对象
  30. private RecyclerView mRecyclerView;
  31. // 上下文对象,注意不要在构造函数中使用
  32. private Context mContext;
  33. // 条目点击事件
  34. private OnItemClickListener mItemClickListener;
  35. // 条目长按事件
  36. private OnItemLongClickListener mItemLongClickListener;
  37. // RecyclerView 滚动事件
  38. private OnScrollingListener mScrollingListener;
  39. // 条目子 View 点击事件
  40. private SparseArray<OnChildClickListener> mChildClickListeners;
  41. // 条目子 View 长按事件
  42. private SparseArray<OnChildLongClickListener> mChildLongClickListeners;
  43. public BaseRecyclerViewAdapter(Context context) {
  44. mContext = context;
  45. }
  46. @Override
  47. public int getItemCount() {
  48. return mDataSet == null ? 0 : mDataSet.size();
  49. }
  50. @Override
  51. public long getItemId(int position) {
  52. return position;
  53. }
  54. /**
  55. * 设置新的数据
  56. */
  57. public void setData(List<T> data) {
  58. mDataSet = data;
  59. notifyDataSetChanged();
  60. }
  61. /**
  62. * 获取当前数据
  63. */
  64. @Nullable
  65. public List<T> getData() {
  66. return mDataSet;
  67. }
  68. /**
  69. * 追加一些数据
  70. */
  71. public void addData(List<T> data) {
  72. if (data == null || data.size() == 0) return;
  73. if (mDataSet == null || mDataSet.size() == 0) {
  74. setData(data);
  75. }else {
  76. mDataSet.addAll(data);
  77. notifyItemRangeInserted(mDataSet.size() - data.size(), data.size());
  78. }
  79. }
  80. /**
  81. * 清空当前数据
  82. */
  83. public void clearData() {
  84. if (mDataSet == null || mDataSet.size() == 0) return;
  85. mDataSet.clear();
  86. notifyDataSetChanged();
  87. }
  88. /**
  89. * 获取某个位置上的数据
  90. */
  91. public T getItem(int position) {
  92. return mDataSet.get(position);
  93. }
  94. /**
  95. * 更新某个位置上的数据
  96. */
  97. public void setItem(int position, T item) {
  98. if (mDataSet == null) mDataSet = new ArrayList<>();
  99. mDataSet.set(position, item);
  100. notifyItemChanged(position);
  101. }
  102. /**
  103. * 添加单条数据
  104. */
  105. public void addItem(T item) {
  106. if (mDataSet == null) mDataSet = new ArrayList<>();
  107. addItem(mDataSet.size(), item);
  108. }
  109. public void addItem(int position, T item) {
  110. if (mDataSet == null) mDataSet = new ArrayList<>();
  111. if (position < mDataSet.size()) {
  112. mDataSet.add(position, item);
  113. } else {
  114. mDataSet.add(item);
  115. position = mDataSet.size() - 1;
  116. }
  117. notifyItemInserted(position);
  118. }
  119. /**
  120. * 删除单条数据
  121. */
  122. public void removeItem(T item) {
  123. int index = mDataSet.indexOf(item);
  124. if (index != -1) {
  125. removeItem(index);
  126. }
  127. }
  128. public void removeItem(int position) {
  129. //如果是在for循环删除后要记得i--
  130. mDataSet.remove(position);
  131. //告诉适配器删除数据的位置,会有动画效果
  132. notifyItemRemoved(position);
  133. }
  134. /**
  135. * 获取RecyclerView对象,需要在setAdapter之后绑定
  136. */
  137. public RecyclerView getRecyclerView() {
  138. return mRecyclerView;
  139. }
  140. /**
  141. * 获取上下文对象,注意不要在构造方法中调用
  142. */
  143. public Context getContext() {
  144. return mContext;
  145. }
  146. /**
  147. * 获取资源对象
  148. */
  149. protected Resources getResources() {
  150. return mContext.getResources();
  151. }
  152. /**
  153. * 获取资源文本
  154. */
  155. public String getString(@StringRes int resId) {
  156. return mContext.getString(resId);
  157. }
  158. /**
  159. * 获取资源颜色
  160. */
  161. protected int getColor(@ColorRes int id) {
  162. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  163. return mContext.getColor(id);
  164. }else {
  165. return mContext.getResources().getColor(id);
  166. }
  167. }
  168. /**
  169. * 获取资源图像
  170. */
  171. protected Drawable getDrawable(@DrawableRes int id) {
  172. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  173. return mContext.getDrawable(id);
  174. }else {
  175. return mContext.getResources().getDrawable(id);
  176. }
  177. }
  178. /**
  179. * 条目ViewHolder,需要子类ViewHolder继承
  180. */
  181. public class ViewHolder extends RecyclerView.ViewHolder
  182. implements View.OnClickListener, View.OnLongClickListener {
  183. // 内存优化和防止泄露
  184. private SparseArray<WeakReference<View>> mViews = new SparseArray<>();
  185. public ViewHolder(ViewGroup parent, int layoutId) {
  186. this(LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false));
  187. }
  188. public ViewHolder(View itemView) {
  189. super(itemView);
  190. initViewListener();
  191. }
  192. /**
  193. * 初始化 View 的监听
  194. */
  195. private void initViewListener() {
  196. // 设置条目的点击和长按事件
  197. if (mItemClickListener != null) {
  198. getItemView().setOnClickListener(this);
  199. }
  200. if (mItemLongClickListener != null) {
  201. getItemView().setOnLongClickListener(this);
  202. }
  203. // 设置条目子 View 点击和长按事件
  204. if (mChildClickListeners != null) {
  205. for (int i = 0; i < mChildClickListeners.size(); i++) {
  206. View childView = findViewById(mChildClickListeners.keyAt(i));
  207. if (childView != null) {
  208. childView.setOnClickListener(this);
  209. }
  210. }
  211. }
  212. if (mChildLongClickListeners != null) {
  213. for (int i = 0; i < mChildLongClickListeners.size(); i++) {
  214. View childView = findViewById(mChildLongClickListeners.keyAt(i));
  215. if (childView != null) {
  216. childView.setOnLongClickListener(this);
  217. }
  218. }
  219. }
  220. }
  221. /**
  222. * {@link View.OnClickListener}
  223. */
  224. @Override
  225. public void onClick(View v) {
  226. if (v == getItemView()) {
  227. if(mItemClickListener != null) {
  228. mItemClickListener.onItemClick(mRecyclerView, v, getLayoutPosition());
  229. return;
  230. }
  231. }
  232. if (mChildClickListeners != null) {
  233. OnChildClickListener childClickListener = mChildClickListeners.get(v.getId());
  234. if (childClickListener != null) {
  235. childClickListener.onChildClick(mRecyclerView, v, getLayoutPosition());
  236. }
  237. }
  238. }
  239. /**
  240. * {@link View.OnLongClickListener}
  241. */
  242. @Override
  243. public boolean onLongClick(View v) {
  244. if (v == getItemView()) {
  245. if (mItemLongClickListener != null) {
  246. return mItemLongClickListener.onItemLongClick(mRecyclerView, v, getLayoutPosition());
  247. }
  248. }
  249. if (mChildLongClickListeners != null) {
  250. OnChildLongClickListener childClickLongListener = mChildLongClickListeners.get(v.getId());
  251. if (childClickLongListener != null) {
  252. childClickLongListener.onChildLongClick(mRecyclerView, v, getLayoutPosition());
  253. }
  254. }
  255. return false;
  256. }
  257. public final View getItemView() {
  258. return itemView;
  259. }
  260. @SuppressWarnings("unchecked")
  261. public final <V extends View> V findViewById(@IdRes int viewId) {
  262. WeakReference<View> reference = mViews.get(viewId);
  263. if (reference != null && reference.get() != null) {
  264. return (V) reference.get();
  265. }else {
  266. View view = getItemView().findViewById(viewId);
  267. mViews.put(viewId, new WeakReference<>(view));
  268. return (V) view;
  269. }
  270. }
  271. }
  272. @Override
  273. public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
  274. mRecyclerView = recyclerView;
  275. //用户设置了滚动监听,需要给RecyclerView设置监听
  276. if (mScrollListener != null) {
  277. //添加滚动监听
  278. mRecyclerView.addOnScrollListener(mScrollListener);
  279. }
  280. //判断当前的布局管理器是否为空,如果为空则设置默认的布局管理器
  281. if (mRecyclerView.getLayoutManager() == null) {
  282. RecyclerView.LayoutManager manager = getDefaultLayoutManager(mContext);
  283. if (manager != null) {
  284. mRecyclerView.setLayoutManager(manager);
  285. }
  286. }
  287. }
  288. @Override
  289. public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
  290. //移除滚动监听
  291. if (mScrollListener != null) {
  292. mRecyclerView.removeOnScrollListener(mScrollListener);
  293. }
  294. mRecyclerView = null;
  295. }
  296. /**
  297. * 获取默认的布局摆放器
  298. */
  299. protected RecyclerView.LayoutManager getDefaultLayoutManager(Context context) {
  300. return new LinearLayoutManager(context);
  301. }
  302. /**
  303. * 设置RecyclerView条目点击监听
  304. */
  305. public void setOnItemClickListener(OnItemClickListener l) {
  306. checkRecyclerViewState();
  307. mItemClickListener = l;
  308. }
  309. /**
  310. * 设置 RecyclerView 条目子 View 点击监听
  311. */
  312. public void setOnChildClickListener(@IdRes int childId, OnChildClickListener l) {
  313. checkRecyclerViewState();
  314. if (mChildClickListeners == null) {
  315. mChildClickListeners = new SparseArray<>();
  316. }
  317. mChildClickListeners.put(childId, l);
  318. }
  319. /**
  320. * 设置RecyclerView条目长按监听
  321. */
  322. public void setOnItemLongClickListener(OnItemLongClickListener l) {
  323. checkRecyclerViewState();
  324. mItemLongClickListener = l;
  325. }
  326. /**
  327. * 设置 RecyclerView 条目子 View 长按监听
  328. */
  329. public void setOnChildLongClickListener(@IdRes int childId, OnChildLongClickListener l) {
  330. checkRecyclerViewState();
  331. if (mChildLongClickListeners == null) {
  332. mChildLongClickListeners = new SparseArray<>();
  333. }
  334. mChildLongClickListeners.put(childId, l);
  335. }
  336. private void checkRecyclerViewState() {
  337. if (mRecyclerView != null) {
  338. // 必须在 RecyclerView.setAdapter() 之前设置监听
  339. throw new IllegalStateException("Binding adapters is not allowed before setting listeners");
  340. }
  341. }
  342. /**
  343. * 设置RecyclerView条目滚动监听
  344. */
  345. public void setOnScrollingListener(OnScrollingListener l) {
  346. mScrollingListener = l;
  347. //如果当前已经有设置滚动监听,再次设置需要移除原有的监听器
  348. if (mScrollListener == null) {
  349. mScrollListener = new ScrollListener();
  350. }else {
  351. mRecyclerView.removeOnScrollListener(mScrollListener);
  352. }
  353. //用户设置了滚动监听,需要给RecyclerView设置监听
  354. if (mRecyclerView != null) {
  355. //添加滚动监听
  356. mRecyclerView.addOnScrollListener(mScrollListener);
  357. }
  358. }
  359. //自定义滚动监听器
  360. private ScrollListener mScrollListener;
  361. private class ScrollListener extends RecyclerView.OnScrollListener {
  362. @Override
  363. public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
  364. if (mScrollingListener == null) return;
  365. if (newState == RecyclerView.SCROLL_STATE_IDLE) {
  366. if (!recyclerView.canScrollVertically(1)) {
  367. //是否能向下滚动,false表示已经滚动到底部
  368. mScrollingListener.onScrollDown(recyclerView);
  369. }else if (!recyclerView.canScrollVertically(-1)) {
  370. //是否能向上滚动,false表示已经滚动到顶部
  371. mScrollingListener.onScrollTop(recyclerView);
  372. }
  373. }else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
  374. //正在滚动中
  375. mScrollingListener.onScrolling(recyclerView);
  376. }
  377. }
  378. }
  379. /**
  380. * RecyclerView 滚动监听类
  381. */
  382. public interface OnScrollingListener {
  383. /**
  384. * 列表滚动到最顶部
  385. *
  386. * @param recyclerView RecyclerView对象
  387. */
  388. void onScrollTop(RecyclerView recyclerView);
  389. /**
  390. * 列表滚动到最底部
  391. *
  392. * @param recyclerView RecyclerView对象
  393. */
  394. void onScrollDown(RecyclerView recyclerView);
  395. /**
  396. * 列表滚动中
  397. *
  398. * @param recyclerView RecyclerView对象
  399. */
  400. void onScrolling(RecyclerView recyclerView);
  401. }
  402. /**
  403. * RecyclerView 条目点击监听类
  404. */
  405. public interface OnItemClickListener{
  406. /**
  407. * 当 RecyclerView 某个条目被点击时回调
  408. *
  409. * @param recyclerView RecyclerView对象
  410. * @param itemView 被点击的条目对象
  411. * @param position 被点击的条目位置
  412. */
  413. void onItemClick(RecyclerView recyclerView, View itemView, int position);
  414. }
  415. /**
  416. * RecyclerView 条目长按监听类
  417. */
  418. public interface OnItemLongClickListener {
  419. /**
  420. * 当 RecyclerView 某个条目被长按时回调
  421. *
  422. * @param recyclerView RecyclerView对象
  423. * @param itemView 被点击的条目对象
  424. * @param position 被点击的条目位置
  425. * @return 是否拦截事件
  426. */
  427. boolean onItemLongClick(RecyclerView recyclerView, View itemView, int position);
  428. }
  429. /**
  430. * RecyclerView 条目子 View 点击监听类
  431. */
  432. public interface OnChildClickListener {
  433. /**
  434. * 当 RecyclerView 某个条目 子 View 被点击时回调
  435. *
  436. * @param recyclerView RecyclerView对象
  437. * @param childView 被点击的条目子 View Id
  438. * @param position 被点击的条目位置
  439. */
  440. void onChildClick(RecyclerView recyclerView, View childView, int position);
  441. }
  442. /**
  443. * RecyclerView 条目子 View 长按监听类
  444. */
  445. public interface OnChildLongClickListener {
  446. /**
  447. * 当 RecyclerView 某个条目子 View 被长按时回调
  448. *
  449. * @param recyclerView RecyclerView对象
  450. * @param childView 被点击的条目子 View Id
  451. * @param position 被点击的条目位置
  452. */
  453. void onChildLongClick(RecyclerView recyclerView, View childView, int position);
  454. }
  455. }