Search code examples
androidkotlinandroid-recyclerview

Kotlin RecyclerView in RecyclerView after update a view is going to child RecyclerView


I have a RecyclerView inside a RecyclerView. When I init my view everything is ok and fine. But when I update my RecyclerView (parent) my view is automatic scroll to first child RecyclerView I do not see an item in parent RecyclerView (is only a TextView). I do not know why it happend. When I create a view for first time all is ok.

Layout of main view

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

     

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/top_panel"
            android:layout_marginTop="20sp" />

    </RelativeLayout>

</RelativeLayout>

This is how I put and update a main view:

private fun initRecyclerView(
    context: Context,
    interaction: TestAdapter.Interaction
) {
    rvList.run {
        testAdapter= TestAdapter(
       
            context
        )

        adapter = testAdapter

        isNestedScrollingEnabled = true
        setHasFixedSize(true)
        layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
    }
}

And this is how I put on item :

itemView.rvList.apply {
        val testAdapter= TestAdapter(
            context
        )
        adapter = testAdapter
    

    layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
    isNestedScrollingEnabled = true
    setHasFixedSize(true)
}

Solution

  • The best approach in this case is to use RecyclerView with multiple view type (multiple view holder).

    You can create multiple classes inheriting same class (or implementing same interface. For this example I will create 2 of them ("name" and "photo"):

    class NameViewHolder extends RecyclerView.ViewHolder {
    
        private TextView name;
    
        NameViewHolder(@NonNull View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name_text_view);
        }
    }
    

    and

    class PhotoViewHolder extends RecyclerView.ViewHolder {
    
        private ImageView image;
    
        PhotoViewHolder(@NonNull View itemView) {
            super(itemView);
            image = itemView.findViewById(R.id.image_avatar);
        }
    }
    

    You have to prepare numbers (positions) to those items, e.g.:

    private static int TYPE_NAME = 1;
    private static int TYPE_PHOTO = 2;
    

    And in your adapter, base on some logic return which type do you need. Here you are returning "for which position from list, which view holder"

    @Override
    public int getItemViewType(int position) {
        // Add here your logic!
        if (people.get(position).hasPhoto()) {
            return TYPE_PHOTO;
        } else {
            return TYPE_NAME;
        }
    }
    

    Next inside onCreateViewHolder() (in your adapter) you have to inflate proper layout:

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        View view;
        if (viewType == TYPE_PHOTO) {
            view = LayoutInflater.from(context).inflate(R.layout.item_photo, viewGroup, false);
            return new PhotoViewHolder(view);
    
        } else { // for email layout
            view = LayoutInflater.from(context).inflate(R.layout.item_name, viewGroup, false);
            return new NameViewHolder(view);
        }
    }
    

    And fill them properly (in onBindViewHolder()):

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
        Person person = people.get(position);
    
        if (getItemViewType(position) == TYPE_PHOTO) {
            ((PhotoViewHolder) viewHolder).bind(person);
        } else {
            ((NameViewHolder) viewHolder).bind(person);
        }
    }