Ramotion/folding-cell-android

java.lang.IllegalArgumentException: width and height must be > 0 in RecyclerView

Vijaykumarj opened this issue · 8 comments

I am using folding cell in RecyclerView.

My FoldingCell click view setup in RecyclerAdapter like below:

mViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@OverRide
public void onClick(View v) {
((FoldingCell) v).toggle(false);
// register in adapter that state for selected cell is toggled
contentAdapter.registerToggle(mViewHolder.getAdapterPosition());
}

I get following error whenever scroll up or scroll down & that Item is not visible in RecyclerView.

Java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:1001)
at android.graphics.Bitmap.createBitmap(Bitmap.java:968)
at android.graphics.Bitmap.createBitmap(Bitmap.java:918)
at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
at com.ramotion.foldingcell.FoldingCell.measureViewAndGetBitmap(FoldingCell.java:346)
at com.ramotion.foldingcell.FoldingCell.unfold(FoldingCell.java:121)
at com.ramotion.foldingcell.FoldingCell.toggle(FoldingCell.java:224)
at com.test.$ContentAdapter.onBindViewHolder(AFragment.java:409)
at com.test..AFragment$ContentAdapter.onBindViewHolder(AFragment.java:252)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6354)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6387)
at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5343)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5606)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5448)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5444)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)
at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1325)
at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1061)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4734)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:778)
at android.view.Choreographer.doFrame(Choreographer.java:710)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6809)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

My requirement is, want to show previous folding cell state (either folded / unfolded) when ever data set is changed or scroll up or scroll down.

I am using Android Studio 3.0 & Folding Cell 1.2.1

Thanks in advance.

I feel your pain. I have been experiencing this since the beginning of time! This is what I'm trying in onBindViewHolder():

switch (itineraryItem.getType()) {
    case ItineraryItem.TYPE_TIME:
            itineraryItemViewHolder.time_foldingcell.setVisibility(View.VISIBLE);
            itineraryItemViewHolder.dist_foldingcell.setVisibility(View.GONE);

            if (unfoldedIndexes.contains(position) && !itineraryItemViewHolder.time_foldingcell.isUnfolded()) {
                        itineraryItemViewHolder.time_foldingcell.unfold(true);
            } else if(!unfoldedIndexes.contains(position) && itineraryItemViewHolder.time_foldingcell.isUnfolded()) {
                itineraryItemViewHolder.time_foldingcell.fold(true);
            }

            break;
        default:
            itineraryItemViewHolder.dist_foldingcell.setVisibility(View.VISIBLE);
            itineraryItemViewHolder.time_foldingcell.setVisibility(View.GONE);

            if (unfoldedIndexes.contains(position) && !itineraryItemViewHolder.dist_foldingcell.isUnfolded()) {
                itineraryItemViewHolder.dist_foldingcell.unfold(true);
            } else if(!unfoldedIndexes.contains(position) && itineraryItemViewHolder.dist_foldingcell.isUnfolded()) {
                itineraryItemViewHolder.dist_foldingcell.fold(true);
            }
            break;
    }

It always gives me the same error when I use the fold() or unfold() method:

java.lang.IllegalArgumentException: width and height must be > 0 at android.graphics.Bitmap.createBitmap(Bitmap.java:969) at android.graphics.Bitmap.createBitmap(Bitmap.java:948) at android.graphics.Bitmap.createBitmap(Bitmap.java:915) at com.ramotion.foldingcell.FoldingCell.measureViewAndGetBitmap(FoldingCell.java:346) at com.ramotion.foldingcell.FoldingCell.unfold(FoldingCell.java:121) at com.ramotion.foldingcell.FoldingCell.toggle(FoldingCell.java:224)

As you can see - it's open source library and you can suggest your own solution for this issue if no one can help. Exception message can give you initial "where to start" information. So all in your hands.

I agree @oleg-vasiliev I like this library, wish I did have the time to debug this and make a pull req.

When I was facing this problem, it was because I was setting the visibility gone on the wrong view.
The visibility gone should be on the cell_content_view. Don't know if anyone have done the same mistake, but maybe it helps someone.

@oleg-vasiliev
I'm facing this issue too after i've updated from 1.0.1 to 1.2.2, i believe that the problem may be:

// make bitmaps from title and content views
Bitmap bitmapFromTitleView = measureViewAndGetBitmap(titleView, this.getMeasuredWidth());
Bitmap bitmapFromContentView = measureViewAndGetBitmap(contentView, this.getMeasuredWidth());
if (skipAnimation) {
contentView.setVisibility(GONE);
titleView.setVisibility(VISIBLE);
FoldingCell.this.mAnimationInProgress = false;
FoldingCell.this.mUnfolded = false;
this.getLayoutParams().height = titleView.getHeight();
} else {
// create empty layout for folding animation
final LinearLayout foldingLayout = createAndPrepareFoldingContainer();
// add that layout to structure
this.addView(foldingLayout);

I'm my case, i'm calling unfold(true) and the measureViewAndGetBitmap calls throw this exception, but they will not be used if i choose to skip animation... so for MY CASE the problem would be solved moving those lines to the else branch that they will be needed (skip animation false)
Also, i've noticed that calling getParent() for the folding cell returns null.. and that may be why the measures return 0 and we get the exception

I'm inflating the view this way :
(FoldingCell) inflater.inflate(R.layout.view_order_list_item, parent, false);
and calling the unfold after, i can't change the attachToView to true because addView(View, LayoutParams) is not supported in AdapterView

Ah, and if its useful, i'm using a ArrayAdapterand not a RecyclerView


My temp solution is

if(cell.getParent() != null){
   cell.unfold(true);
} else {
  //Lay down, try not cry, cry a lot if you need the cell unfolded.
}

I forked this project and made my fixes. They didn't work :/ . So i looked more deep to find out why the measures were all 0, i changed my content_layout visibility from gone to visible and the measures worked (also, the exception was gone too), but in the RecyclerView we need the content to be specifically gone. I've looked at the project code and this:

// hide title and content views
titleView.setVisibility(GONE);
contentView.setVisibility(GONE);
// Measure views and take a bitmaps to replace real views with images
Bitmap bitmapFromTitleView = measureViewAndGetBitmap(titleView, this.getMeasuredWidth());
Bitmap bitmapFromContentView = measureViewAndGetBitmap(contentView, this.getMeasuredWidth());

Was weird, how the view can be measured if it's visibility is GONE?
I did moved the measureViewAndGetBitmap calls to the else branch to get rid of the exception, so this part alone was supposed to work because the of the contentView.setVisibility(VISIBLE);:

if (skipAnimation) {
contentView.setVisibility(VISIBLE);
FoldingCell.this.mUnfolded = true;
FoldingCell.this.mAnimationInProgress = false;
this.getLayoutParams().height = contentView.getHeight();
} else {

But it didn't, contentView.getHeight(); still returns 0.
And that's it, i didn't looked any further into the lib.

But I found a solution for my case, and here it is:

  @Override
  public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    Model model = items.get(position);
    bindModel(model);

    if (model.shouldBeUnfolded) {
      // Find the content layout
      View content = holder.foldingCell.findViewById(R.id.content_layout);
      // "marks" the content to be visible.
      content.setVisibility(View.VISIBLE);
     
      //"schedule" a fold/unfold AFTER the view HAS measurable height
      holder.foldingCell.post(() -> {
        holder.foldingCell.unfold(true);
      });
    }
  }

Hello, guys. We couldn't reproduce this issue. If there is some custom behavior you want to achieve, you're welcome to fork this lib and apply any customization you need.

this happens when you put include into framelayout

<com.ramotion.foldingcell.FoldingCell
        android:id="@+id/folding_cell"
        folding-cell:backSideColor="#000"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <FrameLayout
            android:id="@+id/cell_content_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone">

            <include layout="@layout/cell_content_layout" />

        </FrameLayout>

        <FrameLayout
            android:id="@+id/cell_title_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <include layout="@layout/cell_title_layout" />

        </FrameLayout>

    </com.ramotion.foldingcell.FoldingCell>


</LinearLayout>

remove the frame layout and do this if you are using include

<com.ramotion.foldingcell.FoldingCell xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:folding-cell="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    folding-cell:additionalFlipsCount="2"
    folding-cell:animationDuration="1300"
    folding-cell:backSideColor="@color/bgBackSideColor"
    folding-cell:cameraHeight="30">

    <!-- CONTENT (UNFOLDED) LAYOUT (MUST BE AT LEAST 2x times BIGGER than content layout bellow)-->
    <include layout="@layout/cell_content_layout" />

    <!-- TITLE (FOLDED) LAYOUT (MUST BE AT LEAST 2x times SMALLER than content layout above) -->
    <include layout="@layout/cell_title_layout" />

</com.ramotion.foldingcell.FoldingCell>