Skip to content

Commit

Permalink
Fixes the issue that only single line was displayed with nested Recyc…
Browse files Browse the repository at this point in the history
…lerViews

Fixes the issue that only single line was displayed with nested RecyclerViews
where the inner RecycerView's adapter is FlexboxLayoutManager with FlexWrap is
set to wrap.

This was caused because height 0 was passed from the parent RecyclerView
if the layout_height is specified as wrap_content, thus
FlexboxLayoutManager didn't calculate the entire items.

This fixes #290
  • Loading branch information
thagikura committed Jun 15, 2017
1 parent 8217823 commit e1327c8
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 88 deletions.
Expand Up @@ -44,7 +44,7 @@ protected void onCreate(Bundle savedInstanceState) {
setSupportActionBar(toolbar);

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(this);
layoutManager.setFlexWrap(FlexWrap.WRAP);
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setAlignItems(AlignItems.STRETCH);
Expand Down
Expand Up @@ -57,8 +57,8 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

RecyclerView recyclerView = (RecyclerView) view.findViewById(
R.id.recyclerview);
final FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager();
final MainActivity activity = (MainActivity) getActivity();
final FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager(activity);
recyclerView.setLayoutManager(flexboxLayoutManager);
if (mAdapter == null) {
mAdapter = new FlexItemAdapter(activity, flexboxLayoutManager);
Expand Down
Expand Up @@ -67,7 +67,7 @@ public void testFlexLinesDiscardedOnOrientationChange_direction_row() throws Thr
// orientation
// happens with an Activity that handles configuration changes manually
final ConfigChangeActivity activity = mActivityRule.getActivity();
final FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
final FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(activity);
final TestAdapter adapter = new TestAdapter();

mActivityRule.runOnUiThread(new Runnable() {
Expand Down Expand Up @@ -127,7 +127,7 @@ public void testFlexLinesDiscardedOnOrientationChange_direction_column() throws
// orientation
// happens with an Activity that handles configuration changes manually
final ConfigChangeActivity activity = mActivityRule.getActivity();
final FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
final FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(activity);
final TestAdapter adapter = new TestAdapter();

mActivityRule.runOnUiThread(new Runnable() {
Expand Down

Large diffs are not rendered by default.

Expand Up @@ -30,8 +30,11 @@ class NestedInnerAdapter extends RecyclerView.Adapter<NestedInnerAdapter.InnerVi

private int mInnerPosition;

NestedInnerAdapter(int innerPosition) {
private int mItemCount;

NestedInnerAdapter(int innerPosition, int itemCount) {
mInnerPosition = innerPosition;
mItemCount = itemCount;
}

@Override
Expand All @@ -48,7 +51,7 @@ public void onBindViewHolder(InnerViewHolder holder, int position) {

@Override
public int getItemCount() {
return 5;
return mItemCount;
}

static class InnerViewHolder extends RecyclerView.ViewHolder {
Expand Down
Expand Up @@ -16,6 +16,8 @@

package com.google.android.flexbox.test;

import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
Expand All @@ -35,29 +37,40 @@ class NestedOuterAdapter extends RecyclerView.Adapter<NestedOuterAdapter.OuterVi

private static final int ITEM_COUNT = 4;

private final Context mContext;

private final List<OuterViewHolder> mViewHolderList = new ArrayList<>();

private final int mFlexDirection;

NestedOuterAdapter(@FlexDirection int flexDirection) {
private final int mInnerAdapterItemCount;

private final int mViewHolderResId;

NestedOuterAdapter(Context context, @FlexDirection int flexDirection, int innerAdapterItemCount,
@LayoutRes int viewHolderResId) {
mContext = context;
mFlexDirection = flexDirection;
mInnerAdapterItemCount = innerAdapterItemCount;
mViewHolderResId = viewHolderResId;
}

@Override
public NestedOuterAdapter.OuterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.viewholder_inner_recyclerview, parent, false);
.inflate(mViewHolderResId, parent, false);
OuterViewHolder holder = new OuterViewHolder(view);
mViewHolderList.add(holder);
return holder;
}

@Override
public void onBindViewHolder(OuterViewHolder holder, int position) {
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(mContext);
layoutManager.setFlexDirection(mFlexDirection);
holder.mInnerRecyclerView.setLayoutManager(layoutManager);
holder.mInnerRecyclerView.setAdapter(new NestedInnerAdapter(position));
holder.mInnerRecyclerView.setAdapter(new NestedInnerAdapter(position,
mInnerAdapterItemCount));
}

OuterViewHolder getViewHolder(int position) {
Expand Down
Expand Up @@ -17,6 +17,6 @@
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerview_inner"
android:layout_width="wrap_content"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp" />
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2017 Google Inc. All rights reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- The nested RecyclerViews tests verify the wrap_content behavior -->
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerview_inner"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_marginBottom="8dp" />
Expand Up @@ -167,20 +167,22 @@ public class FlexboxLayoutManager extends RecyclerView.LayoutManager implements
*/
private SparseArray<View> mViewCache = new SparseArray<>();

private final Context mContext;

/**
* Creates a default FlexboxLayoutManager.
*/
public FlexboxLayoutManager() {
this(FlexDirection.ROW, FlexWrap.WRAP);
public FlexboxLayoutManager(Context context) {
this(context, FlexDirection.ROW, FlexWrap.WRAP);
}

/**
* Creates a FlexboxLayoutManager with the flexDirection specified.
*
* @param flexDirection the flex direction attribute
*/
public FlexboxLayoutManager(@FlexDirection int flexDirection) {
this(flexDirection, FlexWrap.WRAP);
public FlexboxLayoutManager(Context context, @FlexDirection int flexDirection) {
this(context, flexDirection, FlexWrap.WRAP);
}

/**
Expand All @@ -189,12 +191,13 @@ public FlexboxLayoutManager(@FlexDirection int flexDirection) {
* @param flexDirection the flex direction attribute
* @param flexWrap the flex wrap attribute
*/
public FlexboxLayoutManager(@FlexDirection int flexDirection,
public FlexboxLayoutManager(Context context, @FlexDirection int flexDirection,
@FlexWrap int flexWrap) {
setFlexDirection(flexDirection);
setFlexWrap(flexWrap);
setAlignItems(AlignItems.STRETCH);
setAutoMeasureEnabled(true);
mContext = context;
}

/**
Expand Down Expand Up @@ -233,6 +236,7 @@ public FlexboxLayoutManager(Context context, AttributeSet attrs, int defStyleAtt
setFlexWrap(FlexWrap.WRAP);
setAlignItems(AlignItems.STRETCH);
setAutoMeasureEnabled(true);
mContext = context;
}

// From here, methods from FlexContainer
Expand Down Expand Up @@ -767,17 +771,37 @@ private void updateFlexLines(int childCount) {
int width = getWidth();
int height = getHeight();
boolean isMainSizeChanged;
int needsToFill;
// Clear the flex lines if the main size has changed from the last measurement.
// For example this happens when the developer handles the configuration changes manually
// or the user change the width boundary in the multi window mode.
if (isMainAxisDirectionHorizontal()) {
isMainSizeChanged = mLastWidth != Integer.MIN_VALUE && mLastWidth != width;

// If the mInfinite flag is set to true (that usually happens when RecyclerViews are
// nested and inner RecyclerView's layout_height is set to wrap_content, thus height is
// passed as 0 from the RecyclerView)
// Set the upper limit as the height of the device in order to prevent computing all
// items in the adapter
needsToFill = mLayoutState.mInfinite ?
mContext.getResources().getDisplayMetrics().heightPixels
: mLayoutState.mAvailable;
} else {
isMainSizeChanged = mLastHeight != Integer.MIN_VALUE && mLastHeight != height;

// If the mInfinite flag is set to true (that usually happens when RecyclerViews are
// nested and inner RecyclerView's layout_width is set to wrap_content, thus width is
// passed as 0 from the RecyclerView)
// Set the upper limit as the width of the device in order to prevent computing all
// items in the adapter
needsToFill = mLayoutState.mInfinite ?
mContext.getResources().getDisplayMetrics().widthPixels
: mLayoutState.mAvailable;
}

mLastWidth = width;
mLastHeight = height;

if (mPendingScrollPosition != NO_POSITION || isMainSizeChanged) {
if (mAnchorInfo.mLayoutFromEnd) {
// Prior flex lines should be already calculated, don't have to be updated
Expand All @@ -798,11 +822,11 @@ private void updateFlexLines(int childCount) {
if (isMainAxisDirectionHorizontal()) {
flexLinesResult = mFlexboxHelper
.calculateHorizontalFlexLinesToIndex(widthMeasureSpec, heightMeasureSpec,
mLayoutState.mAvailable, mAnchorInfo.mPosition, mFlexLines);
needsToFill, mAnchorInfo.mPosition, mFlexLines);
} else {
flexLinesResult = mFlexboxHelper
.calculateVerticalFlexLinesToIndex(widthMeasureSpec, heightMeasureSpec,
mLayoutState.mAvailable, mAnchorInfo.mPosition, mFlexLines);
needsToFill, mAnchorInfo.mPosition, mFlexLines);
}
mFlexLines = flexLinesResult.mFlexLines;
mFlexboxHelper.determineMainSize(widthMeasureSpec, heightMeasureSpec);
Expand All @@ -823,12 +847,12 @@ private void updateFlexLines(int childCount) {
mFlexboxHelper.clearFlexLines(mFlexLines, mAnchorInfo.mPosition);
flexLinesResult = mFlexboxHelper
.calculateHorizontalFlexLines(widthMeasureSpec, heightMeasureSpec,
mLayoutState.mAvailable, mAnchorInfo.mPosition, mFlexLines);
needsToFill, mAnchorInfo.mPosition, mFlexLines);
} else {
mFlexboxHelper.ensureIndexToFlexLine(childCount);
flexLinesResult = mFlexboxHelper
.calculateHorizontalFlexLines(widthMeasureSpec, heightMeasureSpec,
mLayoutState.mAvailable, 0, mFlexLines);
needsToFill, 0, mFlexLines);
}
} else {
if (mFlexLines.size() > 0) {
Expand All @@ -837,12 +861,12 @@ private void updateFlexLines(int childCount) {
mFlexboxHelper.clearFlexLines(mFlexLines, mAnchorInfo.mPosition);
flexLinesResult = mFlexboxHelper
.calculateVerticalFlexLines(widthMeasureSpec, heightMeasureSpec,
mLayoutState.mAvailable, mAnchorInfo.mPosition, mFlexLines);
needsToFill, mAnchorInfo.mPosition, mFlexLines);
} else {
mFlexboxHelper.ensureIndexToFlexLine(childCount);
flexLinesResult = mFlexboxHelper
.calculateVerticalFlexLines(widthMeasureSpec, heightMeasureSpec,
mLayoutState.mAvailable, 0, mFlexLines);
needsToFill, 0, mFlexLines);
}
}
mFlexLines = flexLinesResult.mFlexLines;
Expand Down

0 comments on commit e1327c8

Please sign in to comment.