zoukankan      html  css  js  c++  java
  • Android RecyclerView和ScrollView嵌套使用

    我们的recyclerView有多个layoutmanager,通过重写layoutmanager的方法就可以让recyclerView和ScrollView嵌套了。但是请注意,如果recyclerView很长那么强烈不建议去做嵌套,因为这样recyclerView会在展示的时候立刻展示所有内容,效率极低。

    本文的两部分代码来自一个博主的博客,另一个是我自己写的,正好可以完全适用于现有的layoutmanager。大家需要的话可以试试,应该问题不大。

    原博主的demo:https://github.com/Frank-Zhu/AndroidRecyclerViewDemo

    1.LinearLayoutManager和ScrollView嵌套

    package com.frankzhu.recyclerviewdemo;
    
    import android.content.Context;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    
    /**
     * Author:    ZhuWenWu
     * Version    V1.0
     * Date:      2015/2/26  14:15.
     * Description:
     * Modification  History:
     * Date             Author                Version            Description
     * -----------------------------------------------------------------------------------
     * 2015/2/26        ZhuWenWu            1.0                    1.0
     * Why & What is modified:
     */
    public class FullyLinearLayoutManager extends LinearLayoutManager {
    
        private static final String TAG = FullyLinearLayoutManager.class.getSimpleName();
    
        public FullyLinearLayoutManager(Context context) {
            super(context);
        }
    
        public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
            super(context, orientation, reverseLayout);
        }
    
        private int[] mMeasuredDimension = new int[2];
    
        @Override
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                              int widthSpec, int heightSpec) {
    
            final int widthMode = View.MeasureSpec.getMode(widthSpec);
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
            final int widthSize = View.MeasureSpec.getSize(widthSpec);
            final int heightSize = View.MeasureSpec.getSize(heightSpec);
    
            Log.i(TAG, "onMeasure called. 
    widthMode " + widthMode
                    + " 
    heightMode " + heightSpec
                    + " 
    widthSize " + widthSize
                    + " 
    heightSize " + heightSize
                    + " 
    getItemCount() " + getItemCount());
    
            int width = 0;
            int height = 0;
            for (int i = 0; i < getItemCount(); i++) {
                measureScrapChild(recycler, i,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        mMeasuredDimension);
    
                if (getOrientation() == HORIZONTAL) {
                    width = width + mMeasuredDimension[0];
                    if (i == 0) {
                        height = mMeasuredDimension[1];
                    }
                } else {
                    height = height + mMeasuredDimension[1];
                    if (i == 0) {
                        width = mMeasuredDimension[0];
                    }
                }
            }
            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            setMeasuredDimension(width, height);
        }
    
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                       int heightSpec, int[] measuredDimension) {
            try {
                View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
    
                if (view != null) {
                    RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
    
                    int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                            getPaddingLeft() + getPaddingRight(), p.width);
    
                    int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                            getPaddingTop() + getPaddingBottom(), p.height);
    
                    view.measure(childWidthSpec, childHeightSpec);
                    measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
                    measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
                    recycler.recycleView(view);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
    }

    2.GridLayoutManager和ScrollView进行嵌套

    package com.frankzhu.recyclerviewdemo;
    
    import android.content.Context;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.view.ViewGroup;
    
    /**
     * Author:    ZhuWenWu
     * Version    V1.0
     * Date:      2015/2/26  14:14.
     * Description:
     * Modification  History:
     * Date             Author                Version            Description
     * -----------------------------------------------------------------------------------
     * 2015/2/26        ZhuWenWu            1.0                    1.0
     * Why & What is modified:
     */
    public class FullyGridLayoutManager extends GridLayoutManager {
        public FullyGridLayoutManager(Context context, int spanCount) {
            super(context, spanCount);
        }
    
        public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
            super(context, spanCount, orientation, reverseLayout);
        }
    
        private int[] mMeasuredDimension = new int[2];
    
        @Override
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
            final int widthMode = View.MeasureSpec.getMode(widthSpec);
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
            final int widthSize = View.MeasureSpec.getSize(widthSpec);
            final int heightSize = View.MeasureSpec.getSize(heightSpec);
    
            int width = 0;
            int height = 0;
            int count = getItemCount();
            int span = getSpanCount();
            for (int i = 0; i < count; i++) {
                measureScrapChild(recycler, i,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        mMeasuredDimension);
    
                if (getOrientation() == HORIZONTAL) {
                    if (i % span == 0) {
                        width = width + mMeasuredDimension[0];
                    }
                    if (i == 0) {
                        height = mMeasuredDimension[1];
                    }
                } else {
                    if (i % span == 0) {
                        height = height + mMeasuredDimension[1];
                    }
                    if (i == 0) {
                        width = mMeasuredDimension[0];
                    }
                }
            }
    
            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            setMeasuredDimension(width, height);
        }
    
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                       int heightSpec, int[] measuredDimension) {
            if (position < getItemCount()) {
                try {
                    View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException
                    if (view != null) {
                        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
                        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                                getPaddingLeft() + getPaddingRight(), p.width);
                        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                                getPaddingTop() + getPaddingBottom(), p.height);
                        view.measure(childWidthSpec, childHeightSpec);
                        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
                        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
                        recycler.recycleView(view);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    3.StaggeredGridLayoutManager和ScrollView进行嵌套

    package com.kale.waterfalldemo.extra.RecyclerView;
    
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.StaggeredGridLayoutManager;
    import android.view.View;
    import android.view.ViewGroup;
    
    /**
     * @author Jack Tony
     * @brief 不规则排列(类似于瀑布流)的布局管理器
     * @date 2015/4/6
     */
    public class ExStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
    
        public ExStaggeredGridLayoutManager(int spanCount, int orientation) {
            super(spanCount, orientation);
        }
    
        // 尺寸的数组,[0]是宽,[1]是高
        private int[] measuredDimension = new int[2];
    
        // 用来比较同行/列那个item罪宽/高
        private int[] dimension;
    
    
        @Override
    
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
            // 宽的mode+size
            final int widthMode = View.MeasureSpec.getMode(widthSpec);
            final int widthSize = View.MeasureSpec.getSize(widthSpec);
            // 高的mode + size
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
            final int heightSize = View.MeasureSpec.getSize(heightSpec);
    
            // 自身宽高的初始值
            int width = 0;
            int height = 0;
            // item的数目
            int count = getItemCount();
            // item的列数
            int span = getSpanCount();
            // 根据行数或列数来创建数组
            dimension = new int[span];
    
            for (int i = 0; i < count; i++) {
                measureScrapChild(recycler, i,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), measuredDimension);
    
               // 如果是竖直的列表,计算item的高,否则计算宽度
                //Log.d("LISTENER", "position " + i + " height = " + measuredDimension[1]);
                if (getOrientation() == VERTICAL) {
                    dimension[findMinIndex(dimension)] += measuredDimension[1];
                } else {
                    dimension[findMinIndex(dimension)] += measuredDimension[0];
                }
            }
            if (getOrientation() == VERTICAL) {
                height = findMax(dimension);
            } else {
                width = findMax(dimension);
            }
            
    
            switch (widthMode) {
                // 当控件宽是match_parent时,宽度就是父控件的宽度
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                    break;
                case View.MeasureSpec.AT_MOST:
                    break;
                case View.MeasureSpec.UNSPECIFIED:
                    break;
            }
            switch (heightMode) {
                // 当控件高是match_parent时,高度就是父控件的高度
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                    break;
                case View.MeasureSpec.AT_MOST:
                    break;
                case View.MeasureSpec.UNSPECIFIED:
                    break;
            }
            // 设置测量尺寸  
            setMeasuredDimension(width, height);
        }
    
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                int heightSpec, int[] measuredDimension) {
    
            // 挨个遍历所有item
            if (position < getItemCount()) {
                try {
                    View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException
    
                    if (view != null) {
                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
                        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), lp.width);
                        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), lp.height);
                        // 子view进行测量,然后可以通过getMeasuredWidth()获得测量的宽,高类似
                        view.measure(childWidthSpec, childHeightSpec);
                        // 将item的宽高放入数组中
                        measuredDimension[0] = view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                        measuredDimension[1] = view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
                        recycler.recycleView(view);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        private int findMax(int[] array) {
            int max = array[0];
            for (int value : array) {
                if (value > max) {
                    max = value;
                }
            }
            return max;
        }
    
        /**
         * 得到最数组中最小元素的下标
         *
         * @param array
         * @return
         */
        private int findMinIndex(int[] array) {
            int index = 0;
            int min = array[0];
            for (int i = 0; i < array.length; i++) {
                if (array[i] < min) {
                    min = array[i];
                    index = i;
                }
            }
            return index;
        }
       
    }
  • 相关阅读:
    Python3之random模块常用方法
    Go语言学习笔记(九)之数组
    Go语言学习笔记之简单的几个排序
    Go语言学习笔记(八)
    Python3之logging模块
    Go语言学习笔记(六)
    123. Best Time to Buy and Sell Stock III(js)
    122. Best Time to Buy and Sell Stock II(js)
    121. Best Time to Buy and Sell Stock(js)
    120. Triangle(js)
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/7411180.html
Copyright © 2011-2022 走看看