Jak mogę wyłączyć wszystkie widoki w układzie?


84

Na przykład mam:

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

Czy istnieje sposób na wyłączenie (setEnable (false)) wszystkich elementów wewnątrz LinearLayout my_layout?

Odpowiedzi:


98

Innym sposobem jest wywołanie setEnabled () na każdym dziecku (na przykład, jeśli chcesz zrobić dodatkowe sprawdzenie dziecka przed wyłączeniem)

LinearLayout layout = (LinearLayout) findViewById(R.id.my_layout);
for (int i = 0; i < layout.getChildCount(); i++) {
    View child = layout.getChildAt(i);
    child.setEnabled(false);
}

20
Jednak działa to tylko dla dzieci pierwszego poziomu, jeśli masz zagnieżdżone widoki, nie zadziała.
htafoya

Jednym z rozwiązań jest utworzenie funkcji rekurencyjnej, przekazując ViewGroup jako parametr. Sprawdź klasę pod kątem wszystkich elementów podrzędnych, wyłącz ją, jeśli jest to EditText.
StoneLam

126

ten jest rekurencyjny dla 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);
       }
    }
}

Dobry fragment, ale podglądy przewijane nadal będą przewijalne, potrzeba trochę więcej kodu, aby uzyskać dodatkową funkcjonalność
htafoya

Błystki nie są wyłączone, nie wiem dlaczego :(
Vivek Singh

ViewPagers również nie są wyłączane, w tym widoki wewnątrz niego.
Raphael C

1
To nie działa, ponieważ implementacja setEnabled () leży w podklasie widoku, innymi słowy może być implementowana inaczej dla różnych widoków. Nie ma więc mowy, żeby takie podejście zadziałało dla każdego istniejącego widoku
RexSplode.

83

Odpowiedź tutu jest na dobrej drodze, ale jego rekurencja jest trochę niezręczna. Myślę, że to jest czystsze:

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

Doskonałe rozwiązanie. Dzięki
Blodhgard

To jest właściwa odpowiedź. Przechodzi rekurencyjnie. Obecnie przyjęta odpowiedź sięga tylko jednego poziomu.
Stealth Rabbi

To najlepsza odpowiedź. Spowoduje to wyłączenie wszystkich dotknięć wewnątrz układu. Właśnie tego chciałem. Dzięki!
Dinith Rukshan Kumara

24

A tak naprawdę, czym jest dla mnie praca:

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

i aby to cofnąć:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

3
Ładne, proste rozwiązanie, które spełnia swoje zadanie!
Schm1,

2
To rozwiązanie spowodowałoby wyłączenie wszystkich widoków w działaniu. Tak naprawdę nie rozwiązuje tego pytania. A co, jeśli celem jest wyłączenie tylko niektórych ViewGroups w działaniu?
AlanKley

2
dokładnie tego szukałem, dzięki !! Ale wtedy mogę wykryć, czy użytkownik chce gdzieś kliknąć?
Skizo-ozᴉʞS

1
Świetne proste rozwiązanie
WHOATEMYNOODLES

1
najlepsze rozwiązanie, jeśli chcesz wyłączyć / włączyć tylko jeden lub zestaw widoków, użyj setEnabled (bool) lub jeśli wszystkie widoki są dziećmi jednej pętli widoku przez wszystkie dzieci tego widoku i wyłącz je wszystkie, ale to rozwiązanie uważam za najlepsze (Mam na myśli tę odpowiedź) dzięki Idan
Mohammad Elsayed

21

Jeśli chcesz wyłączyć widoki w określonej grupie widoków, możesz użyć interesującego, być może nieco niejasnego duplicateParentState. Stan widoku to zestaw atrybutów logicznych, takich jak wciśnięty, włączony, aktywowany i inne. Po prostu użyj tego na każdym dziecku, które chcesz zsynchronizować z nadrzędną ViewGroup:

android:duplicateParentState="true"

Zauważ, że powiela cały stan, a nie tylko stan włączony. To może być to, czego chcesz! Oczywiście to podejście jest najlepsze, jeśli ładujesz XML układu.


13

Zmieńmy kod 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);
   }
 }
}

Myślę, że po prostu wyłączanie grupy widoków nie ma sensu. Jeśli chcesz to zrobić, jest inny sposób, którego użyłem do dokładnie tego samego celu. Utwórz widok jako rodzeństwo widoku grupy:

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

a w czasie wykonywania spraw, by był widoczny. Uwaga: nadrzędny układ widoku grupy powinien być układem względnym lub układem ramek. Mam nadzieję, że to pomoże.


1
Twój kod nie wyłączy np. Spinner, ponieważ Spinner rozszerza ViewGroup
qbait

12

Jeśli jakiś zdesperowany programista przewinie tutaj, mam inną opcję, aby to zrobić. Co również wyłącza przewijanie, o ile z nim eksperymentowałem. Chodzi o to, aby użyć elementu View, takiego jak ten, w RelativeLayout pod wszystkimi elementami interfejsu użytkownika.

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

Więc jest ustawione na „zniknięcie” przed jakimś stanem. Następnie ustawiasz jego widoczność na WIDOCZNE, gdy chcesz wyłączyć interfejs użytkownika. Musisz również wdrożyć OnClickListenerdla tego widoku. Spowoduje onClickListenerto przechwycenie zdarzenia kliknięcia i nie przekaże go do elementów bazowych.


1
Właśnie tego szukałem, tak, byłem zdesperowany i znalazłem twoje rozwiązanie przewijające się jak szalone: ​​D
Skizo-ozᴉʞS

1
Całkiem fajne rozwiązanie, właściwie to miałem to w głowie i szukałem kogoś innego mającego ten sam pomysł, więc nie jestem szalonym samotnikiem; D
Ricard

12

Osobiście używam czegoś takiego (pionowe przechodzenie po drzewie przy użyciu rekurencji)

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

stosowanie :

   viewGroup.deepForEach { isEnabled = false }

1
eleganckie rozwiązanie.
Raphael C

forEachChyba brakuje mi metody
Skizo-ozᴉʞS

@ Skizo-ozᴉʞS to androidx.core.viewmetoda: developer.android.com/reference/kotlin/androidx/core/view/…
Achraf Amil

5

Detale

  • Android Studio 3.1.4
  • Kotlin 1.2.70
  • sprawdzono minSdkVersion 19

Rozwiązanie

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

Stosowanie

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  }

Działało jak urok;)
Skizo-ozᴉʞS

3

Chociaż nie całkiem tak samo jak wyłączenie widoki w układzie, warto wspomnieć, że można zapobiec wszystkie dzieci od otrzymania poprawki (bez konieczności recurse hierarchii układu) poprzez nadpisanie ViewGroup # onInterceptTouchEvent (MotionEvent) metodę:

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

}

Następnie możesz uniemożliwić dzieciom otrzymywanie zdarzeń dotykowych:

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

Jeśli masz włączony odbiornik kliknięć layout , nadal będzie on wyzwalany.


Uwielbiam tę odpowiedź. Dość lekka i wydajna w porównaniu do stale przechodzącej przez ViewGroup, aby wyłączyć wszystkie dzieci! Aby rozwiązać problem z układem nadal reagującym na kliknięcia, możesz po prostu wyłączyć / włączyć układ w 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);
    }
}

i wywołaj taką metodę:

RelativeLayout rl_root = (RelativeLayout) findViewById(R.id.rl_root);
disableLL(rl_root);

2

W Kotlinie możesz użyć, isDuplicateParentStateEnabled = truezanim Viewzostanie dodany do ViewGroup.

Jak udokumentowano w setDuplicateParentStateEnabled metodzie, jeśli widok potomny ma dodatkowe stany (takie jak stan zaznaczenia dla pola wyboru), nie będzie to miało wpływu na element nadrzędny.

Analogiem XML jest android:duplicateParentState="true".


1

Zastosowanie poniżej funkcji rekurencyjnej, aby Twoje dziecko poglądy widoczne lub zniknął . Pierwszy argument to widok rodzica, a drugi argument decyduje, czy chcesz, aby elementy potomne widoku rodzica były widoczne, czy zniknęły. prawda = widoczne fałsz = nie ma

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

1

To dość opóźniona odpowiedź, ale może komuś pomóc. Wiele odpowiedzi wymienionych powyżej wydaje się być dobrych. Ale jeśli twój layout.xml ma zagnieżdżone grupy widoków. Wtedy powyższe odpowiedzi mogą nie dać pełnego wyniku. Dlatego zamieściłem swoją opinię jako fragment. Za pomocą poniższego kodu można wyłączyć wszystkie widoki (w tym zagnieżdżone grupy widoków).

UWAGA: Staraj się unikać zagnieżdżonych ViewGroups, ponieważ nie są one zalecane.

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

0

Zestaw

android:descendantFocusability="blocksDescendants"

dla Twojego widoku ViewGroup. Wszyscy potomkowie nie będą się skupiać.


Nie pyta o skupienie.
Stealth Rabbi

0

Jeśli chcesz wyłączyć zestaw lub powiedzieć określony rodzaj widoku, powiedzmy, że chcesz wyłączyć określoną liczbę przycisków z określonym tekstem lub bez tekstu, możesz użyć tablicy tego typu i zapętlić elementy tablicy podczas wyłączania przycisków za pomocą właściwości setEnabled (false) Możesz to zrobić na wywołaniu funkcji w następujący sposób:

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

0

Poprawiłem odpowiedź tütü, aby poprawnie wyłączyć komponenty EditText i RadioButton. Poza tym udostępniam sposób, w jaki znalazłem zmianę widoczności widoku i dodanie przezroczystości w wyłączonych widokach.

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

0

Moje dwa centy działają bez rekurencji

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

0

Najłatwiejszym sposobem jest utworzenie <View w swoim xml, z match_parent dla wysokości i szerokości, upewnij się, że widok jest ponad wszystkimi innymi widokami, a następnie, jeśli chcesz zapobiec kliknięciom, uczyń go widocznym, dodaj onClickListener do tego widoku z null jako parametrem .

Przykład:

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

Następnie w swoim kodzie:

val disableLayoutView = rootView.find<View>(R.id.disable_layout_view)
disableLayoutView.visibility = View.VISIBLE
disableLayoutView.setOnClickListener(null)

0

Lubię mieć kontrolę nad widokiem głównym, więc dodałem includeSelfflagę dodeepForEach

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

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.  

Umożliwi to dynamiczne kontrolowanie wszystkich stanów jednocześnie z widoku nadrzędnego.

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

-1

aby wyłączyć widok, należy wywołać metodę setEnabled z wartością false jako argument. dawny:

Button btn = ...
btn.setEnabled(false);

-1

Dla mnie RelativeLayout lub inny układ na końcu pliku xml z szerokością i wysokością ustawioną na match_parent z atrybutem focusable i klikalnym ustawionym na true.

 <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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.