Recyclerview列表,item嵌套横向Gridview 解决滑动冲突,数据加载问题


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 适配器 并加载数据,


 
size = list.size();
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);
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个数。

问题就解决了


发布了17 篇原创文章 · 获赞 37 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/sinat_32961877/article/details/72909965
今日推荐