Recyclerview with setVisibility GONE does not delete space from the row

2

In a fragment I have a list ( RecyclerView ) that comes from a Content Provider (SQLite). I want row 2 not to show, so within onBindViewHolder of the Adapter, set setVisibility(View.GONE) to position 1 (which is row num 2), and effectively it does not show it but it shows the space occupied by that row, it is as if it had been configured setVisibility(View.INVISIBLE) :

   @Override
   public void onBindViewHolder(ViewHolder holder, int position) {
    cursor.moveToPosition(position);

    if(position ==1){  
        holder.itemView.setVisibility(View.GONE);
    }else {
        holder.itemView.setVisibility(View.VISIBLE);
    }

    String p = cursor.getString(cursor.getColumnIndex(PrimerContract.COLUMN_POSICION));
    String it = cursor.getString(cursor.getColumnIndex(PrimerContract.COLUMN_ITEM));
    String mId = cursor.getString(cursor.getColumnIndex(PrimerContract._ID));

    holder.mText1.setText("card "+position+"\n"+" id  "+mId);
    holder.mText2.setText(p);
    holder.mText3.setText(it);
  }

It looks like this with View.GONE and with View.INVISIBLE :

How can you eliminate that space?

The xml of the item:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/row"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<TextView
    android:id="@+id/textView01"
    android:layout_width="52dp"
    android:layout_height="27dp"
    android:layout_marginLeft="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="01"
    android:textSize="10sp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/textView02"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="00"
    android:textSize="18sp"
    app:layout_constraintStart_toEndOf="@+id/textView01"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/textView03"
    android:layout_width="wrap_content"
    android:layout_height="23dp"
    android:layout_marginLeft="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:text="Text"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/textView02"
    app:layout_constraintTop_toTopOf="parent" />

With this RecyclerView you can modify the SQlite table that also feeds a spinner, like this:

    String selection = PrimerContract.COLUMN_GRUPO + "=?";
    String[] selectionArgs = new String[]{"items"};
    Cursor cursor = getActivity().getContentResolver().query(PrimerContract.CONTENT_URI, null, selection, selectionArgs, PrimerContract._ID);                                                                                                      
    String[] fromColumns = {PrimerContract.COLUMN_ITEM};  // lo que va mostrar el spinner
    int[] toViews = {android.R.id.text1};

        adapter = new SimpleCursorAdapter(getContext(), android.R.layout.simple_spinner_item, cursor, fromColumns, toViews, 0);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);

You can add, edit or delete items  except for item 1 (sqlite id 1, it can be edited but not deleted) and 2 (sqlite id2, should not be edited or deleted). That's why I want the id2, which in the RecyclerView is row 1, not shown, on the spinner if it will be displayed.

That RecyclerView is loaded with a cursor loader:

 @Override
   public Loader<Cursor> onCreateLoader(int id, Bundle args) {
     return new CursorLoader(getActivity(), PrimerContract.CONTENT_URI, null, null, null, PrimerContract._ID);     
}  

Another Solution:

What I want is that it does not show what is in the database sqlite row 2 (id 2) that in the Recyclerview remains in row 2 (position 1). The solution that @Andrespengineer gives is perfect: it does not show row 2 of the Recyclerview and there is no space left. Another solution is to show all the rows of the RecyclerView but none of them show the id 2 of the SQlite. This is achieved by modifying the Cursor Loader in this way:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = new String[]{PrimerContract.COLUMN_ITEM, PrimerContract.COLUMN_POSICION, PrimerContract.COLUMN_GRUPO, PrimerContract._ID};
String selection = PrimerContract._ID + " NOT IN (?)";    // de esta columna no quiero que muestre
String[] selectionArgs = new String[]{"2"};               // el id 2
return new CursorLoader(getActivity(), PrimerContract.CONTENT_URI, projection, selection, selectionArgs, PrimerContract._ID);
    
asked by armen 03.08.2018 в 22:27
source

1 answer

2

The problem in doing setVisibility a Gone , is that the frame of the item was already drawn, because it was called onCreateViewHolder and is taking a space in the RecyclerView . What you should do is change the parameters of the view and return its height to zero. This will make that view disappear. But as in onBindViewHolder these views will be recycled. You must return it to its original state.

In the holder class you should do:

private final View itemView;

In your constructor:

{
. . .
   this.itemView = itemView;
. . .
}

Create the methods:

public void hideView(){
    /*Tipo del layout padre*/.LayoutParams parameters = new /*Tipo del layout padre*/.LayoutParams(/*Width declarado en tu layout*/, 0);
    this.itemView.setLayoutParams(parameters);

}

public void resetView(){
    /*Tipo del layout padre*/.LayoutParams parameters = new /*Tipo del layout padre*/.LayoutParams(/*Width original definido en tu layout*/, /*Height original definido en tu layout*/);
    this.itemView.setLayoutParams(parameters);
}

Note: for both the Width and the Height in the parameters you can assign: ViewGroup.LayoutParams.MATCH_PARENT or ViewGroup.LayoutParams.WRAP_CONTENT as you have defined in the Layout of your Item, if You did not define a fixed size. Whereas with the type of Layout father I mean:

  • LinearLayout
  • FrameLayout
  • RelativeLayout

etc ... The one you have as a parent in the Layout of the Items.

In onBindViewHolder then do the following:

if(/*condicion*/) 
    holder.hideView();
else
    holder.resetView();

Important

If you have any additional rules regarding the defined Layout, say for example: orientation , margin , gravity , etc ... You must define it in the LayoutParams of the metodos creados as well. Otherwise, you will be assigned only the size of the view, but not those properties. LayoutParams has methods that help you define all those properties in code. If you want to clone the properties that you have already defined and save it in a variable you can define an onLayoutChangeListener and remove it when assigning them. So you only have to match it to those properties in resetView(); .

    
answered by 03.08.2018 / 23:57
source