¿Cómo puedo deshabilitar todas las vistas dentro del diseño?

83

Por ejemplo tengo:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
        android:layout_height="fill_parent">
     <Button 
        android:id="@+id/backbutton"
        android:text="Back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:id="@+id/my_layout"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/my_text_view"
            android:text="First Name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <EditText
            android:id="@+id/my_edit_view"
            android:width="100px"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" /> 
        <View .../>
        <View .../>
        ...
        <View .../>
    </LinearLayout>

</LinearLayout>

¿Hay alguna forma de deshabilitar (setEnable (false)) todos los elementos dentro de LinearLayout my_layout?

Scit
fuente

Respuestas:

98

Otra forma es llamar a setEnabled () en cada niño (por ejemplo, si desea hacer una verificación adicional en el niño antes de deshabilitarlo)

LinearLayout layout = (LinearLayout) findViewById(R.id.my_layout);
for (int i = 0; i < layout.getChildCount(); i++) {
    View child = layout.getChildAt(i);
    child.setEnabled(false);
}
4e6
fuente
20
Sin embargo, esto solo funciona para los niños de primer nivel, si tiene vistas anidadas, no funcionará.
htafoya
Una solución es hacer una función recursiva, pasando un ViewGroup como parámetro. Verifique la clase para todos sus hijos, deshabilítelo si es un EditText.
StoneLam
125

este es recursivo para ViewGroups

private void disableEnableControls(boolean enable, ViewGroup vg){
    for (int i = 0; i < vg.getChildCount(); i++){
       View child = vg.getChildAt(i);
       child.setEnabled(enable);
       if (child instanceof ViewGroup){ 
          disableEnableControls(enable, (ViewGroup)child);
       }
    }
}
tütü
fuente
Buen fragmento, pero las vistas de desplazamiento seguirán siendo desplazables, se necesita algo más de código para una funcionalidad adicional
htafoya
Los hilanderos no se desactivan, no sé por qué :(
Vivek Singh
ViewPagers tampoco se deshabilita, incluidas las vistas dentro de él.
Raphael C
1
No funciona porque la implementación de setEnabled () se encuentra en la subclase de la vista, en otras palabras, se puede implementar de manera diferente para diferentes vistas. Por lo tanto, no hay forma de que dicho enfoque funcione para todas las vistas existentes
RexSplode
81

La respuesta de tutu va por buen camino, pero su recursividad es un poco incómoda. Creo que esto es más limpio:

private static void setViewAndChildrenEnabled(View view, boolean enabled) {
    view.setEnabled(enabled);
    if (view instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup) view;
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View child = viewGroup.getChildAt(i);
            setViewAndChildrenEnabled(child, enabled);
        }
    }
}
Eric Cochran
fuente
Excelente solucion. Gracias
Blodhgard
Esta es la respuesta correcta. Pasa de forma recursiva. La respuesta aceptada actual solo tiene un nivel de profundidad.
Stealth Rabbi
24

Realmente lo que me funciona es:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

y deshacerlo:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Idan Magled
fuente
3
¡Buena solución simple que hace el trabajo!
Schm1
2
Esta solución deshabilitaría todas las vistas de la actividad. Realmente no aborda la pregunta. ¿Qué pasa si el objetivo es deshabilitar solo ciertos ViewGroups en la actividad?
AlanKley
2
eso es exactamente lo que estaba buscando, gracias !! ¿Pero entonces puedo detectar si el usuario quiere hacer clic en algún lugar?
Skizo-ozᴉʞS
1
Gran solución simple
WHOATEMYNOODLES
1
la mejor solución si desea deshabilitar / habilitar solo una o un conjunto de vistas, use setEnabled (bool) o si las vistas son todas secundarias de una vista, recorra todos los elementos secundarios de esta vista y las deshabilite todas, pero creo que esta solución es la mejor (Me refiero a esta respuesta) gracias Idan
Mohammad Elsayed
21

Si está interesado en deshabilitar las vistas en un ViewGroup específico, puede usar el interesante, quizás un poco oscuro duplicateParentState. Un estado de vista es un conjunto de atributos booleanos como presionado, habilitado, activado y otros. Solo use esto en cada niño que desee sincronizar con ViewGroup padre:

android:duplicateParentState="true"

Tenga en cuenta que duplica todo el estado y no solo el estado habilitado. ¡Esto puede ser lo que quieras! Por supuesto, este enfoque es mejor si está cargando XML de diseño.

androidguy
fuente
13

Cambiemos el código de tütü

private void disableEnableControls(boolean enable, ViewGroup vg){
for (int i = 0; i < vg.getChildCount(); i++){
   View child = vg.getChildAt(i);
   if (child instanceof ViewGroup){ 
      disableEnableControls(enable, (ViewGroup)child);
   } else {
     child.setEnabled(enable);
   }
 }
}

Creo que no tiene sentido simplemente desactivar el grupo de vistas. Si quieres hacerlo, hay otra forma que he usado exactamente para el mismo propósito. Cree una vista como hermana de su vista de grupo:

<View
    android:visibility="gone"
    android:id="@+id/reservation_second_screen"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="bottom"
    android:background="#66ffffff"
    android:clickable="false" />

y en tiempo de ejecución, hazlo visible. Nota: el diseño principal de su vista de grupo debe ser relativo o de marco. Espero que esto ayude.

boburShox
fuente
1
Su código no deshabilitará, por ejemplo, Spinner, porque Spinner extiende ViewGroup
qbait
12

Si algún desarrollador desesperado se desplaza hasta aquí, tengo otra opción para hacerlo. Lo que también deshabilita el desplazamiento hasta donde experimenté con él. La idea es usar el elemento View como este en un RelativeLayout, debajo de todos los elementos de la interfaz de usuario.

<View
                android:id="@+id/shade"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/primaryShadow"
                android:visibility="gone"/>

Por lo que está configurado para "desaparecer" antes de alguna condición. Y luego configura su visibilidad en VISIBLE cuando desea deshabilitar su interfaz de usuario. También tienes que implementar OnClickListenerpara esta Vista. Esto onClickListenerdetectará el evento de clic y no lo pasará a los elementos subyacentes.

RexSplode
fuente
1
Eso es lo que estaba buscando, sí, estaba desesperado y encontré tu solución desplazándote como loco: D
Skizo-ozᴉʞS
1
Muy buena solución, de hecho lo tenía en mente y estaba buscando a alguien más que tuviera la misma idea, así que no soy un loco solitario; D
Ricard
12

Yo personalmente uso algo como esto (recorrido de árbol vertical usando recursividad)

fun ViewGroup.deepForEach(function: View.() -> Unit) {
    this.forEach { child ->
        child.function()
        if (child is ViewGroup) {
            child.deepForEach(function)
        }
    }
}

uso:

   viewGroup.deepForEach { isEnabled = false }
Achraf Amil
fuente
1
solución elegante.
Raphael C
forEachSupongo que falta el método
Skizo-ozᴉʞS
@ Skizo-ozᴉʞS es un androidx.core.viewmétodo: developer.android.com/reference/kotlin/androidx/core/view/…
Achraf Amil
4

Detalles

  • Estudio de Android 3.1.4
  • Kotlin 1.2.70
  • registrado en minSdkVersion 19

Solución

fun View.forEachChildView(closure: (View) -> Unit) {
    closure(this)
    val groupView = this as? ViewGroup ?: return
    val size = groupView.childCount - 1
    for (i in 0..size) {
        groupView.getChildAt(i).forEachChildView(closure)
    }
}

Uso

val layout = LinearLayout(context!!)
layout.forEachChildView {  it.isEnabled = false  }

val view = View(context!!)
view.forEachChildView {  it.isEnabled = false  }

val fragment = Fragment.instantiate(context, "fragment_id")
fragment.view?.forEachChildView {  it.isEnabled = false  }
Vasily Bodnarchuk
fuente
Funcionó como un encanto;)
Skizo-ozᴉʞS
3

Aunque no es lo mismo que deshabilitar vistas dentro de un diseño, vale la pena mencionar que puede evitar que todos los niños reciban toques (sin tener que repetir la jerarquía del diseño) anulando el método ViewGroup # onInterceptTouchEvent (MotionEvent) :

public class InterceptTouchEventFrameLayout extends FrameLayout {

    private boolean interceptTouchEvents;

    // ...

    public void setInterceptTouchEvents(boolean interceptTouchEvents) {
        this.interceptTouchEvents = interceptTouchEvents;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return interceptTouchEvents || super.onInterceptTouchEvent(ev);
    }

}

Entonces puede evitar que los niños reciban eventos táctiles:

InterceptTouchEventFrameLayout layout = (InterceptTouchEventFrameLayout) findViewById(R.id.layout);
layout.setInterceptTouchEvents(true);

Si tiene un detector de clics activado layout, aún se activará.

Travis
fuente
Amo esta respuesta. Bastante ligero y eficiente en comparación con el ViewGroup que recorre constantemente para desactivar a todos los niños. Para resolver el problema con el diseño que sigue respondiendo a los clics, puede deshabilitar / habilitar el diseño en setInterceptTouchEvents ()
AlanKley
2
  private void disableLL(ViewGroup layout){
    for (int i = 0; i < layout.getChildCount(); i++) {
        View child = layout.getChildAt(i);
        child.setClickable(false);
        if (child instanceof ViewGroup)
            disableLL((ViewGroup) child);
    }
}

y llamar a un método como este:

RelativeLayout rl_root = (RelativeLayout) findViewById(R.id.rl_root);
disableLL(rl_root);
abbasalim
fuente
2

En Kotlin, puede usar isDuplicateParentStateEnabled = trueantes de que Viewse agregue al ViewGroup.

Como se documenta en el setDuplicateParentStateEnabledmétodo, si la vista secundaria tiene estados adicionales (como estado marcado para una casilla de verificación), estos no se verán afectados por el padre.

El análogo xml es android:duplicateParentState="true".

Louis CAD
fuente
1

Utilice la siguiente función recursiva para hacer que las vistas de su hijo sean visibles o desaparezcan . El primer argumento es su vista principal y el segundo argumento decide si desea que los elementos secundarios de la vista principal estén visibles o desaparezcan. verdadero = visible falso = desaparecido

private void layoutElemanlarininGorunumunuDegistir(View view, boolean gorunur_mu_olsun) {
    ViewGroup view_group;
    try {
        view_group = (ViewGroup) view;
        Sabitler.konsolaYazdir(TAG, "View ViewGroup imiş!" + view.getId());
    } catch (ClassCastException e) {
        Sabitler.konsolaYazdir(TAG, "View ViewGroup değilmiş!" + view.getId());
        return;
    }

    int view_eleman_sayisi = view_group.getChildCount();
    for (int i = 0; i < view_eleman_sayisi; i++) {
        View view_group_eleman = view_group.getChildAt(i);
        if (gorunur_mu_olsun) {
            view_group_eleman.setVisibility(View.VISIBLE);
        } else {
            view_group_eleman.setVisibility(View.GONE);
        }
        layoutElemanlarininGorunumunuDegistir(view_group_eleman, gorunur_mu_olsun);
    }
}
resw67
fuente
1

Esta es una respuesta bastante tardía, pero podría ayudar a alguien. Muchas de las respuestas mencionadas anteriormente parecen ser buenas. Pero si su layout.xml tiene grupos de vistas anidados. Entonces, es posible que las respuestas anteriores no proporcionen un resultado completo. Por lo tanto, he publicado mi opinión como un fragmento. Con el siguiente código, se pueden deshabilitar todas las vistas (incluidos los grupos de vistas anidados).

NOTA: Intente evitar ViewGroups anidados, ya que no se recomiendan.

 private void setEnableView(boolean b) {
    LinearLayout layout = (LinearLayout)findViewById(R.id.parent_container);
    ArrayList<ViewGroup> arrVg = new ArrayList<>();
    for (int i = 0; i < layout.getChildCount(); i++) {
        View child = layout.getChildAt(i);
        if (child instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) child;
            arrVg.add(vg);
        }
        child.setEnabled(b);
    }

    for (int j=0;j< arrVg.size();j++){
        ViewGroup vg = arrVg.get(j);
        for (int k = 0; k < vg.getChildCount(); k++) {
         vg.getChildAt(k).setEnabled(b);
        }
    }
}
mohammed nathar
fuente
0

Conjunto

android:descendantFocusability="blocksDescendants"

para su vista ViewGroup. Todos los descendientes no se enfocarán.

Maratu13
fuente
No está preguntando por el enfoque.
Stealth Rabbi
0

Si desea deshabilitar un conjunto de, o decir un tipo particular de vista, digamos que desea deshabilitar un número fijo de botones con un texto en particular o sin texto, entonces puede usar una matriz de ese tipo y recorrer los elementos de la matriz. mientras deshabilita los botones usando la propiedad setEnabled (false) Puede hacerlo en una llamada de función como esta:

public void disable(){
        for(int i=0;i<9;i++){
                if(bt[i].getText().equals("")){//Button Text condition
                    bt[i].setEnabled(false);
            }
        }
}
Mohit Pardasani
fuente
0

Mejoré el tutú respuesta a desactivar adecuadamente Componentes EditText y RadioButton. Además, estoy compartiendo una forma que encontré para cambiar la visibilidad de la vista y agregar transparencia en las vistas deshabilitadas.

private static void disableEnableControls(ViewGroup view, boolean enable){
    for (int i = 0; i < view.getChildCount(); i++) {
        View child = view.getChildAt(i);
        child.setEnabled(enable);
        if (child instanceof ViewGroup){
            disableEnableControls((ViewGroup)child, enable);
        }
        else if (child instanceof EditText) {
            EditText editText = (EditText) child;
            editText.setEnabled(enable);
            editText.setFocusable(enable);
            editText.setFocusableInTouchMode(enable);
        }
        else if (child instanceof RadioButton) {
            RadioButton radioButton = (RadioButton) child;
            radioButton.setEnabled(enable);
            radioButton.setFocusable(enable);
            radioButton.setFocusableInTouchMode(enable);
        }
    }
}

public static void setLayoutEnabled(ViewGroup view, boolean enable) {
    disableEnableControls(view, enable);
    view.setEnabled(enable);
    view.setAlpha(enable? 1f: 0.3f);
}

public static void setLayoutEnabled(ViewGroup view, boolean enable, boolean visibility) {
    disableEnableControls(view, enable);
    view.setEnabled(enable);
    view.setAlpha(enable? 1f: 0.3f);
    view.setVisibility(visibility? View.VISIBLE: View.GONE);
}
Ângelo Polotto
fuente
0

Mis dos centavos funcionan sin recursividad

    package io.chord.ui.utils

import android.view.View
import android.view.ViewGroup
import androidx.core.view.forEach

class ViewUtils
{
    companion object
    {
        fun setViewState(view: View, state: Boolean)
        {
            var depth = 0
            val views: MutableMap<Int, MutableList<View>> = mutableMapOf()
            views[depth] = mutableListOf(view)

            while(true)
            {
                val currentViews = views[depth]
                val nextViews = mutableListOf<View>()

                currentViews!!.forEach { view ->
                    if(view is ViewGroup)
                    {
                        view.forEach { children ->
                            nextViews.add(children)
                        }
                    }
                }

                if(nextViews.size == 0)
                {
                    break
                }

                depth++

                views[depth] = nextViews
            }

            views.flatMap {
                it.value
            }.forEach {
                it.isEnabled = state
            }
        }
    }
}
midoriiro
fuente
0

La forma más fácil es crear una <Vista en su xml, con match_parent para la altura y el ancho, asegúrese de que la vista esté por encima de todas las demás vistas, luego, cuando desee evitar los clics, hágalo visible agregue un onClickListener a esa vista con nulo como parámetro .

Ejemplo:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
        android:layout_height="fill_parent">
     <Button 
        android:id="@+id/backbutton"
        android:text="Back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:id="@+id/my_layout"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/my_text_view"
            android:text="First Name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <EditText
            android:id="@+id/my_edit_view"
            android:width="100px"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" /> 
        
        <View
            android:id="@+id/disable_layout_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"/>
    </LinearLayout>

</LinearLayout>

Luego en tu código:

val disableLayoutView = rootView.find<View>(R.id.disable_layout_view)
disableLayoutView.visibility = View.VISIBLE
disableLayoutView.setOnClickListener(null)
Jesús Almaral - Hackaprende
fuente
0

Me gusta tener un control sobre la vista raíz, así que agregué la includeSelfbandera adeepForEach

fun ViewGroup.deepForEach(includeSelf: Boolean = true, function: View.() -> Unit) {
    if (includeSelf) function()
    forEach {
        it.apply {
            function()
            (this as? ViewGroup)?.apply { deepForEach(includeSelf, function) }
        }
    }
}
t3chb0t
fuente
-1

Para mí, RelativeLayout o cualquier otro diseño al final del archivo xml con el ancho y la altura establecidos en match_parent con el atributo enfocable y en el que se puede hacer clic establecido en verdadero.

 <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clickable="true"
            android:focusable="true">

        <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true" />

    </RelativeLayout>
N. Hsn
fuente
-2

para deshabilitar una vista, debe llamar al método setEnabled con false como argumento. ex:

Button btn = ...
btn.setEnabled(false);
Eric Ningabiye
fuente