recyclerview列表数据,每个item 嵌套横向滑动GridView的问题,
这几天新需求,列表加载用户关注的人物,一页15条数据,,,,,,。然后每个人物 都有自己的一系列作品,要在人物头像之后 ,放一个可以横着滑动,又支持分页加载的横向列表。
刚开始觉得挺容易的,动手就开始写,,recyclerview 垂直布局,item布局嵌套一个横向的GridView,看源码xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<LinearLayout
android:layout_width="110dp"
android:layout_height="110dp"
android:gravity="center"
android:orientation="vertical">
<com.test.testrecyclerview.weight.RoundImageView
android:id="@+id/item_engineer_headerimg"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ease_default_avatar" />
<TextView
android:id="@+id/tv_author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="名字"
android:textSize="14sp" />
</LinearLayout>
<HorizontalScrollView
android:id="@+id/horizontalScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<GridView
android:id="@+id/item_engineer_work_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:gravity="center"
android:scrollbars="none" />
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
recyclerview适配器里 拿到数据源 初始化GridView 适配器 并加载数据,
DisplayMetrics dm2 = context.getResources().getDisplayMetrics(); float density = dm2.density; int allWidth = (int) (110 * size * density); int itemWidth = (int) (100 * density); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( allWidth, LinearLayout.LayoutParams.MATCH_PARENT); holder.mGridview.setLayoutParams(params);// 设置GirdView布局参数 holder.mGridview.setColumnWidth(itemWidth);// 列表项宽 holder.mGridview.setHorizontalSpacing(10);// 列表项水平间距 holder.mGridview.setStretchMode(GridView.NO_STRETCH); holder.mGridview.setNumColumns(size);size = list.size();
holder.mGridview.setAdapter(mGriddapter);
动态的根据GridView的 list的size 大小 设置item个数,,运行出来之后 发现,横向的GridView 滑动 监听不到滑动到最后一个,item点击倒是正常,,,找了各种问题,有自定义了一个LoadMoreHorizontalScrollView,拦截滑动坐标,判断是否滑动到了最右边
public class LoadMoreHorizontalScrollView extends HorizontalScrollView { private ScrollViewListener scrollViewListener = null; private boolean isNeedBreakNet;//这里加了个字段,用于判断 划到最右边 请求数据,不然滑到了最右边,如果手还没离开屏幕,(坐标值一直在左右边)会多次请求数据 public LoadMoreHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public LoadMoreHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public LoadMoreHorizontalScrollView(Context context) { super(context); } public boolean isNeedBreakNet() { return isNeedBreakNet; } public void setNeedBreakNet(boolean needBreakNet) { isNeedBreakNet = needBreakNet; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: int scrollX = getScrollX(); Log.i("GFH", "scrollX=" + scrollX + ";getScrollX()==" + getScrollX()); //最右边 if (scrollX >= getChildWidth()) { if (null != scrollViewListener) { scrollViewListener.onNextPage(); } } //在最左边 if (scrollX == 0) { if (null != scrollViewListener) { scrollViewListener.onPrePage(); } } break; } return super.onTouchEvent(ev); } public void setScrollViewListener(ScrollViewListener scrollViewListener) { this.scrollViewListener = scrollViewListener; } /** * 获取当前HorizontalScrollView最大能滑动的距离 */ private int getChildWidth() { int maxScrollX = 0; try { maxScrollX = getChildAt(0).getMeasuredWidth() - getMeasuredWidth(); } catch (Exception e) { Log.e("GFH", "测量最大滑动距离发生异常:" + e.toString()); } return maxScrollX; } ; public interface ScrollViewListener { void onPrePage(); void onNextPage(); } }
,自定义控件 拦截手势之后,发现还是不对,数据请求过来了,list.size 也变大了,但是,GridView的适配器 数据源没有更新, 就是横着的item 始终是5 个(分页加载的 ,每页5条数据,),
holder.horizontalScrollView.setScrollViewListener(new LoadMoreHorizontalScrollView.ScrollViewListener() { @Override public void onPrePage() { //滑动到最左边 Log.i("SNN", "滑动到最左边,上一页数据请求"); } @Override public void onNextPage() { boolean isNeedBreakNet = holder.horizontalScrollView.isNeedBreakNet(); //滑动到最右边,下一页数据请求 Log.e("SNN", "滑动到最右边,下一页数据请求"); Log.e("SNN", list.get(position).getName()); if (!isNeedBreakNet) { //请求新数据 加载而更多 } holder.horizontalScrollView.setNeedBreakNet(true); } });
头疼了 大半天,才发现,list 和 GridViewAdapter 用的是全局变量,,而recyclerview 的 onBindViewHolder 方法 是每个item都会创建执行一次,,所以现在的情况是 GridViewadapter 只创建了一次,数据更新了 list.size 次,每次横向滑动去加载数据的时候,数据都会被加载到 recyclerview的最后一个item里边的GridView上面。
找到了 问题,就好解决了,,,就是把 list 和 GridView 都放到Map 集合中,,recyclerview加载数据的时候,根据item索引 ,去map集合中取 与position对应的 list 和 GridViewadapter
map集合 ,存放 list集合 和GridviewAdapter
private Map<Integer,GridviewAdapter> GridViewAdapterMap = new HashMap<>(); private Map<Integer, List<WorkInfoBean>> workInfoBeanMap = new HashMap<>(); private Map<Integer, Integer> pageNumMap = new HashMap<>();
然后在onBindViewHolder 中 绑定position 和数据
List<WorkInfoBean> workList = null; if (null != workInfoBeanMap.get(position)) { // workList.get(position); } else { workList = list.get(position).getPots(); workInfoBeanMap.put(position, workList); }
GridviewAdapter mGriddapter = null; if (null != engineerWorkInfoGridViewAdapterMap.get(position)) { mGriddapter = GridViewAdapterMap.get(position); } else { mGriddapter = new GridViewAdapter(context, workList); GridViewAdapterMap.put(position, mGriddapter); }
最后得注意 GridView item个数额计算,不能放在onBindViewHolder 中,单独提取个方法出来,,
/** * // 获取屏幕宽高 动态设置 mGridview item * * @param size * @param holder */ public void newSize(int size, MyViewHolder holder) { DisplayMetrics dm2 = context.getResources().getDisplayMetrics(); float density = dm2.density; int allWidth = (int) (110 * size * density); int itemWidth = (int) (100 * density); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( allWidth, LinearLayout.LayoutParams.MATCH_PARENT); holder.mGridview.setLayoutParams(params);// 设置GirdView布局参数 holder.mGridview.setColumnWidth(itemWidth);// 列表项宽 holder.mGridview.setHorizontalSpacing(10);// 列表项水平间距 holder.mGridview.setStretchMode(GridView.NO_STRETCH); holder.mGridview.setNumColumns(size); }
在 onBindViewHolder 中 setadapter 之前 调用一次,然后在 请求新数据之后 再调用一次,,重新计算item个数。
问题就解决了