Llame primero a removeView () en el padre del niño

138

Primero un poco de historia:

Tengo un diseño dentro de una vista de desplazamiento. Al principio, cuando el usuario se desplaza en la pantalla, la vista de desplazamiento se desplaza. Sin embargo, después de una cierta cantidad de desplazamiento, debía deshabilitar el desplazamiento en la vista de desplazamiento y mover el "foco de desplazamiento" a una vista web dentro del diseño secundario. De esta manera, la vista de desplazamiento se pega y todos los eventos de desplazamiento van a la vista web dentro de ella.

Entonces, para una solución, cuando se alcanza el umbral de desplazamiento, elimino el diseño secundario de la vista de desplazamiento y lo pongo en el padre de la vista de desplazamiento (y hago que la vista de desplazamiento sea 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);

Idea general: (-> medios contiene)

Antes: parentlayout -> scrollview -> scrollChildLayout

Después: parentLayout -> scrollChildLayout

El código anterior me está dando esta excepción:

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)

¿Sabes lo que está pasando? Claramente estoy llamando a removeView en el padre.

kasgoku
fuente

Respuestas:

289

Solución:

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

Use el elemento hijo para obtener una referencia al padre. Transmita el padre a un ViewGroup para que tenga acceso al método removeView y lo use.

Gracias a @Dongshengcn por la solución

kasgoku
fuente
1
La solución es correcta, pero ¿por qué "scollView.removeView (scrollChildLayout)" no funcionaría? ¿No deberían ser las dos líneas iguales?
andrea.rinaldi
@ andrea.spot, parece que scrollView.removeView(scrollChildLayout)intenta eliminar el elemento secundario de scrollView, no eliminar el scrollView en sí de su ViewGroup principal
Dmitry Gryazin
1
@ user25 Sé que esto puede ser demasiado tarde para usted, pero la excepción de puntero nulo se debe a que el elemento primario está vacío, lo que significa que la vista no está asociada a ningún elemento primario. Como no hay padre al principio, no hay nada que eliminar. if (mAdView.getParent()!=null) ((ViewGroup) mAdView.getParent()).removeView(mAdView);
Tarek
@kasgoku, ¿puedes ayudarme por favor? Estoy tratando de mostrar un fragmento en un diseño relativo con un clic de botón. pero muestra el error "El niño especificado ya tiene un padre. Primero debe llamar a removeView () en el padre del niño". ¿Cómo resolver esto?
Imranrana07
También recibí este error en mi aplicación, que es una de las aplicaciones de chat. Estoy tratando de resolver este problema. ese ícono se elimina pero necesito el ícono nuevamente para cargar imágenes. ( stackoverflow.com/q/58117428/10971384 ) este es mi enlace de preguntas
Thangapandi
21

Intente eliminar scrollChildLayout de su vista principal primero?

scrollview.removeView(scrollChildLayout)

O elimine todo el elemento secundario de la vista principal y agréguelos nuevamente.

scrollview.removeAllViews()
dongshengcn
fuente
Ya estoy llamando a removeView en el código de mi pregunta anterior. removeAllViews () tampoco funciona.
kasgoku
¿Está seguro de que es el padre al que llama removeView () / removeAllViews ()? Estoy haciendo algo muy similar y me ha funcionado.
dongshengcn
44
Puede mirar a su padre mirando: view.getParent () developer.android.com/reference/android/view/…
dongshengcn
@dongshengcn puedes ayudarme por favor. Estoy tratando de mostrar un fragmento en un diseño relativo con un clic de botón. pero muestra el error "El niño especificado ya tiene un padre. Primero debe llamar a removeView () en el padre del niño". ¿Cómo resolver esto?
Imranrana07
19

En onCreate con actividad o en onCreateView con fragmento.

 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
fuente
15

Ok, llámame paranoico pero te sugiero:

  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

lanzar sin instanceofsolo parece estar mal. Y (gracias IntelliJ IDEA por decirme) removeViewes parte de la ViewManagerinterfaz. Y no se debe lanzar a una clase concreta cuando hay disponible una interfaz perfectamente adecuada.

Martín
fuente
3

Todo lo que tienes que hacer es publicar () un Runnable que haga addView ().

Romain Guy
fuente
No funciono Esto es lo que probé: scrollView.removeView (scrollChildLayout); scrollView.setVisibility (View.GONE); parentLayout.post (new Runnable () {@Override public void run () {parentLayout.addView (scrollChildLayout);}});
kasgoku
1

Estaba llamando a parentView.removeView (childView) y aún se mostraba childView. Eventualmente me di cuenta de que de alguna manera se estaba activando un método dos veces y agregué childView a parentView dos veces.

Por lo tanto, use parentView.getChildCount () para determinar cuántos hijos tiene el padre antes de agregar una vista y después. Si el elemento secundario se agrega demasiadas veces, se eliminará el elemento superior de la parte superior y la copia childView permanecerá, lo que parece que removeView funciona incluso cuando lo está.

Además, no debe usar View.GONE para eliminar una vista. Si realmente se elimina, entonces no necesitará ocultarlo, de lo contrario, todavía está allí y solo se lo está ocultando a usted mismo :(

Chris Sprague
fuente
1

En mi caso, tengo BaseFragment y todos los demás fragmentos heredan de esto.

Entonces mi solución fue agregar estas líneas en el OnDestroyView()método

@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
fuente
¿Has intentado seleccionar el siguiente fragmento y presionar demasiado rápido?
iamthevoid
1

Solución Kotlin

Kotlin simplifica la conversión principal con as?, devolviendo nulo si el lado izquierdo es nulo o falla la conversión .

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

Solución de extensión Kotlin

Si desea simplificar esto aún más, puede agregar esta extensión.

childView.removeSelf()

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

No hará nada con seguridad si esta Vista es nula, la vista primaria es nula o la vista primaria no es un ViewGroup

NOTA: Si también desea la eliminación segura de las vistas secundarias por parte de los padres, agregue esto:

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

También puede hacerlo verificando si el método indexOfView de View si el método indexOfView devuelve -1, entonces podemos usarlo.

DetachViewFromParent (v) de ViewGroup; seguido por removeDetachedView de ViewGroup (v, verdadero / falso);

Arun Gupta
fuente
0

Lo que estaba haciendo mal, así que obtuve este error es que no estaba creando instancias de diseño dinámico y agregando hijos, así que obtuve este error

blackHawk
fuente
0

Aquí está mi solución.

Digamos que tienes dos TextViewsy ponlos en un LinearLayout(nombrado ll). Pondrás esto LinerLayouten otro 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> 

Cuando desee crear esta estructura, debe dar a los padres como herencia.

Si quieres usarlo en un onCreatemétodo thisserá suficiente.

De lo contrario, aquí está la solución:

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.
fuente