当前位置:   article > 正文

RecyclerView 多布局使用_android recyclerview实现多布局效果

android recyclerview实现多布局效果

RecyclerView 使用了很久了,一直是简单的和ListView 一样的效果。其实RecyclerView 的强大之处在于实现一线复杂的布局,这是ListView 不能做到的。对于基本的RecyclerView 使用我们都很熟悉了,今天写一个多布局的实现。先看需求图:


需求如上:对于“历史选择”这个条目以上的部分我们可以写一个LinearLayout 就处理了。“历史选择”一下的部分我们用RecyclerView 去实现。(以前的思路我们可能是ScrollView 加listView 嵌套来实现这个需求)

我们看上图画了一些框,“历史选择”为一行,位置的信息如:嘉峪关则一行有四个格子,下面的灰色分割线也是占满了一行,还有“选择省份”也是一行,下面的省份的名称如“甘肃”,也是一行。大概我们就可以看明白了有五种不同的布局要处理,历史选择,地点名称的小格子,灰色分割线,选择省份一行,省份名称一行,他们占的padding是不同的,我们只能用多个布局来处理。这样我们就可以开始写布局了。

历史选择:就一个TextView

  1. <TextView
  2. android:id="@+id/tv_selectHistoryTitle"
  3. tools:text="历史选择:"
  4. android:textColor="@color/black"
  5. android:padding="@dimen/padding_10dp"
  6. android:paddingLeft="@dimen/padding_15dp"
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content" />
显示地名的小格子布局:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:gravity="center"
  5. android:id="@+id/ll_content"
  6. android:background="@color/white"
  7. android:layout_height="wrap_content"
  8. android:layout_marginLeft="@dimen/margin_4dp"
  9. android:layout_marginRight="@dimen/margin_4dp"
  10. android:layout_marginTop="@dimen/margin_5dp"
  11. android:layout_marginBottom="@dimen/margin_5dp">
  12. <TextView
  13. android:id="@+id/tv_selectPlaceContent"
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content"
  16. android:gravity="center"
  17. android:background="@drawable/bg_bit_gray_hollow_rounded_rectangle"
  18. android:ellipsize="end"
  19. android:lines="1"
  20. android:paddingLeft="@dimen/padding_6dp"
  21. android:paddingRight="@dimen/padding_6dp"
  22. android:paddingTop="@dimen/padding_6dp"
  23. android:paddingBottom="@dimen/padding_6dp"
  24. android:textColor="@color/black"
  25. tools:text="历史选择的的" />
  26. </LinearLayout>
其中给TextView 添加一个drawable ,也就是一个shape就可以成为途中的椭圆的样子了。

下面是选择省份这个标题,也是一个TextView

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:background="@color/lightgray"
  6. android:orientation="vertical">
  7. <TextView
  8. android:id="@+id/tv_selectProvinceTitle"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:background="@color/white"
  12. android:paddingLeft="@dimen/padding_10dp"
  13. android:paddingRight="@dimen/padding_10dp"
  14. android:paddingTop="@dimen/padding_10dp"
  15. android:textColor="@color/black"
  16. tools:text="选择省粉:" />
  17. </LinearLayout>
最后是显示省份名称的布局:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:layout_width="match_parent"
  3. android:layout_height="wrap_content"
  4. android:background="@color/white"
  5. android:paddingBottom="@dimen/padding_5dp"
  6. android:paddingTop="@dimen/padding_5dp"
  7. xmlns:tools="http://schemas.android.com/tools">
  8. <TextView
  9. android:id="@+id/tv_selectProvinceName"
  10. tools:text="甘肃"
  11. android:textColor="@color/black"
  12. android:layout_marginLeft="@dimen/margin_10dp"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content" />
  15. </LinearLayout>
这样就完成了上面分析的布局的编写。

然后写RecyclerView 和Adapter适配器。对于多布局的实现,主要是要对数据进行分类,我们根据不同的类别在Adapter中返回不同的ViewHoler就可以了。和其他的Adapter相比,我们需要多写一个方法

public int getItemViewType(int position)
进行一个分类。
其实前面我们可以看出来这个对于RecyclerView 来说我们要使用一个GridLayoutManager 布局管理器,让他显示为四列的样子,对于那些标题部分显示的是一列,我们可以重写一个方法,让在这个类型的布局的时候显示一列就有可以了。所以说这个多布局中主要还有一个方法:

gridLayoutManager.setSpanSizeLookup()
这个就是用来设置显示几列的方法。

下面看代码:

  1. private Context context;
  2. private List<PlaceItem> list;
  3. private final int SPAN_SIZE_HISTORY_CHOICE = 1001;//,历史选择
  4. private final int SPAN_SIZE_CHOICE_PROVINCE = 1002;//标题,选择省
  5. private final int SPAN_SIZE_PROVINCE_NAME = 1003;//选择的省名称
  6. private final int SPAN_SIZE_CONTENT = 1004;//位置数据
  7. private final int SPAN_SIZE_GRAY_SEPARATE = 1005;//灰色分割条
  8. private OnPlaceItemClickListener onPlaceItemClickListener;
  9. public void setOnPlaceItemClickListener(OnPlaceItemClickListener onPlaceItemClickListener) {
  10. this.onPlaceItemClickListener = onPlaceItemClickListener;
  11. }
  12. public SelectPlaceAdapter(Context context, List<PlaceItem> list) {
  13. this.context = context;
  14. this.list = list;
  15. }
  16. @Override
  17. public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  18. if(viewType == SPAN_SIZE_GRAY_SEPARATE){
  19. View separateView = LayoutInflater.from(context).inflate(R.layout.recycle_select_place_item_gray_bg, parent, false);
  20. SelectPlaceGraybgViewHolder viewHolder = new SelectPlaceGraybgViewHolder(separateView);
  21. return viewHolder;
  22. }else if (viewType == SPAN_SIZE_HISTORY_CHOICE) {
  23. View historyView = LayoutInflater.from(context).inflate(R.layout.recycle_select_place_item_history_select_title, parent, false);
  24. SelectHistoryTitleViewHolder viewHolder = new SelectHistoryTitleViewHolder(historyView);
  25. return viewHolder;
  26. } else if (viewType == SPAN_SIZE_CHOICE_PROVINCE) {
  27. View provinceTitleView = LayoutInflater.from(context).inflate(R.layout.recycle_select_place_item_select_province_title, parent, false);
  28. SelectProvinceTitleViewHolder viewHolder = new SelectProvinceTitleViewHolder(provinceTitleView);
  29. return viewHolder;
  30. } else if (viewType == SPAN_SIZE_PROVINCE_NAME) {
  31. View provinceNameView = LayoutInflater.from(context).inflate(R.layout.recycle_select_place_item_subtitle, parent, false);
  32. SelectProvinceNameViewHolder viewHolder = new SelectProvinceNameViewHolder(provinceNameView);
  33. return viewHolder;
  34. } else if (viewType == SPAN_SIZE_CONTENT) {
  35. View contentView = LayoutInflater.from(context).inflate(R.layout.recycle_select_place_item_content, parent, false);
  36. SelectPlaceContentViewHoder viewHolder = new SelectPlaceContentViewHoder(contentView);
  37. return viewHolder;
  38. }
  39. return null;
  40. }
  41. @Override
  42. public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
  43. int type = getItemViewType(position);
  44. Log.e("TAG", "bindViewHolder type-" + type);
  45. switch (type) {
  46. case SPAN_SIZE_GRAY_SEPARATE:{
  47. SelectPlaceGraybgViewHolder selectPlaceGraybgViewHolder = (SelectPlaceGraybgViewHolder) holder;
  48. GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) selectPlaceGraybgViewHolder.llSelectPlaceGraybg.getLayoutParams();
  49. DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
  50. layoutParams.width = displayMetrics.widthPixels;
  51. layoutParams.setMarginStart(DensityUtil.dp2px(context,-10));//设置左边移动,从(0,0)开始
  52. selectPlaceGraybgViewHolder.llSelectPlaceGraybg.setLayoutParams(layoutParams);
  53. selectPlaceGraybgViewHolder.llSelectPlaceGraybg.requestLayout();
  54. break;
  55. }
  56. case SPAN_SIZE_HISTORY_CHOICE: {
  57. SelectHistoryTitleViewHolder historyTitleViewHolder = (SelectHistoryTitleViewHolder) holder;
  58. historyTitleViewHolder.tvSelectHistoryTitle.setText("历史选择title");
  59. break;
  60. }
  61. case SPAN_SIZE_CHOICE_PROVINCE: {
  62. SelectProvinceTitleViewHolder provinceTitleViewHolder = (SelectProvinceTitleViewHolder) holder;
  63. provinceTitleViewHolder.tvSlectProvinceTitdle.setText("选择省份:");
  64. break;
  65. }
  66. case SPAN_SIZE_PROVINCE_NAME: {
  67. SelectProvinceNameViewHolder provinceNameViewHolder = (SelectProvinceNameViewHolder) holder;
  68. provinceNameViewHolder.tvSelectProvinceName.setText("甘肃省");
  69. break;
  70. }
  71. case SPAN_SIZE_CONTENT: {
  72. SelectPlaceContentViewHoder contentViewHoder = (SelectPlaceContentViewHoder) holder;
  73. contentViewHoder.itemView.setOnClickListener(v -> {
  74. if(onPlaceItemClickListener!=null){
  75. onPlaceItemClickListener.onItemClick(contentViewHoder.itemView,position);
  76. }
  77. });
  78. contentViewHoder.tvSelectPlaceContent.setText(list.get(position).getItemContent());
  79. break;
  80. }
  81. }
  82. }
  83. @Override
  84. public int getItemCount() {
  85. return list.size();
  86. }
  87. @Override
  88. public int getItemViewType(int position) {
  89. if (list.get(position).getItemType() == 1) {
  90. return SPAN_SIZE_HISTORY_CHOICE;//1001
  91. } else if (list.get(position).getItemType() == 2) {
  92. return SPAN_SIZE_CHOICE_PROVINCE;//1002
  93. } else if (list.get(position).getItemType() == 3) {
  94. return SPAN_SIZE_PROVINCE_NAME;//1003
  95. } else if (list.get(position).getItemType() == 4) {
  96. return SPAN_SIZE_CONTENT;//1004
  97. } else if(list.get(position).getItemType() == 5){
  98. return SPAN_SIZE_GRAY_SEPARATE;
  99. }else{
  100. return SPAN_SIZE_CONTENT;//默认是内容返回
  101. }
  102. }
  103. /**
  104. * 位置点击
  105. */
  106. public interface OnPlaceItemClickListener{
  107. void onItemClick(View view,int postion);
  108. }
  109. /**
  110. * 历史选择 标题
  111. */
  112. public class SelectHistoryTitleViewHolder extends RecyclerView.ViewHolder {
  113. @BindView(R.id.tv_selectHistoryTitle)
  114. TextView tvSelectHistoryTitle;
  115. public SelectHistoryTitleViewHolder(View itemView) {
  116. super(itemView);
  117. ButterKnife.bind(this, itemView);
  118. }
  119. }
  120. /**
  121. * 选择省粉 标题
  122. */
  123. public class SelectProvinceTitleViewHolder extends RecyclerView.ViewHolder {
  124. @BindView(R.id.tv_selectProvinceTitle)
  125. TextView tvSlectProvinceTitdle;
  126. public SelectProvinceTitleViewHolder(View itemView) {
  127. super(itemView);
  128. ButterKnife.bind(this, itemView);
  129. }
  130. }
  131. /**
  132. * 省份名称显示
  133. */
  134. public class SelectProvinceNameViewHolder extends RecyclerView.ViewHolder {
  135. @BindView(R.id.tv_selectProvinceName)
  136. TextView tvSelectProvinceName;
  137. public SelectProvinceNameViewHolder(View itemView) {
  138. super(itemView);
  139. ButterKnife.bind(this, itemView);
  140. }
  141. }
  142. /**
  143. * 地点显示
  144. */
  145. public class SelectPlaceContentViewHoder extends RecyclerView.ViewHolder {
  146. @BindView(R.id.tv_selectPlaceContent)
  147. TextView tvSelectPlaceContent;
  148. @BindView(R.id.ll_content)
  149. LinearLayout llContent;
  150. public SelectPlaceContentViewHoder(View itemView) {
  151. super(itemView);
  152. ButterKnife.bind(this, itemView);
  153. }
  154. }
  155. /**
  156. * 灰色条
  157. */
  158. public class SelectPlaceGraybgViewHolder extends RecyclerView.ViewHolder{
  159. @BindView(R.id.ll_selectPlaceGraybg)
  160. LinearLayout llSelectPlaceGraybg;
  161. public SelectPlaceGraybgViewHolder(View itemView) {
  162. super(itemView);
  163. ButterKnife.bind(this,itemView);
  164. }
  165. }

每一个布局我们都写一个ViewHolder 总共有5个ViewHolder。上面我们重写了getItemViewType ()这个方法,主要是根据数据的类型返回不同的类型。然后在onCreateViewHolder 中根据类型判断穿件不同的ViewHolder.最后在onBindViewHolder()中绑定数据就可以了。接着来看看显示一行时候调用的方法:

  1. gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
  2. @Override
  3. public int getSpanSize(int position) {
  4. int type = recycleSelectPlace.getAdapter().getItemViewType(position);
  5. switch (type){
  6. case 1004:{
  7. return 1;//占1格
  8. }
  9. case 1001:{
  10. return 4;
  11. }
  12. case 1002:{
  13. return 4;
  14. }
  15. case 1003:{
  16. return 4;
  17. }
  18. case 1005:{
  19. return 4;
  20. }
  21. }
  22. return 4;
  23. }
  24. });
代码很简单,就是根据type,return 要占的格子数就好了。其中的type值和Adapter中的类型对应。

数据部分:我们要按照图中从上到下(历史选择->历史选择的数据->选择省份:标题->省份名称->省份数据->省份名称...)的顺序处理好,在数据对象中添加一个type,然后添加到List 中传递进Adapter就可以了。

这样,大体上的效果我们就可以看到了:



基本上实现了需求,有一些细节的地方可能需求按自己的要求修改一下。




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/174911
推荐阅读
相关标签
  

闽ICP备14008679号