(4.3.2.17)Listview || ScrollView嵌套RecyclerView、ListView时解决布局问题

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

[java]  view plain  copy
  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的高度了。

重写recyclerView的方法:

[java]  view plain  copy
  1. public class MyRecyclerView extends RecyclerView{  
  2.   
  3.     public MyRecyclerView(Context context) {  
  4.         super(context);  
  5.     }  
  6.   
  7.     public MyRecyclerView(Context context, AttributeSet attrs) {  
  8.         super(context, attrs);  
  9.     }  
  10.   
  11.     public MyRecyclerView(Context context, AttributeSet attrs, int defStyle) {  
  12.         super(context, attrs, defStyle);  
  13.     }  
  14.   
  15.     @Override  
  16.     protected void onMeasure(int widthSpec, int heightSpec) {  
  17.         int newHeightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);  
  18.         super.onMeasure(widthSpec, newHeightSpec);  
  19.     }  
  20. }  
但是这种方法在recyclerview重写不管用。  我们此时要重写的的是LinearLayoutManager或GridLayoutManager

重写LinearLayoutManager

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

重写 GridLayoutManager

[java]  view plain  copy
  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和平常一样用就可以了

[java]  view plain  copy
  1. mLinearLayoutManager = new MyLinearLayoutManger(this);  
  2. suggest_list_recycler.setLayoutManager(mLinearLayoutManager);  
  3.  //添加分隔线 RecyclerView  
  4. suggest_list_recycler.addItemDecoration(new AdvanceDecoration(EventActivity.this, OrientationHelper.VERTICAL));  
  5. suggest_list_recycler.setAdapter(adapter = new EventSuggestListAdapter(EventActivity.this, eventSuggestModel.list));  

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


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

[java]  view plain  copy
  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. }  

这样就可以了,暴力屏蔽。。。。5以上的事件直接传递给了内层的recyclerview,所以我们把滑动事件拦截就好了。

===================================================================================


ScrollView嵌套ListView只显示一行之计算的高度不正确的解决办法:

参考:http://blog.csdn.NET/spring_he/article/details/17409661

1.在类中添加setListViewHeightBasedOnChildren(ListView listView)方法;

[java]  view plain  copy
  1. /** 
  2.     * @param  listview 
  3.     * 此方法是本次listview嵌套listview的核心方法:计算parentlistview item的高度。 
  4.     * 如果不使用此方法,无论innerlistview有多少个item,则只会显示一个item。 
  5.     **/  
  6.    public void setListViewHeightBasedOnChildren(ListView listView) {  
  7.        // 获取ListView对应的Adapter  
  8.        ListAdapter listAdapter = listView.getAdapter();  
  9.        if (listAdapter == null) {        return;    }  
  10.        int totalHeight = 0;  
  11.        for (int i = 0, len = listAdapter.getCount(); i < len; i++) {  
  12.            // listAdapter.getCount()返回数据项的数目  
  13.            View listItem = listAdapter.getView(i, null, listView);  
  14.            // 计算子项View 的宽高  
  15.            listItem.measure(00);  
  16.            // 统计所有子项的总高度  
  17.            totalHeight += listItem.getMeasuredHeight();  
  18.        }  
  19.        ViewGroup.LayoutParams params = listView.getLayoutParams();  
  20.        params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));  
  21.        listView.setLayoutParams(params);  
  22.    }  


2.在activity类中这样使用

[java]  view plain  copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;">parentAdapter = new ParentAdapter(MainActivity.this,parentList);</span><pre name="code" class="java">act_listview.setAdapter(parentAdapter);  
  2. setListViewHeightBasedOnChildren(act_listview);  

 
3.需要将activity中布局文件的listview和scrollview的宽高设置为match_parent;并将scrollview添加属性android:fillViewport = "true"。 

布局activity_main如下:

[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical">  
  6.     <ScrollView  
  7.         android:layout_width="match_parent"  
  8.         android:layout_height="match_parent"  
  9.         android:fillViewport="true">  
  10.         <ListView  
  11.             android:id="@+id/act_listview"  
  12.             android:layout_width="match_parent"  
  13.             android:layout_height="match_parent" />  
  14.     </ScrollView>  
  15. </LinearLayout>  

4.将外层adapter和里层adapter的布局文件都已LinearLayout作为根布局。

[java]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical">  
  6.     <TextView  
  7.         android:id="@+id/children_country_tv"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content" />  
  10. </LinearLayout>  


总结:

解决方案: 

(1)ListView不能用自定义的,必须用原生的ListView;

         (2)ListView的宽高都用 match_parent或fill_parent;

         (3)用计算高度的方式去实现setListViewHeightBasedOnChildren(ListView);

         (4)adapter的item的根布局必须为LinearLayout布局,不然计算高度时会有问题;

         (5)ScrollView中添加属性 Android:fillViewport="true"

  利用以上的5点,基本可以解决问题,我是这样解决,如果有没有解决的,请注意布局上看看有什么问题,把多余的功能去掉,从最基本的只显示ListView开始调节,一个功能一个功能的加上去,看看是哪里出问题,就逐步排除并解决。

=========================================================================================


listview中嵌套子listview,解决子listview点击问题:

1.在子listview的item最外面的一层布局LinearLayout 添加 android:descendantFocusability="blocksDescendants"属性;

2.在父listview中添加android:focusable="false" 属性;或者换种思路 listview中嵌入gridview,就不会出现无响应事件

[java]  view plain  copy
  1. android:descendantFocusability="blocksDescendants" //viewgroup会覆盖子类控件而直接获得焦点  
  2. android:descendantFocusability="beforeDescendants" //viewgroup会优先其子类控件而获取到焦点    
  3. android:descendantFocusability="afterDescendants"   //viewgroup只有当其子类控件不需要获取焦点时才获取焦点    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值