2016-02-18 2 views
2

У меня есть recyclerview, и я устанавливаю адаптер для этого recyclerview. В элементе списка recyclerview у меня есть другой recyclerview.Recyclerview с GridLayout Manager внутри другого recycerview

Я дал layout_height для внутреннего Recylerview как wrap_content. Теперь я настраиваю GridLayoutManager на этот recyclerview, но содержимое этого recyclerview становится невидимым.

Я попытался настроить CustomLinearLayout-менеджер на этот recyclerview, и это работает нормально. Я попытался найти настраиваемый GridLayoutManager, чтобы установить это в Recyclerview, но я не могу найти такую ​​документацию, которая дает мне настраиваемый менеджер GridLayout, такой как CustomLinearLayout Manger.

Прошу вас, если кто-нибудь знает, как установить GridLayoutManager на Recyclerview, который находится внутри другого recyclerview.

Большое спасибо в продвинутом виде.

ответ

1

Пожалуйста, пройти через это я сделал это обычай, согласно моему требованию:

DO некоторые хитрости для вашего требования

public class WrapHorizontalGridLayoutManager extends GridLayoutManager { 

    private static boolean canMakeInsetsDirty = true; 
    private static Field insetsDirtyField = null; 

    private static final int CHILD_WIDTH = 0; 
    private static final int CHILD_HEIGHT = 1; 
    private static final int DEFAULT_CHILD_SIZE = 100; 

    private final int[] childDimensions = new int[2]; 
    private RecyclerView view; 

    private int childSize = DEFAULT_CHILD_SIZE; 
    private boolean hasChildSize; 
    private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS; 
    private final Rect tmpRect = new Rect(); 
    private final int spanCount; 

    private int[] mMeasuredDimension = new int[2]; 


    public WrapHorizontalGridLayoutManager(RecyclerView view, int spanCount, int orientation, boolean reverseLayout) { 
     super(view.getContext(), spanCount, orientation, reverseLayout); 
     this.spanCount=spanCount; 
     this.view = view; 
     this.overScrollMode = ViewCompat.getOverScrollMode(view); 
    } 



    public void setOverScrollMode(int overScrollMode) { 
     if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER) 
      throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode); 
     if (this.view == null) throw new IllegalStateException("view == null"); 
     this.overScrollMode = overScrollMode; 
     ViewCompat.setOverScrollMode(view, overScrollMode); 
    } 

    public static int makeUnspecifiedSpec() { 
     return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 
    } 

    @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); 

     final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED; 
     final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED; 

     final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY; 
     final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY; 

     final int unspecified = makeUnspecifiedSpec(); 

     if (exactWidth && exactHeight) { 
      // in case of exact calculations for both dimensions let's use default "onMeasure" implementation 
      super.onMeasure(recycler, state, widthSpec, heightSpec); 
      return; 
     } 

     final boolean vertical = getOrientation() == VERTICAL; 

     initChildDimensions(widthSize, heightSize, vertical); 

     int width = 0; 
     int height = 0; 

     // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This 
     // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the 
     // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never 
     // called whiles scrolling) 
     recycler.clear(); 

     final int stateItemCount = state.getItemCount(); 
     final int adapterItemCount = getItemCount(); 
     // adapter always contains actual data while state might contain old data (f.e. data before the animation is 
     // done). As we want to measure the view with actual data we must use data from the adapter and not from the 
     // state 

     int loopOverAdapeterItemCount = (adapterItemCount % 2 == 1) ? adapterItemCount + 1 : adapterItemCount; 

     for (int i = 0; i <loopOverAdapeterItemCount/2; i++) { 
      if (vertical) { 
       if (!hasChildSize) { 

        if (i < stateItemCount) { 
         // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items 
         // we will use previously calculated dimensions 
         measureChild(recycler, i, widthSize, unspecified, childDimensions); 
        } else { 
         logMeasureWarning(i); 
        } 
       } 
       height += childDimensions[CHILD_HEIGHT]; 
       if (i == 0) { 
        width = childDimensions[CHILD_WIDTH]; 
       } 
       if (hasHeightSize && height >= heightSize) { 
        break; 
       } 

      } else { 
       if (!hasChildSize) { 
        if (i < stateItemCount) { 
         // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items 
         // we will use previously calculated dimensions 
         measureChild(recycler, i, unspecified, heightSize, childDimensions); 
        } else { 
         logMeasureWarning(i); 
        } 
       } 
       width += childDimensions[CHILD_WIDTH]; 
       if (i == 0) { 
        Log.e("spanCount ",spanCount+" "); 
        height = childDimensions[CHILD_HEIGHT]*spanCount; 
       } 
       if (hasWidthSize && width >= widthSize) { 
        break; 
       } 
      } 
     } 

     if (exactWidth) { 
      width = widthSize; 
     } else { 
      width += getPaddingLeft() + getPaddingRight(); 
      if (hasWidthSize) { 
       width = Math.min(width, widthSize); 
      } 
     } 

     if (exactHeight) { 
      height = heightSize; 
     } else { 
      height += getPaddingTop() + getPaddingBottom(); //TODO adjacement 
      if (hasHeightSize) { 
       height = Math.min(height, heightSize); 
      } 
     } 

     setMeasuredDimension(width, height); 

     if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) { 
      final boolean fit = (vertical && (!hasHeightSize || height < heightSize)) 
        || (!vertical && (!hasWidthSize || width < widthSize)); 

      ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS); 
     } 
    } 

    private void logMeasureWarning(int child) { 
     if (BuildConfig.DEBUG) { 
      Log.w("LinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." + 
        "To remove this message either use #setChildSize() method or don't run RecyclerView animations"); 
     } 
    } 

    private void initChildDimensions(int width, int height, boolean vertical) { 
     if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) { 
      // already initialized, skipping 
      return; 
     } 
     if (vertical) { 
      childDimensions[CHILD_WIDTH] = width; 
      childDimensions[CHILD_HEIGHT] = childSize; 
     } else { 
      childDimensions[CHILD_WIDTH] = childSize; 
      childDimensions[CHILD_HEIGHT] = height; 
     } 
    } 

    @Override 
    public void setOrientation(int orientation) { 
     // might be called before the constructor of this class is called 
     //noinspection ConstantConditions 
     if (childDimensions != null) { 
      if (getOrientation() != orientation) { 
       childDimensions[CHILD_WIDTH] = 0; 
       childDimensions[CHILD_HEIGHT] = 0; 
      } 
     } 
     super.setOrientation(orientation); 
    } 

    public void clearChildSize() { 
     hasChildSize = false; 
     setChildSize(DEFAULT_CHILD_SIZE); 
    } 

    public void setChildSize(int childSize) { 
     hasChildSize = true; 
     if (this.childSize != childSize) { 
      this.childSize = childSize; 
      requestLayout(); 
     } 
    } 

    private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) { 
     final View child; 
     try { 
      child = recycler.getViewForPosition(position); 
     } catch (IndexOutOfBoundsException e) { 
      if (BuildConfig.DEBUG) { 
       Log.w("LinearLayoutManager", "LinearLayoutManager doesn't work well with animations. Consider switching them off", e); 
      } 
      return; 
     } 

     final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams(); 

     final int hPadding = getPaddingLeft() + getPaddingRight(); 
     final int vPadding = getPaddingTop() + getPaddingBottom(); 

     final int hMargin = p.leftMargin + p.rightMargin; 
     final int vMargin = p.topMargin + p.bottomMargin; 

     // we must make insets dirty in order calculateItemDecorationsForChild to work 
     makeInsetsDirty(p); 
     // this method should be called before any getXxxDecorationXxx() methods 
     calculateItemDecorationsForChild(child, tmpRect); 

     final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child); 
     final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child); 

     final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally()); 
     final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically()); 

     child.measure(childWidthSpec, childHeightSpec); 

     dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin; 
     dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin; 

     // as view is recycled let's not keep old measured values 
     makeInsetsDirty(p); 
     recycler.recycleView(child); 
    } 

    private static void makeInsetsDirty(RecyclerView.LayoutParams p) { 
     if (!canMakeInsetsDirty) { 
      return; 
     } 
     try { 
      if (insetsDirtyField == null) { 
       insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty"); 
       insetsDirtyField.setAccessible(true); 
      } 
      insetsDirtyField.set(p, true); 
     } catch (NoSuchFieldException e) { 
      onMakeInsertDirtyFailed(); 
     } catch (IllegalAccessException e) { 
      onMakeInsertDirtyFailed(); 
     } 
    } 

    private static void onMakeInsertDirtyFailed() { 
     canMakeInsetsDirty = false; 
     if (BuildConfig.DEBUG) { 
      Log.w("LinearLayoutManager", "Can't make LayoutParams insets dirty, decorations measurements might be incorrect"); 
     } 
    } 


} 
+0

Это работает отлично, спасибо так много. Еще один вопрос, который я хочу задать, заключается в том, что, поскольку я использую Recyclerview с gridLayoutManager, я использую этот recyclerview для отображения изображений в сетке. Теперь я хочу показывать изображения с переменной длиной от промежутков. Нравится, если у меня 1 фотография, мне нужно показать только одну строку и одну колонку. Если есть 2 фотографии: Будет показано 2 фотографии с одинаковой шириной каждой фотографии. Если у вас 3: я хочу показать 2 строки. В 1-й строке будет показано 1 изображение полной ширины, а во 2-й строке будет отображаться 2 изображения полуширины. Я также проверил метод getSpanSize, но он дает мне размер диапазона на определенном pos. –

+0

Прошу проголосовать и принять :), если у вас есть другой вопрос, отправьте его отдельно –

Смежные вопросы