Najpierw wywołaj metodę removeView () na rodzicu dziecka


138

Najpierw małe tło:

Mam układ w przewijanym widoku. Na początku, gdy użytkownik przewija ekran, przewija się widok scrollview. Jednak po pewnym czasie przewijania musiałem wyłączyć przewijanie w widoku przewijania, aby przenieść „fokus przewijania” na widok sieciowy w układzie potomnym. W ten sposób przewijane drążki i wszystkie zdarzenia przewijania trafiają do znajdującego się w nim widoku internetowego.

Tak więc, aby znaleźć rozwiązanie, po osiągnięciu progu przewijania usuwam układ potomny z widoku scrollview i umieszczam go w elemencie nadrzędnym scrollview (i sprawiam, że scrollview jest niewidoczny).

// Remove the child view from the scroll view
scrollView.removeView(scrollChildLayout);

// Get scroll view out of the way
scrollView.setVisibility(View.GONE);

// Put the child view into scrollview's parent view
parentLayout.addView(scrollChildLayout);

Ogólna idea: (-> oznacza zawiera)

Przed: parentlayout -> scrollview -> scrollChildLayout

Po: parentLayout -> scrollChildLayout

Powyższy kod daje mi ten wyjątek:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
           at android.view.ViewGroup.addViewInner(ViewGroup.java:1976)
           at android.view.ViewGroup.addView(ViewGroup.java:1871)
           at android.view.ViewGroup.addView(ViewGroup.java:1828)
           at android.view.ViewGroup.addView(ViewGroup.java:1808)

Czy wiesz, co się dzieje? Wyraźnie wzywam removeView na rodzica.

Odpowiedzi:


289

Rozwiązanie:

((ViewGroup)scrollChildLayout.getParent()).removeView(scrollChildLayout);
//scrollView.removeView(scrollChildLayout);

Użyj elementu potomnego, aby uzyskać odniesienie do rodzica. Prześlij element nadrzędny do ViewGroup, aby uzyskać dostęp do metody removeView i jej użyć.

Dzięki @Dongshengcn za rozwiązanie


1
Rozwiązanie jest prawidłowe, ale dlaczego „scollView.removeView (scrollChildLayout)” nie działa? Czy te dwie linie nie powinny być takie same?
andrea.rinaldi

@ andrea.spot, wygląda na to, że scrollView.removeView(scrollChildLayout)próbuje usunąć element potomny scrollView, a nie usuwać samego scrollView z jego nadrzędnej ViewGroup
Dmitry Gryazin

1
@ user25 Wiem, że to może być za późno dla u, ale wyjątek wskaźnika zerowego wynika z tego, że rodzic jest pusty, co oznacza, że ​​widok nie jest dołączony do żadnego rodzica. ponieważ na początku nie ma rodzica, nie ma nic do usunięcia. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek

@kasgoku, czy możesz mi pomóc, proszę. próbuję pokazać fragment we względnym układzie po kliknięciu przycisku. ale pokazuje błąd „Podane dziecko ma już rodzica. Najpierw należy wywołać metodę removeView () na rodzicu dziecka”. jak to rozwiązać?
Imranrana 07

Otrzymałem również ten błąd w mojej aplikacji, która jest jedną z aplikacji czatu. Próbuję rozwiązać ten problem. ta ikona została usunięta, ale potrzebuję jej ponownie do przesyłania obrazów. ( stackoverflow.com/q/58117428/10971384 ) to jest mój link do pytania
Thangapandi

21

Spróbuj najpierw usunąć scrollChildLayout z jego widoku nadrzędnego?

scrollview.removeView(scrollChildLayout)

Lub usuń całe dziecko z widoku rodzica i dodaj je ponownie.

scrollview.removeAllViews()

Już wywołuję removeView w kodzie w moim pytaniu powyżej. removeAllViews () też nie działa.
kasgoku

Czy na pewno to rodzic, do którego dzwonisz removeView () / removeAllViews ()? Robię bardzo podobne rzeczy i to działa dla mnie.
dongshengcn

4
Możesz spojrzeć na jego rodzica, patrząc na: view.getParent () developer.android.com/reference/android/view/…
dongshengcn

@dongshengcn, czy możesz mi pomóc, proszę. próbuję pokazać fragment we względnym układzie po kliknięciu przycisku. ale pokazuje błąd „Podane dziecko ma już rodzica. Najpierw należy wywołać metodę removeView () na rodzicu dziecka”. jak to rozwiązać?
Imranrana 07

19

W onCreate z aktywnością lub w onCreateView z fragmentem.

 if (view != null) {
    ViewGroup parent = (ViewGroup) view.getParent();
    if (parent != null) {
        parent.removeView(view);
    }
}
try {
    view = inflater.inflate(R.layout.fragment_main, container, false);
} catch (InflateException e) {

}

15

Ok, nazwij mnie paranoikiem, ale proponuję:

  final android.view.ViewParent parent = view.getParent ();

  if (parent instanceof android.view.ViewManager)
  {
     final android.view.ViewManager viewManager = (android.view.ViewManager) parent;

     viewManager.removeView (view);
  } // if

rzucanie bez instanceofpo prostu wydaje się złe. I (dzięki IntelliJ IDEA za poinformowanie mnie) removeViewjest częścią ViewManagerinterfejsu. I nie należy rzucać na konkretną klasę, gdy dostępny jest idealnie odpowiedni interfejs.


3

Wszystko, co musisz zrobić, to wysłać () element Runnable, który wykona addView ().


Nie udało się. Oto, co próbowałem: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (new Runnable () {@Override public void run () {parentLayout.addView (scrollChildLayout);}});
kasgoku

1

Wołałem parentView.removeView (childView), a childView wciąż się wyświetlało. W końcu zdałem sobie sprawę, że metoda została w jakiś sposób wyzwolona dwukrotnie i dwukrotnie dodałem childView do parentView.

Tak więc, użyj parentView.getChildCount (), aby określić, ile dzieci ma rodzic przed dodaniem widoku i później. Jeśli element podrzędny zostanie dodany zbyt wiele razy, zostanie usunięty najbardziej górny element podrzędny, a kopia childView pozostanie - która wygląda na to, że removeView działa nawet wtedy, gdy jest.

Nie należy również używać View.GONE do usuwania widoku. Jeśli jest naprawdę usunięty, nie musisz go ukrywać, w przeciwnym razie nadal tam jest i po prostu ukrywasz go przed sobą :(


1

W moim przypadku mam BaseFragment i wszystkie inne fragmenty dziedziczą z tego.

Więc moim solytionem było dodanie tych linii w OnDestroyView()metodzie

@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    if (mRootView == null)
    {
        mRootView = (inflater == null ? getActivity().getLayoutInflater() : inflater).inflate(mContentViewResourceId, container, false);
    }
....////
}

@Override
public void onDestroyView()
{
    if (mRootView != null)
    {
        ViewGroup parentViewGroup = (ViewGroup) mRootView.getParent();

        if (parentViewGroup != null)
        {
            parentViewGroup.removeAllViews();
        }
    }

    super.onDestroyView();
}

czy próbowałeś wybrać następny fragment i nacisnąć zbyt szybko?
iamthevoid

1

Rozwiązanie Kotlin

Kotlin upraszcza rzutowanie rodzica za pomocą as?, zwracając wartość null, jeśli lewa strona jest pusta lub rzutowanie nie powiedzie się.

(childView.parent as? ViewGroup)?.removeView(childView)

Rozszerzenie Kotlin

Jeśli chcesz to jeszcze bardziej uprościć, możesz dodać to rozszerzenie.

childView.removeSelf()

fun View?.removeSelf() {
    this ?: return
    val parentView = parent as? ViewGroup ?: return
    parentView.removeView(this)
}

Bezpiecznie nic nie zrobi, jeśli ten widok ma wartość null, widok nadrzędny ma wartość null lub widok nadrzędny nie jest grupą widoków

UWAGA: Jeśli chcesz również bezpiecznie usuwać widoki podrzędne przez rodzica, dodaj to:

fun ViewGroup.removeViewSafe(toRemove: View) {
    if (contains(toRemove)) removeView(toRemove)
}

0

Możesz to również zrobić, sprawdzając, czy metoda indexOfView View, jeśli metoda indexOfView zwraca -1, wtedy możemy użyć.

ViewGroup's detachViewFromParent (v); po którym następuje removeDetachedView ViewGroup (v, prawda / fałsz);


0

To, co robiłem źle, więc otrzymałem ten błąd, to nie utworzyłem instancji układu dynamicznego i nie dodałem do niego elementów podrzędnych, więc otrzymałem ten błąd


0

Oto moje rozwiązanie.

Powiedzmy, że masz dwa TextViewsi umieść je na LinearLayout(nazwane ll). Położysz to LinerLayoutna innym LinerLayout.

< lm Linear Layout> 
       < ll Linear Layout> 
             <name Text view>
             </name Text view>
             <surname Text view>
             </surname Text view>
       </ll Linear Layout> 
</lm Linear Layout> 

Jeśli chcesz stworzyć taką strukturę, musisz przekazać rodzicowi jako dziedziczenie.

Jeśli chcesz, użyj go w onCreatemetodziethis , wystarczy.

W przeciwnym razie tutaj jest rozwiązanie:

LinerLayout lm = new LinearLayout(this); // You can use getApplicationContext() also
LinerLayout ll = new LinearLayout(lm.getContext());
TextView name = new TextView(ll.getContext());
TextView surname = new TextView(ll.getContext());
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.