The task is to display the list "treeResult" in RecyclerView, and by clicking on the list item, another list should be displayed "treeResult.getSubChildrens ()", which may consist of a previously unknown number of elements.

To solve the problem, I used ExpandableRelativeLayout (by clicking on it, it shifts the elements under itself, displaying its own content) and implemented the method of dynamically adding elements to the parent container located in ExpandableRelativeLayout.

There was the following problem, when you start the application, all the data is in place and displayed correctly. But if you scroll down the list, open some ExpandableRelativeLayout and go back, you may find that the display of elements has become incorrect (somewhere instead of three elements two are displayed, and empty artifacts appear somewhere).

As far as I am allowed to judge the knowledge of how RecyclerView works, the error is in the bindCrime method of the ViewHolder class. But I can not solve the problem. If you remove "container.removeAllView", then the child elements are already beginning to change places in a chaotic manner, when using this method, they at least remain in place.

Visual description of the current state of the application:

  1. The application is just running, click on the elements of the list. Everything is correct.
  2. Scroll to the bottom down, and we see that the last element opened by itself + it contains only two elements, but the space is allocated for three.
  3. Scroll up to the end, the correct display is broken, instead of three elements only two are displayed (and during the debag method "addChildView" is executed three times, as it should be). enter image description here

PS I think that the "setIsRecyclable (false)" method is not a solution, since RecyclerView speed is significantly reduced.

Adapter code:

public class AdapterRecycler extends 

RecyclerView.Adapter {

 private ArrayList<RootJsonObject> treeResult; private Context context; public AdapterRecycler(ArrayList<RootJsonObject> treeResult) { this.treeResult = treeResult; } @Override public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) { this.context = parent.getContext(); return new ViewHolder(LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_recycle_view, parent, false)); } @Override public void onBindViewHolder(final ViewHolder holder, final int position) { final RootJsonObject rootTree = treeResult.get(position); holder.bindCrime(rootTree); } @Override public int getItemCount() { return treeResult.size(); } class ViewHolder extends RecyclerView.ViewHolder { private TextView textView; private LinearLayout rootContainer; private ExpandableRelativeLayout expandableRelativeLayout; private LinearLayout container; public ViewHolder(View itemView) { super(itemView); textView = (TextView) itemView.findViewById(R.id.textView); rootContainer = (LinearLayout) itemView.findViewById(R.id.rootContainer); expandableRelativeLayout = (ExpandableRelativeLayout) itemView.findViewById(R.id.expandableLayout); expandableRelativeLayout.toggle(); container = (LinearLayout)expandableRelativeLayout .findViewById(R.id.containerContent); rootContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { expandableRelativeLayout.toggle(); } }); } public void bindCrime(RootJsonObject rootTree) { textView.setText(rootTree.getTitle()); container.removeAllViews(); // если не удалять старые View, // то они начинают перемешиваться друг с другом if (rootTree.getSubChildrens() != null) { Iterator<RootJsonObject.SubChildren> iterator = rootTree.getSubChildrens().iterator(); while (iterator.hasNext()) { RootJsonObject.SubChildren subChildren = iterator.next(); int id = subChildren.getId(); String title = subChildren.getTitle(); addChildView(container, id, title); } } } private void addChildView(LinearLayout container, int id, String title) { View childView = LayoutInflater.from(context) .inflate(R.layout.item_expandable_layout, null, false); TextView tvId = (TextView) childView.findViewById(R.id.text_id); TextView tvTitle = (TextView) childView.findViewById(R.id.text_title); tvId.setText(String.valueOf(id)); tvTitle.setText(title); //для наглядности подкрашиваем созданные View Random rand = new Random(); childView.setBackgroundColor(Color.rgb(rand.nextInt(200), rand.nextInt(200), rand.nextInt(200))); container.addView(childView); } } 

}

Markup code for the RecyclerView element:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/rootContainer" android:padding="@dimen/item_recycle_padding" tools:background="@android:color/holo_orange_dark"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="@dimen/item_recycle_height" android:padding="@dimen/item_recycle_padding" tools:background="@android:color/holo_orange_dark"> <ImageView android:layout_width="60dp" android:layout_height="match_parent" android:src="@drawable/ic_folder"/> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Test" android:gravity="center" tools:background="@android:color/holo_red_dark"/> </LinearLayout> <com.github.aakira.expandablelayout.ExpandableRelativeLayout android:id="@+id/expandableLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/textView" android:orientation="vertical" android:background="@android:color/darker_gray" app:ael_duration="300" app:ael_expanded="false"> <LinearLayout android:id="@+id/containerContent" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"/> </com.github.aakira.expandablelayout.ExpandableRelativeLayout> 

    1 answer 1

    As you know, the view in RecyclerView reused during scrolling, which leads to such errors. To prevent elements from being opened / closed arbitrarily during scrolling, you need to save the state of each element and restore it during binding. For example, as done in the example of the library you are using:

     private SparseBooleanArray expandState = new SparseBooleanArray(); ... @Override public void onBindViewHolder(final ViewHolder holder, final int position) { ... holder.expandableLayout.setExpanded(expandState.get(position)); ... } 

    At the expense of solving the second problem, with the size of the drop-down element, I'm not sure, but it is possible that the explicit installation of LayoutParams during the binding process can help, so that the size recalculates again:

     RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT) container.setLayoutParams(params); 

    But if I were you, I would go the other way. Since you decided to use the library, it is better to try one of those created specifically for your task ExpandableRecyclerView . There are plenty of them today.

    • Unfortunately, explicit installation of LayoutParams did not solve the problem of the size of the parent element. But I thank for the answer, now I will look towards special libraries. - NeXuS525
    • There is another option to set the exact size of the parent element. That is, take the height of one child, multiply by their number and set in LayoutParams instead of WRAP_CONTENT - eugeneek
    • I tried this option. Anyway, if you open a lot of tabs, then errors in the size of the parent container begin. All as in the screenshots above. - NeXuS525