ScrollView,ListView,GrideView,RecyclerView,ViewPager等多种view嵌套问题

本文主要是介绍ScrollView,ListView,GrideView,RecyclerView,ViewPager等多种view嵌套问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在开发中各种滑动布局的view如ScrollView,ListView等非常常用,但是你也会发现各种奇怪问题产生。网上的解决方法有很多种,但是杂而不全,根据个人经验现在列出常见问题以及代码最少最简单的解决方法,首先你要了解事件的分发机制及事件冲突,这里不再赘述。(其他继承自AbsListView的类也适用,包括ExpandableListView、GridView等等)

  • ScrollView嵌套ListView冲突问题的最优解决方案

ScrollView嵌套ListVew或者GridView等很常用,下面来说解决版本

问题一 : 嵌套在 ScrollView的 ListVew数据显示不全,我遇到的是最多只显示两条已有的数据。

解决办法:重写 ListVew或者 GridView,网上还有很多若干解决办法,但是都不好用或者很复杂。

     
  1. @Override
  2. /**   只重写该方法,达到使ListView适应ScrollView的效果   */
  3. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  4. int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
  5. MeasureSpec.AT_MOST);
  6. super.onMeasure(widthMeasureSpec, expandSpec);
  7. }

  8. 这个方法有一个同样的毛病,就是默认显示的首项是ListView,需要手动把ScrollView滚动至最顶端


问题二 、打开套有 ListVew的 ScrollView的页面布局 默认 起始位置不是最顶部。

解决办法有两种都挺好用:

一是把套在里面的Gridview 或者 ListVew 不让获取焦点即可。

gridview.setFocusable(false); listview.setFocusable(false);

注意:在xml布局里面设置android:focusable=“false”不生效

方法二:网上还查到说可以设置myScrollView.smoothScrollTo(0,0);

  •    
    1. 看错误的布局代码:
    2. <ScrollView
    3.    android:id="@+id/act_solution_1_sv"
    4.    android:layout_width="fill_parent"
    5.    android:layout_height="fill_parent">
    6. <LinearLayout
    7.        android:layout_width="fill_parent"
    8.        android:layout_height="wrap_content"
    9.        android:orientation="vertical">
    10. <TextView
    11.            android:layout_width="fill_parent"
    12.            android:layout_height="wrap_content"
    13.            android:text="\nListView上方数据\n" />
    14. <ListView
    15.            android:id="@+id/act_solution_1_lv"
    16.            android:layout_width="fill_parent"
    17.            android:layout_height="wrap_content">
    18. </ListView>
    19. <TextView
    20.            android:layout_width="fill_parent"
    21.            android:layout_height="wrap_content"
    22.            android:text="\nListView下方数据\n" />
    23. </LinearLayout>
    24. </ScrollView>
    25. ScrollView中只能放一个控件,一般都放LinearLayout,orientation属性值为vertical。
    26. 在LinearLayout中放需要呈现的内容。ListView也在其中,ListView的高度设为适应自身内容(wrap_content
    27. 原因就是scroll事件的消费处理以及ListView控件的高度设定问题


  • ViewPager和ScrollView嵌套滚动问题解决方案

  •    
    1. 嵌套是ViewPager-->ScrollView-->ViewPager.
    2. public class HorizontalInnerViewPager extends ViewPager {
    3.    /** 触摸时按下的点 **/
    4.    PointF downP = new PointF();
    5.    /** 触摸时当前的点 **/
    6.    PointF curP = new PointF();
    7.    /** 自定义手势**/
    8.    private GestureDetector mGestureDetector;
    9.    public HorizontalInnerViewPager(Context context, AttributeSet attrs) {
    10.        super(context, attrs);
    11.        mGestureDetector = new GestureDetector(context, new XScrollDetector());
    12.    }
    13.    public HorizontalInnerViewPager(Context context) {
    14.        super(context);
    15.        mGestureDetector = new GestureDetector(context, new XScrollDetector());
    16.    }
    17.    @Override
    18.    public boolean onInterceptTouchEvent(MotionEvent ev) {
    19.        return super.onInterceptTouchEvent(ev);//default
    20.        //当拦截触摸事件到达此位置的时候,返回true,
    21.        //说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent
    22. //        return true;
    23.        //接近水平滑动时子控件处理该事件,否则交给父控件处理
    24. //        return mGestureDetector.onTouchEvent(ev);
    25.    }
    26.    @Override
    27.    public boolean onTouchEvent(MotionEvent ev) {
    28.        //每次进行onTouch事件都记录当前的按下的坐标
    29.        curP.x = ev.getX();
    30.        curP.y = ev.getY();
    31.        if(ev.getAction() == MotionEvent.ACTION_DOWN){
    32.            //记录按下时候的坐标
    33.            //切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变
    34.            downP.x = ev.getX();
    35.            downP.y = ev.getY();
    36.            //此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
    37.            getParent().requestDisallowInterceptTouchEvent(true);
    38.        }
    39.        if(ev.getAction() == MotionEvent.ACTION_MOVE){
    40.            float distanceX = curP.x - downP.x;
    41.            float distanceY = curP.y - downP.y;
    42.            //接近水平滑动,ViewPager控件捕获手势,水平滚动
    43.            if(Math.abs(distanceX) > Math.abs(distanceY)){
    44.                //此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
    45.                getParent().requestDisallowInterceptTouchEvent(true);
    46.            }else{
    47.                //接近垂直滑动,交给父控件处理
    48.                getParent().requestDisallowInterceptTouchEvent(false);
    49.            }
    50.        }
    51.        return super.onTouchEvent(ev);
    52.    }
    53.    private class XScrollDetector extends GestureDetector.SimpleOnGestureListener{
    54.        @Override
    55.        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    56. //            return super.onScroll(e1, e2, distanceX, distanceY);
    57.            //接近水平滑动时子控件处理该事件,否则交给父控件处理
    58.            return (Math.abs(distanceX) > Math.abs(distanceY));
    59.        }
    60.    }
    61. }
  • ScrollView里嵌套ScrollView

  •    
    1. 两个相同方向的ScrollView是不能嵌套的,所以尽量避免这种情况; 如果不能避免,则看下面
    2. 目前做的这个只支持两个ScrollView嵌套,两个以上还有待改进,能套两个就已经能满足很多需求了目前为纵向scrollview的支持.直接看代码:
    3. public class InnerScrollView extends ScrollView {
    4.  
    5.    /**
    6.     */
    7.    public ScrollView parentScrollView;
    8.  
    9.    public InnerScrollView(Context context, AttributeSet attrs) {
    10.        super(context, attrs);
    11.  
    12.    }
    13.  
    14.    private int lastScrollDelta = 0;
    15.  
    16.    public void resume() {
    17.        overScrollBy(0, -lastScrollDelta, 0, getScrollY(), 0, getScrollRange(), 0, 0, true);
    18.        lastScrollDelta = 0;
    19.    }
    20.  
    21.    int mTop = 10;
    22.  
    23.    /**
    24.     * 将targetView滚到最顶端
    25.     */
    26.    public void scrollTo(View targetView) {
    27.  
    28.        int oldScrollY = getScrollY();
    29.        int top = targetView.getTop() - mTop;
    30.        int delatY = top - oldScrollY;
    31.        lastScrollDelta = delatY;
    32.        overScrollBy(0, delatY, 0, getScrollY(), 0, getScrollRange(), 0, 0, true);
    33.    }
    34.  
    35.    private int getScrollRange() {
    36.        int scrollRange = 0;
    37.        if (getChildCount() > 0) {
    38.            View child = getChildAt(0);
    39.            scrollRange = Math.max(0, child.getHeight() - (getHeight()));
    40.        }
    41.        return scrollRange;
    42.    }
    43.  
    44.    int currentY;
    45.  
    46.    @Override
    47.    public boolean onInterceptTouchEvent(MotionEvent ev) {
    48.        if (parentScrollView == null) {
    49.            return super.onInterceptTouchEvent(ev);
    50.        } else {
    51.            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    52.                // 将父scrollview的滚动事件拦截
    53.                currentY = (int)ev.getY();
    54.                setParentScrollAble(false);
    55.                return super.onInterceptTouchEvent(ev);
    56.            } else if (ev.getAction() == MotionEvent.ACTION_UP) {
    57.                // 把滚动事件恢复给父Scrollview
    58.                setParentScrollAble(true);
    59.            } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
    60.            }
    61.        }
    62.        return super.onInterceptTouchEvent(ev);
    63.  
    64.    }
    65.  
    66.    @Override
    67.    public boolean onTouchEvent(MotionEvent ev) {
    68.        View child = getChildAt(0);
    69.        if (parentScrollView != null) {
    70.            if (ev.getAction() == MotionEvent.ACTION_MOVE) {
    71.                int height = child.getMeasuredHeight();
    72.                height = height - getMeasuredHeight();
    73.  
    74.                // System.out.println("height=" + height);
    75.                int scrollY = getScrollY();
    76.                // System.out.println("scrollY" + scrollY);
    77.                int y = (int)ev.getY();
    78.  
    79.                // 手指向下滑动
    80.                if (currentY < y) {
    81.                    if (scrollY <= 0) {
    82.                        // 如果向下滑动到头,就把滚动交给父Scrollview
    83.                        setParentScrollAble(true);
    84.                        return false;
    85.                    } else {
    86.                        setParentScrollAble(false);
    87.  
    88.                    }
    89.                } else if (currentY > y) {
    90.                    if (scrollY >= height) {
    91.                        // 如果向上滑动到头,就把滚动交给父Scrollview
    92.                        setParentScrollAble(true);
    93.                        return false;
    94.                    } else {
    95.                        setParentScrollAble(false);
    96.  
    97.                    }
    98.  
    99.                }
    100.                currentY = y;
    101.            }
    102.        }
    103.  
    104.        return super.onTouchEvent(ev);
    105.    }
    106.  
    107.    /**
    108.     * 是否把滚动事件交给父scrollview
    109.     *  
    110.     * @param flag
    111.     */
    112.    private void setParentScrollAble(boolean flag) {
    113.  
    114.        parentScrollView.requestDisallowInterceptTouchEvent(!flag);
    115.    }
    116.  
    117. }
  • RecyclerView嵌套滚动问题

     

    在 Android 应用中,大部分情况下都会使用一个垂直滚动的 View 来显示内容(比如 ListView、RecyclerView 等)。但是有时候你还希望垂直滚动的View 里面的内容可以水平滚动。如果直接在垂直滚动的 View 里面使用水平滚动的 View,则滚动操作并不是很流畅。

    比如下图中的示例:

    为什么会出现这个问题呢?

    上图中的布局为一个 RecyclerView 使用的是垂直滚动的 LinearLayoutManager 布局管理器,而里面每个 Item 为另外一个 RecyclerView 使用的是水平滚动的 LinearLayoutManager。而在 Android系统的事件分发 中,即使最上层的 View 只能垂直滚动,当用户水平拖动的时候,最上层的 View 依然会拦截点击事件。下面是 RecyclerView.java 中 onInterceptTouchEvent 的相关代码:

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {  ...switch (action) {case MotionEvent.ACTION_DOWN:...case MotionEvent.ACTION_MOVE: {...if (mScrollState != SCROLL_STATE_DRAGGING) {boolean startScroll = false;if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {...startScroll = true;}if (canScrollVertically && Math.abs(dy) > mTouchSlop) {...startScroll = true;}if (startScroll) {setScrollState(SCROLL_STATE_DRAGGING);}}} break;...}return mScrollState == SCROLL_STATE_DRAGGING;
    }

    注意上面的 if 判断:

    if(canScrollVertically && Math.abs(dy) > mTouchSlop) {...}  

    RecyclerView 并没有判断用户拖动的角度, 只是用来判断拖动的距离是否大于滚动的最小尺寸。 如果是一个只能垂直滚动的 View,这样实现是没有问题的。如果我们在里面再放一个 水平滚动的 RecyclerView ,则就出现问题了。

    可以通过如下的方式来修复该问题:

    if(canScrollVertically && Math.abs(dy) > mTouchSlop && (canScrollHorizontally || Math.abs(dy) > Math.abs(dx))) {...}  

    下面是一个完整的实现 BetterRecyclerView.java :

    public class BetterRecyclerView extends RecyclerView{private static final int INVALID_POINTER = -1;private int mScrollPointerId = INVALID_POINTER;private int mInitialTouchX, mInitialTouchY;private int mTouchSlop;public BetterRecyclerView(Contextcontext) {this(context, null);}public BetterRecyclerView(Contextcontext, @Nullable AttributeSetattrs) {this(context, attrs, 0);}public BetterRecyclerView(Contextcontext, @Nullable AttributeSetattrs, int defStyle) {super(context, attrs, defStyle);final ViewConfigurationvc = ViewConfiguration.get(getContext());mTouchSlop = vc.getScaledTouchSlop();}@Overridepublic void setScrollingTouchSlop(int slopConstant) {super.setScrollingTouchSlop(slopConstant);final ViewConfigurationvc = ViewConfiguration.get(getContext());switch (slopConstant) {case TOUCH_SLOP_DEFAULT:mTouchSlop = vc.getScaledTouchSlop();break;case TOUCH_SLOP_PAGING:mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(vc);break;default:break;}}@Overridepublic boolean onInterceptTouchEvent(MotionEvent e) {final int action = MotionEventCompat.getActionMasked(e);final int actionIndex = MotionEventCompat.getActionIndex(e);switch (action) {case MotionEvent.ACTION_DOWN:mScrollPointerId = MotionEventCompat.getPointerId(e, 0);mInitialTouchX = (int) (e.getX() + 0.5f);mInitialTouchY = (int) (e.getY() + 0.5f);return super.onInterceptTouchEvent(e);case MotionEventCompat.ACTION_POINTER_DOWN:mScrollPointerId = MotionEventCompat.getPointerId(e, actionIndex);mInitialTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f);mInitialTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f);return super.onInterceptTouchEvent(e);case MotionEvent.ACTION_MOVE: {final int index = MotionEventCompat.findPointerIndex(e, mScrollPointerId);if (index < 0) {return false;}final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f);final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f);if (getScrollState() != SCROLL_STATE_DRAGGING) {final int dx = x - mInitialTouchX;final int dy = y - mInitialTouchY;final boolean canScrollHorizontally = getLayoutManager().canScrollHorizontally();final boolean canScrollVertically = getLayoutManager().canScrollVertically();boolean startScroll = false;if (canScrollHorizontally && Math.abs(dx) > mTouchSlop && (Math.abs(dx) >= Math.abs(dy) || canScrollVertically)) {startScroll = true;}if (canScrollVertically && Math.abs(dy) > mTouchSlop && (Math.abs(dy) >= Math.abs(dx) || canScrollHorizontally)) {startScroll = true;}return startScroll && super.onInterceptTouchEvent(e);}return super.onInterceptTouchEvent(e);}default:return super.onInterceptTouchEvent(e);}}
    }

    其他问题

    当用户快速滑动(fling)RecyclerView 的时候, RecyclerView 需要一段时间来确定其最终位置。 如果用户在快速滑动一个子的水平 RecyclerView,在子 RecyclerView 还在滑动的过程中,如果用户垂直滑动,则是无法垂直滑动的。原因是子 RecyclerView 依然处理了这个垂直滑动事件。

    所以,在快速滑动后的滚动到静止的状态中,子 View 不应该响应滑动事件了,再次看看 RecyclerView 的 onInterceptTouchEvent() 代码:

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {  ...switch (action) {case MotionEvent.ACTION_DOWN:...if (mScrollState == SCROLL_STATE_SETTLING) {getParent().requestDisallowInterceptTouchEvent(true);setScrollState(SCROLL_STATE_DRAGGING);}...}return mScrollState == SCROLL_STATE_DRAGGING;
    }

    可以看到,当 RecyclerView 的状态为 SCROLL_STATE_SETTLING (快速滑动后到滑动静止之间的状态)时, RecyclerView 告诉父控件不要拦截事件。

    同样的,如果只有一个方向固定,这样处理是没问题的。

    针对我们这个嵌套的情况,父 RecyclerView 应该只拦截垂直滚动事件,所以可以这么修改父 RecyclerView:

    public class FeedRootRecyclerView extends BetterRecyclerView{  public FeedRootRecyclerView(Contextcontext) {this(context, null);}public FeedRootRecyclerView(Contextcontext, @Nullable AttributeSetattrs) {this(context, attrs, 0);}public FeedRootRecyclerView(Contextcontext, @Nullable AttributeSetattrs, int defStyle) {super(context, attrs, defStyle);}@Overridepublic void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {/* do nothing */}
    }

    下图为最终的结果:



  • recycleview跟scrollview嵌套问题

    scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview的高度,比如:


           
    1. ViewGroup.LayoutParams mParams = recyclerView.getLayoutParams();  
    2.       mParams.height = (CommonUtils.getScreenWidthPX(getActivity()) * 480 / 720 + CommonUtils.dipToPixels(40)) * num + CommonUtils.dipToPixels(8);  
    3.       mParams.width = CommonUtils.getScreenWidthPX(getActivity());  
    4.       recyclerView.setLayoutParams(mParams);  



    这中方法适合item高度比较好计算的情形,但要遇到里面的item高度不一定这就需要我们重写recyclerview的高度了,以前嵌套listview的时候我们只需重写listview 然后重写



           
    1. @Override  
    2.    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
    3.        // TODO Auto-generated method stub  
    4.        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  
    5.                MeasureSpec.AT_MOST);  
    6.        super.onMeasure(widthMeasureSpec, expandSpec);  
    7.    }  


    但是这种方法在recyclerview重写不管用。 

    我们此时要重写的的是LinearLayoutManager或GridLayoutManager

           
    1. public class FullyLinearLayoutManager extends LinearLayoutManager {  
    2.  
    3.    private static final String TAG = FullyLinearLayoutManager.class.getSimpleName();  
    4.  
    5.    public FullyLinearLayoutManager(Context context) {  
    6.        super(context);  
    7.    }  
    8.  
    9.    public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {  
    10.        super(context, orientation, reverseLayout);  
    11.    }  
    12.  
    13.    private int[] mMeasuredDimension = new int[2];  
    14.  
    15.    @Override  
    16.    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,  
    17.                          int widthSpec, int heightSpec) {  
    18.  
    19.        final int widthMode = View.MeasureSpec.getMode(widthSpec);  
    20.        final int heightMode = View.MeasureSpec.getMode(heightSpec);  
    21.        final int widthSize = View.MeasureSpec.getSize(widthSpec);  
    22.        final int heightSize = View.MeasureSpec.getSize(heightSpec);  
    23.  
    24.        Log.i(TAG, "onMeasure called. \nwidthMode " + widthMode  
    25.                + " \nheightMode " + heightSpec  
    26.                + " \nwidthSize " + widthSize  
    27.                + " \nheightSize " + heightSize  
    28.                + " \ngetItemCount() " + getItemCount());  
    29.  
    30.        int width = 0;  
    31.        int height = 0;  
    32.        for (int i = 0; i < getItemCount(); i++) {  
    33.            measureScrapChild(recycler, i,  
    34.                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
    35.                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
    36.                    mMeasuredDimension);  
    37.  
    38.            if (getOrientation() == HORIZONTAL) {  
    39.                width = width + mMeasuredDimension[0];  
    40.                if (i == 0) {  
    41.                    height = mMeasuredDimension[1];  
    42.                }  
    43.            } else {  
    44.                height = height + mMeasuredDimension[1];  
    45.                if (i == 0) {  
    46.                    width = mMeasuredDimension[0];  
    47.                }  
    48.            }  
    49.        }  
    50.        switch (widthMode) {  
    51.            case View.MeasureSpec.EXACTLY:  
    52.                width = widthSize;  
    53.            case View.MeasureSpec.AT_MOST:  
    54.            case View.MeasureSpec.UNSPECIFIED:  
    55.        }  
    56.  
    57.        switch (heightMode) {  
    58.            case View.MeasureSpec.EXACTLY:  
    59.                height = heightSize;  
    60.            case View.MeasureSpec.AT_MOST:  
    61.            case View.MeasureSpec.UNSPECIFIED:  
    62.        }  
    63.  
    64.        setMeasuredDimension(width, height);  
    65.    }  
    66.  
    67.    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,  
    68.                                   int heightSpec, int[] measuredDimension) {  
    69.        try {  
    70.            View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException  
    71.  
    72.            if (view != null) {  
    73.                RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();  
    74.  
    75.                int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,  
    76.                        getPaddingLeft() + getPaddingRight(), p.width);  
    77.  
    78.                int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,  
    79.                        getPaddingTop() + getPaddingBottom(), p.height);  
    80.  
    81.                view.measure(childWidthSpec, childHeightSpec);  
    82.                measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;  
    83.                measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;  
    84.                recycler.recycleView(view);  
    85.            }  
    86.        } catch (Exception e) {  
    87.            e.printStackTrace();  
    88.        } finally {  
    89.        }  
    90.    }  
    91. }  




           
    1. public class FullyGridLayoutManager extends GridLayoutManager {  
    2.  
    3.    private int mwidth = 0;  
    4.    private int mheight = 0;  
    5.  
    6.    public FullyGridLayoutManager(Context context, int spanCount) {  
    7.        super(context, spanCount);  
    8.    }  
    9.  
    10.    public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {  
    11.        super(context, spanCount, orientation, reverseLayout);  
    12.    }  
    13.  
    14.    private int[] mMeasuredDimension = new int[2];  
    15.  
    16.    public int getMwidth() {  
    17.        return mwidth;  
    18.    }  
    19.  
    20.    public void setMwidth(int mwidth) {  
    21.        this.mwidth = mwidth;  
    22.    }  
    23.  
    24.    public int getMheight() {  
    25.        return mheight;  
    26.    }  
    27.  
    28.    public void setMheight(int mheight) {  
    29.        this.mheight = mheight;  
    30.    }  
    31.  
    32.    @Override  
    33.    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {  
    34.        final int widthMode = View.MeasureSpec.getMode(widthSpec);  
    35.        final int heightMode = View.MeasureSpec.getMode(heightSpec);  
    36.        final int widthSize = View.MeasureSpec.getSize(widthSpec);  
    37.        final int heightSize = View.MeasureSpec.getSize(heightSpec);  
    38.  
    39.        int width = 0;  
    40.        int height = 0;  
    41.        int count = getItemCount();  
    42.        int span = getSpanCount();  
    43.        for (int i = 0; i < count; i++) {  
    44.            measureScrapChild(recycler, i,  
    45.                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
    46.                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
    47.                    mMeasuredDimension);  
    48.  
    49.            if (getOrientation() == HORIZONTAL) {  
    50.                if (i % span == 0) {  
    51.                    width = width + mMeasuredDimension[0];  
    52.                }  
    53.                if (i == 0) {  
    54.                    height = mMeasuredDimension[1];  
    55.                }  
    56.            } else {  
    57.                if (i % span == 0) {  
    58.                    height = height + mMeasuredDimension[1];  
    59.                }  
    60.                if (i == 0) {  
    61.                    width = mMeasuredDimension[0];  
    62.                }  
    63.            }  
    64.        }  
    65.  
    66.        switch (widthMode) {  
    67.            case View.MeasureSpec.EXACTLY:  
    68.                width = widthSize;  
    69.            case View.MeasureSpec.AT_MOST:  
    70.            case View.MeasureSpec.UNSPECIFIED:  
    71.        }  
    72.  
    73.        switch (heightMode) {  
    74.            case View.MeasureSpec.EXACTLY:  
    75.                height = heightSize;  
    76.            case View.MeasureSpec.AT_MOST:  
    77.            case View.MeasureSpec.UNSPECIFIED:  
    78.        }  
    79.        setMheight(height);  
    80.        setMwidth(width);  
    81.        setMeasuredDimension(width, height);  
    82.    }  
    83.  
    84.    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,  
    85.                                   int heightSpec, int[] measuredDimension) {  
    86.        if (position < getItemCount()) {  
    87.            try {  
    88.                View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException  
    89.                if (view != null) {  
    90.                    RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();  
    91.                    int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,  
    92.                            getPaddingLeft() + getPaddingRight(), p.width);  
    93.                    int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,  
    94.                            getPaddingTop() + getPaddingBottom(), p.height);  
    95.                    view.measure(childWidthSpec, childHeightSpec);  
    96.                    measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;  
    97.                    measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;  
    98.                    recycler.recycleView(view);  
    99.                }  
    100.            } catch (Exception e) {  
    101.                e.printStackTrace();  
    102.            }  
    103.        }  
    104.    }  
    105. }  


    重写完之后,用就好说了,在adapter的onBindview和平常一样用就可以了



           
    1. final FullyGridLayoutManager manager = new FullyGridLayoutManager(context.getActivity(), 3);  
    2.        manager.setOrientation(GridLayoutManager.VERTICAL);  
    3.        manager.setSmoothScrollbarEnabled(true);  
    4.        viewHolder.recyclerView.setLayoutManager(manager);

    或者再activity中设置一样的



    此种方法在4.x系统上好用,能显示滑动也流畅,但是在5.x上虽然显示正常,但是滑动的时候好像被粘住了,没有惯性效果。。。。然后郁闷了一下午。。。。 
    最后解决方法是重写最外层的Scrollview


  •    
    1. **  
    2. * 屏蔽 滑动事件  
    3. * Created by fc on 2015/7/16.  
    4. */  
    5. public class MyScrollview extends ScrollView {  
    6.    private int downX;  
    7.    private int downY;  
    8.    private int mTouchSlop;  
    9.  
    10.    public MyScrollview(Context context) {  
    11.        super(context);  
    12.        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
    13.    }  
    14.  
    15.    public MyScrollview(Context context, AttributeSet attrs) {  
    16.        super(context, attrs);  
    17.        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
    18.    }  
    19.  
    20.    public MyScrollview(Context context, AttributeSet attrs, int defStyleAttr) {  
    21.        super(context, attrs, defStyleAttr);  
    22.        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
    23.    }  
    24.  
    25.    @Override  
    26.    public boolean onInterceptTouchEvent(MotionEvent e) {  
    27.        int action = e.getAction();  
    28.        switch (action) {  
    29.            case MotionEvent.ACTION_DOWN:  
    30.                downX = (int) e.getRawX();  
    31.                downY = (int) e.getRawY();  
    32.                break;  
    33.            case MotionEvent.ACTION_MOVE:  
    34.                int moveY = (int) e.getRawY();  
    35.                if (Math.abs(moveY - downY) > mTouchSlop) {  
    36.                    return true;  
    37.                }  
    38.        }  
    39.        return super.onInterceptTouchEvent(e);  
    40.    }  
    41. }  

这篇关于ScrollView,ListView,GrideView,RecyclerView,ViewPager等多种view嵌套问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1020426

相关文章

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

题目1254:N皇后问题

题目1254:N皇后问题 时间限制:1 秒 内存限制:128 兆 特殊判题:否 题目描述: N皇后问题,即在N*N的方格棋盘内放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在同一斜线上。因为皇后可以直走,横走和斜走如下图)。 你的任务是,对于给定的N,求出有多少种合法的放置方法。输出N皇后问题所有不同的摆放情况个数。 输入

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR