Appelez d'abord removeView () sur le parent de l'enfant

138

Tout d'abord un peu de contexte:

J'ai une mise en page dans un scrollview. Au début, lorsque l'utilisateur fait défiler l'écran, la vue de défilement défile. Cependant, après un certain nombre de défilement, je devais désactiver le défilement sur la vue de défilement et déplacer le "focus de défilement" sur une vue Web à l'intérieur de la mise en page enfant. De cette façon, la vue de défilement reste bloquée et tous les événements de défilement vont à la vue Web à l'intérieur.

Donc, pour une solution, lorsque le seuil de défilement est atteint, je supprime la mise en page enfant de la vue de défilement et la place dans le parent de la vue de défilement (et rend la vue de défilement invisible).

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

Idée générale: (-> signifie contient)

Avant: parentlayout -> scrollview -> scrollChildLayout

Après: parentLayout -> scrollChildLayout

Le code ci-dessus me donne cette exception:

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)

Savez-vous ce qui se passe? J'appelle clairement removeView sur le parent.

Kasgoku
la source

Réponses:

289

Solution:

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

Utilisez l'élément enfant pour obtenir une référence au parent. Convertissez le parent en ViewGroup afin que vous ayez accès à la méthode removeView et que vous l'utilisiez.

Merci à @Dongshengcn pour la solution

Kasgoku
la source
1
La solution est correcte, mais pourquoi "scollView.removeView (scrollChildLayout)" ne fonctionnerait pas? Les deux lignes ne devraient-elles pas être les mêmes?
andrea.rinaldi
@ andrea.spot, semble scrollView.removeView(scrollChildLayout)essayer de supprimer l'enfant de scrollView, de ne pas supprimer le scrollView lui-même de son ViewGroup parent
Dmitry Gryazin
1
@ user25 Je sais que c'est peut-être trop tard pour u mais l'exception de pointeur nul est due au fait que le parent est vide, ce qui signifie que la vue n'est attachée à aucun parent. comme il n'y a pas de parent au début, il n'y a rien à supprimer. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek
@kasgoku pouvez-vous m'aider s'il vous plaît. J'essaye de montrer un fragment dans la disposition relative sur un clic de bouton. mais son erreur d'affichage "L'enfant spécifié a déjà un parent. Vous devez d'abord appeler removeView () sur le parent de l'enfant." comment résoudre ça?
Imranrana07
J'ai également eu cette erreur dans mon application qui est l'une des applications de chat. J'essaye de résoudre ce problème. cette icône est supprimée mais j'ai à nouveau besoin de l'icône pour télécharger des images. ( stackoverflow.com/q/58117428/10971384 ) c'est mon lien de question
Thangapandi
21

Essayez d'abord de supprimer scrollChildLayout de sa vue parente?

scrollview.removeView(scrollChildLayout)

Ou supprimez tous les enfants de la vue parent et ajoutez-les à nouveau.

scrollview.removeAllViews()
dongshengcn
la source
J'appelle déjà removeView dans le code de ma question ci-dessus. removeAllViews () ne fonctionne pas non plus.
kasgoku
Êtes-vous sûr que c'est le parent que vous appelez removeView () / removeAllViews ()? Je fais quelque chose de très similaire et cela fonctionne pour moi.
dongshengcn
4
Vous pouvez regarder son parent en regardant: view.getParent () developer.android.com/reference/android/view/…
dongshengcn
@dongshengcn pouvez-vous m'aider s'il vous plaît. J'essaye de montrer un fragment dans la disposition relative sur un clic de bouton. mais son erreur d'affichage "L'enfant spécifié a déjà un parent. Vous devez d'abord appeler removeView () sur le parent de l'enfant." comment résoudre ça?
Imranrana07
19

Dans onCreate avec activité ou dans onCreateView avec fragment.

 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) {

}
Cabezas
la source
15

Ok, appelez-moi paranoïaque mais je suggère:

  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 sans instanceofsemble juste faux. Et (merci IntelliJ IDEA de me l'avoir dit) removeViewfait partie de l' ViewManagerinterface. Et il ne faut pas jeter dans une classe concrète lorsqu'une interface parfaitement adaptée est disponible.

Martin
la source
3

Tout ce que vous avez à faire est de poster () un Runnable qui fait le addView ().

Romain Guy
la source
Ça n'a pas marché. Voici ce que j'ai essayé: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (new Runnable () {@Override public void run () {parentLayout.addView (scrollChildLayout);}});
kasgoku
1

J'appelais parentView.removeView (childView) et childView était toujours affiché. J'ai finalement réalisé qu'une méthode était en quelque sorte déclenchée deux fois et j'ai ajouté deux fois le childView au parentView.

Donc, utilisez parentView.getChildCount () pour déterminer le nombre d'enfants que le parent a avant d'ajouter une vue et après. Si l'enfant est ajouté trop de fois, alors l'enfant le plus en haut est en cours de suppression et la copie childView reste - ce qui ressemble à removeView fonctionne même quand c'est le cas.

De plus, vous ne devez pas utiliser View.GONE pour supprimer une vue. S'il est vraiment supprimé, vous n'aurez pas besoin de le cacher, sinon il est toujours là et vous le cachez simplement :(

Chris Sprague
la source
1

Dans mon cas, j'ai BaseFragment et tous les autres fragments en héritent.

Donc ma solytion a été d'ajouter ces lignes dans la OnDestroyView()méthode

@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();
}
Aleksey Timoshchenko
la source
avez-vous essayé de sélectionner le fragment suivant et d'appuyer trop vite?
iamthevoid
1

Solution Kotlin

Kotlin simplifie le casting parent avec as?, en renvoyant null si le côté gauche est nul ou si le cast échoue.

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

Solution d'extension Kotlin

Si vous souhaitez simplifier encore plus cela, vous pouvez ajouter cette extension.

childView.removeSelf()

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

Il ne fera rien en toute sécurité si cette vue est nulle, la vue parente est nulle ou la vue parente n'est pas un groupe de vues

REMARQUE: Si vous souhaitez également supprimer en toute sécurité les vues enfants par le parent, ajoutez ceci:

fun ViewGroup.removeViewSafe(toRemove: View) {
    if (contains(toRemove)) removeView(toRemove)
}
Gibolt
la source
0

Vous pouvez également le faire en vérifiant si la méthode indexOfView de View si la méthode indexOfView renvoie -1, nous pouvons utiliser.

DetachViewFromParent (v) de ViewGroup; suivi de removeDetachedView de ViewGroup (v, true / false);

Arun Gupta
la source
0

Ce que je faisais de mal, j'ai eu cette erreur, c'est que je n'instanciais pas la mise en page dynamique et n'y ajoutais pas des enfants, j'ai donc cette erreur

blackHawk
la source
0

Voici ma solution.

Disons que vous en avez deux TextViewset mettez-les sur un LinearLayout(nommé ll). Vous allez mettre ça LinerLayoutsur un autre 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> 

Lorsque vous souhaitez créer cette structure, vous devez donner le parent en héritage.

Si vous voulez l'utiliser dans une onCreateméthode thissuffira.

Sinon voici la solition:

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());
ishak O.
la source