Kotlin RecyclerView в RecyclerView после обновления представления переходит в дочерний RecyclerView - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть RecyclerView внутри RecyclerView. Когда я начинаю свой взгляд, все в порядке. Но когда я обновляю свой RecyclerView (родительский), мое представление автоматически c прокручивается к первому дочернему RecyclerView. Я не вижу элемента в родительском RecyclerView (только TextView). Я не знаю, почему это произошло. Когда я создаю вид в первый раз, все в порядке.

Макет основного вида

<?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"
    tools:context=".ui.EventsListActivity">

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

        <RelativeLayout
            android:id="@+id/top_panel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="20sp"
            android:layout_marginEnd="20sp"
            android:background="@drawable/top_menu_blue">

        </RelativeLayout>

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

    </RelativeLayout>

</RelativeLayout>

это мой элементVIew:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="20sp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_category_name"
        android:textSize="20sp"
        android:clickable="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list_events"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_category_name"
        android:layout_marginTop="10sp" />

</RelativeLayout>

Вот как я ставлю и обновляю главный вид:

private fun initEventsRecyclerView(
    context: Context,
    interaction: EventAdapter.Interaction
) {
    event_categories_list.run {
        eventCategoryAdapter = EventCategoryAdapter(
            eventsListModel.eventList,
            eventsListModel.ticketsList,
            interaction,
            context
        )

        adapter = eventCategoryAdapter

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

И вот как я ставлю на предмет:

itemView.list_events.apply {
    if (eventCategory.eventsList != null) {
        val eventCategoryAdapter = EventAdapter(
            eventCategory,
            eventCategory.eventsList,
            ticketList,
            interaction,
            context
        )
        adapter = eventCategoryAdapter
    }

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

// edit Когда я делаю это для updateView:

eventCategoryAdapter.updateEventsCategoryList(eventsListModel.getFilterEvents(dt.time))
        eventCategoryAdapter.notifyDataSetChanged()

steal прокручивается вниз

// edit

Это основной адаптер:

class EventCategoryAdapter(
    eventsCategoryList: List<EventCategory>,
    ticketList: ArrayList<Ticket>,
    private val interaction: EventAdapter.Interaction? = null,
    val context: Context
) : RecyclerView.Adapter<EventCategoryAdapter.ViewHolder>() {

    private var eventsCategory = mutableListOf<EventCategory>()
    private val ticketListForEvents = ArrayList<Ticket>()

    init {
        eventsCategory.addAll(eventsCategoryList)
        ticketListForEvents.addAll(ticketList)
    }

    fun updateEventsCategoryList(eventsCategoryList: List<EventCategory>){
        eventsCategory = eventsCategoryList as MutableList<EventCategory>
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.event_category_item, parent, false)
        return ViewHolder(
            view
        )
    }

    override fun getItemCount() = eventsCategory.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(eventsCategory[position],ticketListForEvents, context, interaction)
    }


    class ViewHolder(
        itemView: View
    ) : RecyclerView.ViewHolder(itemView) {

        fun bind(
            eventCategory: EventCategory,
            ticketList :ArrayList<Ticket>,
            context: Context,
            interaction: EventAdapter.Interaction?
        ) {
            itemView.tv_category_name.text = eventCategory.name
            itemView.list_events

            itemView.list_events.apply {
                if (eventCategory.eventsList != null) {
                    val eventCategoryAdapter = EventAdapter(
                        eventCategory,
                        eventCategory.eventsList,
                        ticketList,
                        interaction,
                        context
                    )
                    adapter = eventCategoryAdapter
                }

            }
            val linearLayoutManager = LinearLayoutManager(context)
            itemView.list_events.layoutManager = linearLayoutManager
            itemView.list_events.isNestedScrollingEnabled = true
            itemView.list_events.setHasFixedSize(true)
            itemView.list_events.layoutManager =
                LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
        }
    }

}

и это дочерний адаптер:

class EventAdapter(
    private val eventCategory: EventCategory,
    eventsList: List<Event?>,
    ticketList: ArrayList<Ticket>,
    private val interaction: Interaction? = null,
    val context: Context
) : RecyclerView.Adapter<EventAdapter.ViewHolder>() {

    private val events = mutableListOf<Event?>()
    private val ticketListForEvents = ArrayList<Ticket>()

    init {
        events.addAll(eventsList)
        ticketListForEvents.addAll(ticketList)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.event_item, parent, false)
        return ViewHolder(
            view,
            interaction
        )
    }

    override fun getItemCount() = events.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val event = events[position]
        if (event?.id != null)
            holder.bind(
                event,
                eventCategory,
                getTicketsForEvent(event.id, ticketListForEvents),
                context
            )
    }


    class ViewHolder(
        itemView: View,
        private val interaction: Interaction?
    ) : RecyclerView.ViewHolder(itemView) {

        fun bind(
            event: Event,
            eventCategory: EventCategory,
            ticketList: ArrayList<Ticket>?,
            context: Context
        ) {
            val activity = context as AppCompatActivity

            itemView.iv_event_thumbnail.clipToOutline = true

            Glide.with(context)
                .load("${BASE_URL}xxx${event.thumbnail}")
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .override(500,500)
                .into(itemView.iv_event_thumbnail)
            if (ticketList != null && ticketList.size > 0) {
                itemView.ticket_info_panel.visibility = View.VISIBLE
                itemView.iv_ticket_end.visibility = View.VISIBLE
                itemView.tv_ticket_counter.text = ticketList.size.toString()
            } else {
                itemView.ticket_info_panel.visibility = View.GONE
                itemView.iv_ticket_end.visibility = View.GONE
            }
            itemView.tv_event_name.text = event.title
            itemView.tv_event_short_descr.text = event.shortDescription
            itemView.setOnClickListener {
                interaction?.onItemSelected(adapterPosition, event, eventCategory,ticketList)
            }
        }
    }

    interface Interaction {
        fun onItemSelected(
            position: Int,
            event: Event,
            eventCategory: EventCategory,
            ticketList: ArrayList<Ticket>?
        )
    }
}

1 Ответ

1 голос
/ 27 апреля 2020

Лучшим подходом в этом случае является использование RecyclerView с несколькими типами представлений (несколько держателей представлений).

Вы можете создать несколько классов, наследующих один и тот же класс (или реализующих один и тот же интерфейс. Для этого примера я создам 2 из них («имя» и «фотография»):

class NameViewHolder extends RecyclerView.ViewHolder {

    private TextView name;

    NameViewHolder(@NonNull View itemView) {
        super(itemView);
        name = itemView.findViewById(R.id.name_text_view);
    }
}

и

class PhotoViewHolder extends RecyclerView.ViewHolder {

    private ImageView image;

    PhotoViewHolder(@NonNull View itemView) {
        super(itemView);
        image = itemView.findViewById(R.id.image_avatar);
    }
}

Вы должны подготовить номера (позиции) к этим элементам, например:

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

А в вашем адаптере, опираясь на некоторые логи c, возвращаем, какой тип вам нужен. Здесь вы возвращаете "для какой позиции из списка, какой держатель представления"

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

Далее внутри onCreateViewHolder() (в вашем адаптере) вы должны надуть правильную компоновку:

@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);
    }
}

и правильно заполнить их (в 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...