Android: перенести вид из родительского в другой - PullRequest
0 голосов
/ 01 апреля 2020

Я пришел сюда, чтобы помочь, так как я совсем не понимаю, мой код не работает. Чтобы быть быстрым, моя цель состоит в том, чтобы "перезагрузить" представление, которое представляет элемент списка. Так как мой элемент списка может содержать другие элементы списка в его дочерних элементах, я хочу надувать новый элемент списка, а затем перенести эти дочерние элементы из старого в новый.

Я получаю "Указанный дочерний элемент уже имеет родителя. Вы должны сначала вызвать removeView () для родителя ребенка. " ошибка, но я вызываю removeView на родительском объекте ребенка (как-то это не работает) (см. мой код после)

Вот как устроен мой макет (я удаляю некоторые строки, чтобы для чтения):

<?xml version="1.0" encoding="utf-8"?>
 <layout 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">

    <data>
        <variable
            name="mainListItem"
            type="com.plg.lirs.data.LirsDataEntity" />
    </data>

    <LinearLayout android:id="@+id/main_list_item_global_layout">

        <LinearLayout android:id="@+id/main_list_item_parent_layout"
            app:mainListItemParentLayout="@{mainListItem}">

        <!-- contains a bunch of views and stuff, nothing important here -->

        </LinearLayout>

        <LinearLayout android:id="@+id/main_list_item_children_layout"
            android:animateLayoutChanges="true">

        <!-- here are all the children i want to transfer, all the children here are inflated from this layout -->

        </LinearLayout>

    </LinearLayout>

</layout>

Теперь вот мой код для раздувания этого макета:

/* entity is just a logical class that contains my data
olderView is the old view representing the old list item */
private fun inflateItem(entity: LirsDataEntity, olderView: View? = null) : View {
        val itemBinding = DataBindingUtil.inflate<MainListItemBinding>(inflater, R.layout.main_list_item, null, false, null)
       // the itemBinding.root will be added into the parent's children layout later on, after this function
       // + i've tried with true as attachToParent, doesn't change

       /* HERE is the core of the problem. My goal is : if an olderView is provided, then transfer the children from the old one to the new one */
        if(olderView != null) {
            val olderChildrenLayout = olderView.findViewById<LinearLayout>(R.id.main_list_item_children_layout) // here is the LinearLayout that contains the children
            val children = olderChildrenLayout.children
            children.forEach {
                olderChildrenLayout.removeView(it) // remove the children from the old parent
                itemBinding.mainListItemChildrenLayout.addView(it) // add it to the new parent
                // at this point i get the error
            }
        }

        entity.ui.reset() // not important here
        itemBinding.mainListItem = entity 

        /* some listeners are set here */

        return itemBinding.root
    }

Спасибо за чтение!

1 Ответ

0 голосов
/ 02 апреля 2020

Я узнаю, что было не так. При вызове removeView () android пытается его анимировать, помещая дочерний вид в переменную, содержащую дочерние элементы, которые в данный момент анимируются. Затем, при попытке изменить родительский вид дочернего представления (который мы хотим иметь нулевое значение), он проверяет, анимируется ли текущее представление. Как это верно, родитель не меняется (пока, по крайней мере, я не знаю, будет ли он изменен позже). Вот почему мы не можем вызвать addView ().

Решение состоит в том, чтобы сохранить класс LayoutTransition, затем установить для него значение null, выполнить передачу и затем сбросить ее. Он не оживит детей, но, по крайней мере, сработает.

Вот небольшой фрагмент кода, который заставит это работать:

public class JavaUtils {
    public static void transferChildren(@NotNull final ViewGroup depart, @NotNull final ViewGroup arrival) {
        LayoutTransition transition = depart.getLayoutTransition();
        depart.setLayoutTransition(null);
            while(depart.getChildCount() > 0) {
            View c = depart.getChildAt(0);
            depart.removeViewAt(0);
            arrival.addView(c);
        }
        depart.setLayoutTransition(transition);
    }
}

И для Kotlin пользователей:

fun ViewGroup.transferChildrenTo(arrival: ViewGroup) {
    val transition: LayoutTransition = layoutTransition
    layoutTransition = null
    while (childCount > 0) {
        val c: View = getChildAt(0)
        removeViewAt(0)
        arrival.addView(c)
    }
    layoutTransition = transition
}
...