Chiama removeView () prima sul genitore del bambino


138

Prima un po 'di storia:

Ho un layout all'interno di una vista di scorrimento. All'inizio, quando l'utente scorre lo schermo, scorre la vista di scorrimento. Tuttavia, dopo una certa quantità di scorrimento, avrei dovuto disabilitare lo scorrimento nella vista di scorrimento per spostare il "focus di scorrimento" su una visualizzazione Web all'interno del layout figlio. In questo modo, la vista di scorrimento si attacca e tutti gli eventi di scorrimento passano alla vista Web al suo interno.

Quindi, per una soluzione, quando viene raggiunta la soglia di scorrimento, rimuovo il layout figlio dalla vista di scorrimento e lo inserisco nel padre della vista di scorrimento (e rendo invisibile la vista di scorrimento).

// 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);

Idea generale: (-> significa contiene)

Prima: parentlayout -> scrollview -> scrollChildLayout

Dopo: parentLayout -> scrollChildLayout

Il codice sopra mi dà questa eccezione:

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)

Sai cosa sta succedendo? Chiamo chiaramente removeView sul genitore.

Risposte:


289

Soluzione:

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

Utilizzare l'elemento figlio per ottenere un riferimento al genitore. Trasmetti il ​​genitore a un ViewGroup in modo da ottenere l'accesso al metodo removeView e utilizzarlo.

Grazie a @Dongshengcn per la soluzione


1
La soluzione è giusta, ma perché "scollView.removeView (scrollChildLayout)" non funziona? Le due linee non dovrebbero essere uguali?
andrea.rinaldi,

@ andrea.spot, sembra che scrollView.removeView(scrollChildLayout)cerchi di rimuovere il figlio di scrollView, non di rimuovere scrollView stesso dal suo gruppo View View
Dmitry Gryazin,

1
@utente25 lo so forse troppo tardi per te, ma l'eccezione del puntatore null è dovuta al fatto che il genitore è vuoto, il che significa che la vista non è collegata a nessun genitore. poiché all'inizio non esiste un genitore, non c'è nulla da rimuovere. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek,

@kasgoku puoi aiutarmi per favore. sto cercando di mostrare un frammento nel layout relativo con un clic sul pulsante. ma viene visualizzato l'errore "Il figlio specificato ha già un genitore. Devi prima chiamare removeView () sul genitore del figlio." come risolverlo?
Imranrana07,

Ho anche riscontrato questo errore nella mia applicazione che è una delle applicazioni di chat. Sto cercando di risolvere questo problema. quell'icona viene rimossa ma mi serve di nuovo l'icona per caricare le immagini. ( stackoverflow.com/q/58117428/10971384 ) questo è il link alla mia domanda
Thangapandi,

21

Prova a rimuovere scrollChildLayout dalla sua vista padre prima?

scrollview.removeView(scrollChildLayout)

Oppure rimuovi tutto il figlio dalla vista padre e aggiungilo di nuovo.

scrollview.removeAllViews()

Sto già chiamando removeView nel codice nella mia domanda sopra. removeAllViews () non funziona neanche.
Kasgoku,

Sei sicuro che sia il genitore che stai chiamando removeView () / removeAllViews ()? Sto facendo cose molto simili e ha funzionato per me.
Dongshengcn,

4
Puoi guardare il suo genitore guardando: view.getParent () developer.android.com/reference/android/view/…
dongshengcn

@dongshengcn puoi aiutarmi per favore. sto cercando di mostrare un frammento nel layout relativo con un clic sul pulsante. ma viene visualizzato l'errore "Il figlio specificato ha già un genitore. Devi prima chiamare removeView () sul genitore del figlio." come risolverlo?
Imranrana07,

19

In onCreate con attività o in onCreateView con frammento.

 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, chiamami paranoico ma suggerisco:

  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

casting senza instanceofsembrare sbagliato. E (grazie a IntelliJ IDEA per avermelo detto) removeViewfa parte ViewManagerdell'interfaccia. E non si dovrebbe trasmettere a una classe concreta quando è disponibile un'interfaccia perfettamente adatta.


3

Tutto quello che devi fare è pubblicare () un Runnable che esegue addView ().


Non ha funzionato Questo è quello che ho provato: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (new Runnable () {@Override public void run () {parentLayout.addView (scrollChildLayout);}});
Kasgoku,

1

Stavo chiamando parentView.removeView (childView) e childView stava ancora mostrando. Alla fine mi sono reso conto che in qualche modo un metodo veniva attivato due volte e ho aggiunto il childView al parentView due volte.

Quindi, usa parentView.getChildCount () per determinare quanti figli ha il genitore prima di aggiungere una vista e successivamente. Se il figlio viene aggiunto troppe volte, viene rimossa la maggior parte del figlio superiore e la copia childView rimane, il che sembra che removeView funzioni anche quando lo è.

Inoltre, non dovresti usare View.GONE per rimuovere una vista. Se è veramente rimosso, non dovrai nasconderlo, altrimenti è ancora lì e lo stai nascondendo da te stesso :(


1

Nel mio caso, ho BaseFragment e tutti gli altri frammenti ereditano da questo.

Quindi il mio consiglio è stato aggiungere queste righe nel OnDestroyView()metodo

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

hai provato a selezionare il frammento successivo e premere troppo velocemente indietro?
iamthevoid,

1

Soluzione di Kotlin

Kotlin semplifica il casting dei genitori con as?, restituendo null se il lato sinistro è null o il cast fallisce.

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

Soluzione di estensione Kotlin

Se vuoi semplificare ulteriormente questo, puoi aggiungere questa estensione.

childView.removeSelf()

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

Non farà nulla in modo sicuro se questa vista è nulla, la vista padre è nulla o la vista padre non è un gruppo di viste

NOTA: se si desidera anche la rimozione sicura delle viste figlio da parte del genitore, aggiungere questo:

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

0

Puoi anche farlo controllando se il metodo indexOfView di View se il metodo indexOfView restituisce -1, quindi possiamo usare.

DetachViewFromParent di ViewGroup (v); seguito da removeDetachedView di ViewGroup (v, true / false);


0

Quello che stavo facendo di sbagliato, quindi ho riscontrato questo errore, non ho creato un'istanza di layout dinamico e l'aggiunta di elementi secondari, quindi ho riscontrato questo errore


0

Ecco la mia soluzione

Diciamo che ne hai due TextViewse mettili su un LinearLayout(chiamato ll). Lo metterai LinerLayoutsu un altro 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> 

Quando vuoi creare questa struttura devi dare il genitore come eredità.

Se vuoi usarlo in un onCreatemetodo thissarà abbastanza.

Altrimenti ecco la solizione:

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());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.