Wie kann ich alle Ansichten im Layout deaktivieren?

83

Zum Beispiel habe ich:

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

Gibt es eine Möglichkeit, alle Elemente in LinearLayout zu deaktivieren (setEnable (false)) my_layout?

Scit
quelle

Antworten:

98

Eine andere Möglichkeit besteht darin, setEnabled () für jedes Kind aufzurufen (z. B. wenn Sie das Kind vor dem Deaktivieren zusätzlich überprüfen möchten).

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
quelle
20
Dies funktioniert jedoch nur für untergeordnete Elemente der ersten Ebene. Wenn Sie verschachtelte Ansichten haben, funktioniert dies nicht.
Htafoya
Eine Lösung besteht darin, eine rekursive Funktion zu erstellen und eine ViewGroup als Parameter zu übergeben. Überprüfen Sie die Klasse auf alle Kinder und deaktivieren Sie sie, wenn es sich um einen EditText handelt.
StoneLam
126

Dieser ist für ViewGroups rekursiv

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ü
quelle
Gutes Snippet, aber Bildlaufansichten können weiterhin gescrollt werden. Für zusätzliche Funktionen wird etwas mehr Code benötigt
htafoya
Spinner werden nicht behindert nicht sicher warum :(
Vivek Singh
ViewPager werden auch nicht deaktiviert, einschließlich der darin enthaltenen Ansichten.
Raphael C
1
Es funktioniert nicht, da die Implementierung von setEnabled () in der Unterklasse der Ansicht liegt. Mit anderen Worten, es kann für verschiedene Ansichten unterschiedlich implementiert werden. Es gibt also keine Möglichkeit, dass ein solcher Ansatz für jede existierende Ansicht
funktioniert
82

Tutus Antwort ist auf dem richtigen Weg, aber seine Rekursion ist etwas umständlich. Ich finde das sauberer:

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
quelle
Hervorragende Lösung. Vielen Dank
Blodhgard
Das ist die richtige Antwort. Es geht rekursiv durch. Die aktuell akzeptierte Antwort geht nur eine Ebene tief.
Stealth Rabbi
24

Was für mich wirklich funktioniert:

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

und um es rückgängig zu machen:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Idan Magled
quelle
3
Schöne einfache Lösung, die den Job macht!
Schm1
2
Diese Lösung würde alle Ansichten in der Aktivität deaktivieren. Geht die Frage nicht wirklich an. Was ist, wenn das Ziel darin besteht, nur bestimmte ViewGroups in der Aktivität zu deaktivieren?
AlanKley
2
genau das habe ich gesucht, danke !! Aber dann kann ich erkennen, ob der Benutzer irgendwo klicken möchte?
Skizo-ozᴉʞS
1
Große einfache Lösung
WHOATEMYNOODLES
1
Beste Lösung, wenn Sie nur eine oder mehrere Ansichten deaktivieren / aktivieren möchten, verwenden Sie setEnabled (bool), oder wenn die Ansichten alle untergeordnete Elemente einer Ansicht sind, durchlaufen Sie alle untergeordneten Elemente dieser Ansicht und deaktivieren Sie sie alle, aber diese Lösung ist meiner Meinung nach die beste (Ich meine diese Antwort) Danke Idan
Mohammad Elsayed
21

Wenn Sie Ansichten in einer bestimmten ViewGroup deaktivieren möchten, können Sie die interessante, möglicherweise etwas undurchsichtige verwenden duplicateParentState. Ein Ansichtsstatus ist eine Reihe von booleschen Attributen wie gedrückt, aktiviert, aktiviert und andere. Verwenden Sie dies einfach für jedes Kind, das Sie mit der übergeordneten ViewGroup synchronisieren möchten:

android:duplicateParentState="true"

Beachten Sie, dass der gesamte Status und nicht nur der aktivierte Status dupliziert wird. Dies kann sein, was Sie wollen! Dieser Ansatz ist natürlich am besten geeignet, wenn Sie Layout-XML laden.

androidguy
quelle
13

Lassen Sie uns den Code von tütü ändern

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

Ich denke, es macht keinen Sinn, nur die Ansichtsgruppe zu deaktivieren. Wenn Sie es tun möchten, gibt es einen anderen Weg, den ich für genau den gleichen Zweck verwendet habe. Erstellen Sie eine Ansicht als Geschwister Ihrer Gruppenansicht:

<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" />

und zur Laufzeit sichtbar machen. Hinweis: Das übergeordnete Layout Ihrer Gruppenansicht sollte entweder ein relatives oder ein Rahmenlayout sein. Hoffe das wird helfen.

boburShox
quelle
1
Ihr Code wird zB Spinner nicht deaktivieren, da Spinner ViewGroup
qbait
12

Wenn ein verzweifelter Entwickler hier nach unten scrollt, habe ich eine andere Möglichkeit, dies zu tun. Das deaktiviert auch das Scrollen, soweit ich damit experimentiert habe. Die Idee ist, ein View-Element wie dieses in einem RelativeLayout unter all Ihren UI-Elementen zu verwenden.

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

Es ist also so eingestellt, dass es vor einer bestimmten Bedingung "weg" ist. Und dann setzen Sie die Sichtbarkeit auf SICHTBAR, wenn Sie Ihre Benutzeroberfläche deaktivieren möchten. Außerdem müssen Sie OnClickListenerfür diese Ansicht implementieren . Dadurch onClickListenerwird das Klickereignis abgefangen und nicht an die zugrunde liegenden Elemente übergeben.

RexSplode
quelle
1
Das habe ich gesucht, ja, ich war verzweifelt und fand deine Lösung wie verrückt: D
Skizo-ozᴉʞS
1
Ziemlich nette Lösung, eigentlich hatte ich es im Kopf und suchte jemanden, der die gleiche Idee hatte, damit ich kein verrückter Einzelgänger bin; D
Ricard
12

Ich persönlich benutze so etwas (vertikale Baumdurchquerung mit Rekursion)

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

Verwendung :

   viewGroup.deepForEach { isEnabled = false }
Achraf Amil
quelle
1
elegante Lösung.
Raphael C
forEach
Fehlt wohl
@ Skizo-ozᴉʞS es ist eine androidx.core.viewMethode: developer.android.com/reference/kotlin/androidx/core/view/…
Achraf Amil
4

Einzelheiten

  • Android Studio 3.1.4
  • Kotlin 1.2.70
  • eingecheckt in minSdkVersion 19

Lösung

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

Verwendung

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  }
Wassili Bodnarchuk
quelle
Arbeitete wie ein Zauber;)
Skizo-ozᴉʞS
3

Obwohl dies nicht ganz mit dem Deaktivieren von Ansichten in einem Layout identisch ist, sollten Sie erwähnen, dass Sie verhindern können, dass alle untergeordneten Elemente Berührungen erhalten (ohne die Layouthierarchie wiederholen zu müssen), indem Sie die ViewGroup # onInterceptTouchEvent (MotionEvent) -Methode überschreiben :

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

}

Dann können Sie verhindern, dass Kinder Berührungsereignisse erhalten:

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

Wenn Sie einen Klick-Listener aktiviert haben layout, wird dieser weiterhin ausgelöst.

Travis
quelle
Ich liebe diese Antwort. Ziemlich leicht und effizient im Vergleich zum ständigen Durchlaufen der ViewGroup, um alle Kinder zu deaktivieren! Um das Problem zu lösen, dass das Layout immer noch auf Klicks reagiert, können Sie das Layout in 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);
    }
}

und rufen Sie die Methode wie folgt auf:

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

In Kotlin können Sie verwenden, isDuplicateParentStateEnabled = truebevor das Viewzum hinzugefügt wird ViewGroup.

Wie in der setDuplicateParentStateEnabledMethode dokumentiert , werden diese nicht vom übergeordneten Status beeinflusst, wenn die untergeordnete Ansicht zusätzliche Status aufweist (z. B. den aktivierten Status für ein Kontrollkästchen).

Das XML-Analogon ist android:duplicateParentState="true".

Louis CAD
quelle
1

Verwenden Sie die folgende rekursive Funktion, um die Ansichten Ihres Kindes sichtbar oder verschwunden zu machen . Das erste Argument ist Ihre übergeordnete Ansicht und das zweite Argument entscheidet, ob Kinder der übergeordneten Ansicht sichtbar oder verschwunden sein sollen. wahr = sichtbar falsch = weg

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
quelle
1

Dies ist eine ziemlich verspätete Antwort. Aber es könnte jemandem helfen. Viele der oben genannten Antworten scheinen gut zu sein. Aber wenn Ihre layout.xml verschachtelte Ansichtsgruppen hat. Dann liefern die obigen Antworten möglicherweise nicht das vollständige Ergebnis. Daher habe ich meine Meinung als Ausschnitt gepostet. Mit dem folgenden Code können alle Ansichten deaktiviert werden (einschließlich verschachtelter Ansichtsgruppen).

HINWEIS: Vermeiden Sie verschachtelte ViewGroups, da diese nicht empfohlen werden.

 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
quelle
0

einstellen

android:descendantFocusability="blocksDescendants"

für Ihre ViewGroup-Ansicht. Alle Nachkommen werden nicht fokussiert.

Maratu13
quelle
Er fragt nicht nach dem Fokus.
Stealth Rabbi
0

Wenn Sie einen Satz von oder eine bestimmte Art von Ansicht deaktivieren möchten. Nehmen wir an, Sie möchten eine feste Anzahl von Schaltflächen mit einem bestimmten Text oder keinem Text deaktivieren, dann können Sie ein Array dieses Typs verwenden und die Array-Elemente durchlaufen während Sie die Schaltflächen mit der Eigenschaft setEnabled (false) deaktivieren Sie können dies bei einem Funktionsaufruf wie folgt tun:

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

Ich habe die Tütü- Reaktion verbessert , um die EditText- und RadioButton-Komponenten ordnungsgemäß zu deaktivieren. Außerdem teile ich eine Möglichkeit, die Sichtbarkeit der Ansicht zu ändern und Transparenz in den deaktivierten Ansichten hinzuzufügen.

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);
}
Engelo Polotto
quelle
0

Meine zwei Cent funktionieren ohne Rekursion

    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
quelle
0

Am einfachsten ist es, eine <Ansicht in Ihrer XML-Datei mit match_parent für Höhe und Breite zu erstellen. Stellen Sie sicher, dass sich die Ansicht über allen anderen Ansichten befindet. Wenn Sie Klicks verhindern möchten, machen Sie sie sichtbar und fügen Sie dieser Ansicht einen onClickListener mit null als Parameter hinzu .

Beispiel:

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

Dann in Ihrem Code:

val disableLayoutView = rootView.find<View>(R.id.disable_layout_view)
disableLayoutView.visibility = View.VISIBLE
disableLayoutView.setOnClickListener(null)
Jesus Almaral - Hackaprende
quelle
0

Ich möchte eine Kontrolle über die Stammansicht haben, also habe ich das includeSelfFlag hinzugefügtdeepForEach

fun ViewGroup.deepForEach(includeSelf: Boolean = true, function: View.() -> Unit) {
    if (includeSelf) function()
    forEach {
        it.apply {
            function()
            (this as? ViewGroup)?.apply { deepForEach(includeSelf, function) }
        }
    }
}
t3chb0t
quelle
0
You can have whichever children that you want to have the same state as the parents include android:duplicateParentState="true".  Then if you disable the parent, whatever children you have that set on will follow suit.  

Auf diese Weise können Sie alle Status gleichzeitig dynamisch in der übergeordneten Ansicht steuern.

<LinearLayout
    android:id="@+id/some_parent_something"
    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" 
        android:duplicateParentState="true"/>
    <LinearLayout
        android:id="@+id/my_layout"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:duplicateParentState="true">
        <TextView
            android:id="@+id/my_text_view"
            android:text="First Name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:duplicateParentState="true" />
        <EditText
            android:id="@+id/my_edit_view"
            android:width="100px"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:duplicateParentState="true" /> 
        <View .../>
        <View .../>
        ...
           <View .../>
    </LinearLayout>

</LinearLayout>
a54studio
quelle
-1

Für mich ist RelativeLayout oder ein anderes Layout am Ende der XML-Datei mit Breite und Höhe auf match_parent gesetzt, wobei das Attribut fokussierbar und anklickbar auf true gesetzt ist.

 <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
quelle
-2

Um eine Ansicht zu deaktivieren, müssen Sie die Methode setEnabled mit false als Argument aufrufen. Ex:

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