Як я можу вимкнути всі види всередині макета?


84

Наприклад, я маю:

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

Чи є спосіб вимкнути (setEnable (false)) всі елементи всередині LinearLayout my_layout?

Відповіді:


98

Інший спосіб - викликати setEnabled () для кожної дитини (наприклад, якщо ви хочете зробити додаткову перевірку дитини перед відключенням)

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
Однак це працює лише для дітей першого рівня, якщо у вас є вкладені подання, це не буде працювати.
htafoya

Одним із рішень є створення рекурсивної функції, передаючи ViewGroup як параметр. Перевірте клас для всіх його дітей, вимкніть його, якщо це EditText.
StoneLam

126

цей є рекурсивним для 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);
       }
    }
}

Хороший фрагмент, але прокручувані перегляди все одно можна буде прокручувати, для додаткової функціональності потрібен ще якийсь код
htafoya

Спінери не отримують інвалідів, не впевнені, чому :(
Вівек Сінгх

ViewPagers також не відключаються, включаючи види всередині нього.
Рафаель С

1
Це не працює, оскільки реалізація setEnabled () лежить на підкласі подання, іншими словами, вона може бути реалізована по-різному для різних поглядів. Тож такий підхід не зможе спрацювати для будь-якої існуючої точки зору
RexSplode

83

Відповідь пачки на правильному шляху, але його рекурсія трохи незграбна. Я думаю, що це чистіше:

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

Відмінне рішення. Дякую
Blodhgard

Це правильна відповідь. Це проходить рекурсивно. Поточна прийнята відповідь йде лише на один рівень глибше.
Stealth Rabbi

Це найкраща відповідь. Це вимкнуло всі штрихи всередині макета. Це те, що я хотів. Дякую!
Дініт Рукшан Кумара

24

Насправді, що для мене працює:

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

і скасувати це:

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

3
Гарне просте рішення, яке робить роботу!
Schm1,

2
Це рішення вимкне всі представлення даних про діяльність. Не стосується цього питання. Що робити, якщо метою є відключити лише певні групи перегляду в цій діяльності?
AlanKley

2
це саме я шукав, дякую !! Але тоді я можу визначити, чи хоче користувач десь клацнути?
Skizo-ozᴉʞS

1
Чудове просте рішення
WHOATEMYNOODLES

1
найкраще рішення, якщо ви хочете відключити / увімкнути лише один або набір переглядів, використовуйте setEnabled (bool) або якщо всі подання є дочірніми з одного циклу перегляду у всіх дочірніх елементах цього подання та відключити їх усі, але це рішення я вважаю найкращим (Я маю на увазі цю відповідь) дякую
Айдан

21

Якщо ви зацікавлені у відключенні переглядів у певній ViewGroup, тоді ви можете використовувати цікаве, можливо, трохи неясне duplicateParentState. Стан перегляду - це набір булевих атрибутів, таких як натиснуті, увімкнені, активовані та інші. Просто використовуйте це для кожної дитини, яку ви хочете синхронізувати з батьківською ViewGroup:

android:duplicateParentState="true"

Зверніть увагу, що він дублює весь стан, а не лише увімкнений стан. Це може бути те, що ти хочеш! Звичайно, такий підхід найкращий, якщо ви завантажуєте макет XML.


13

Давайте змінимо код 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);
   }
 }
}

Думаю, немає сенсу просто вимикати групу перегляду. Якщо ви хочете це зробити, є інший спосіб, який я використав із точно цією ж метою. Створіть представлення як брата або сестру вашого групового перегляду:

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

а під час виконання зробіть це видимим. Примітка: батьківський макет групи view повинен бути відносним або макетом кадру. Сподіваюся, це допоможе.


1
Ваш код не вимкне, наприклад, Spinner, оскільки Spinner розширює ViewGroup
qbait

12

Якщо якийсь відчайдушний розробник прокручує сюди, у мене є інший варіант зробити це. Що також відключає прокрутку, наскільки я експериментував з нею. Ідея полягає в тому, щоб використовувати елемент View, подібний до цього, у RelativeLayout, під усіма елементами вашого інтерфейсу.

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

Отже, він встановлений для того, щоб "пропасти" перед якоюсь умовою. А потім ви встановлюєте для видимості значення VISIBLE, коли ви хочете вимкнути свій інтерфейс. Також вам потрібно застосувати OnClickListenerдля цього подання. Це onClickListenerсприймає подію кліку та не передає її базовим елементам.


1
Це те, що я шукав, так, я був у відчаї і знайшов, що ваше рішення прокручується як божевільний: D
Skizo-ozᴉʞS

1
Дуже приємне рішення, насправді я це мав на увазі, і я шукав когось іншого з такою ж ідеєю, тому я не божевільний одиночка; D
Рікард

12

Я особисто використовую щось подібне (вертикальний обхід дерева з використанням рекурсії)

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

використання:

   viewGroup.deepForEach { isEnabled = false }

1
елегантне рішення.
Рафаель С

Відсутній forEachметод, я думаю
Skizo-ozᴉʞS

@ Skizo-ozᴉʞS це androidx.core.viewметод: developer.android.com/reference/kotlin/androidx/core/view/…
Achraf Amil

5

Деталі

  • Android studio 3.1.4
  • Котлін 1.2.70
  • зареєстровано в minSdkVersion 19

Рішення

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

Використання

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  }

Працював як шарм;)
Skizo-ozᴉʞS

3

Незважаючи на те, що це не зовсім те саме, як вимкнення переглядів у макеті, варто згадати, що ви можете запобігти всім дітям отримувати дотики (без необхідності повторювати ієрархію макета), замінюючи метод 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);
    }

}

Тоді ви можете перешкодити дітям отримувати сенсорні події:

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

Якщо ви ввімкнули прослуховувач кліків layout, він все одно буде спрацьовувати.


Люблю цю відповідь. Досить невелика вага та ефективність у порівнянні з постійним переглядом ViewGroup, щоб вимкнути всіх дітей! Щоб вирішити проблему з тим, що макет все ще відповідає на клацання, ви можете просто відключити / увімкнути макет у setInterceptTouchEvents ()
AlanKley

як щодо передачі контексту в cinstructor? Ви не можете створити вигляд без контексту
Вальдманн

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

і викликати метод таким чином:

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

2

У Kotlin ви можете використовувати, isDuplicateParentStateEnabled = trueперш ніж Viewдодано до ViewGroup.

Як задокументовано у setDuplicateParentStateEnabledметоді, якщо дочірнє подання має додаткові стани (наприклад, перевірений стан для прапорця), на них батьки не впливатимуть.

Аналогом xml є android:duplicateParentState="true".


1

Це досить відкладена відповідь, але це може комусь допомогти. Багато згаданих вище відповідей здаються хорошими. Але якщо у вашому layout.xml є вкладені групи перегляду. Тоді наведені вище відповіді можуть не дати повного результату. Тому я опублікував свою думку як фрагмент. За допомогою коду нижче можна вимкнути всі представлення даних (включаючи вкладені групи перегляду).

ПРИМІТКА. Спробуйте уникати вкладених ViewGroups, оскільки вони не рекомендуються.

 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

Встановити

android:descendantFocusability="blocksDescendants"

для вашого перегляду ViewGroup. Усі нащадки не будуть фокусувати увагу.


Він не питає про фокус.
Stealth Rabbi

0

Використовуйте нижче рекурсивну функцію, щоб зробити перегляди вашої дитини видимими або зниклими . Перший аргумент - це ваш батьківський погляд, а другий аргумент вирішує, чи хочете ви, щоб дочірні елементи батьківського подання були видимими чи відсутніми. true = видимий false = зник

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

питання стосувалось відключення, не приховування поглядів
Вальдманн

0

Якщо ви хочете відключити набір або сказати певний вид подання. Скажімо, ви хочете вимкнути фіксовану кількість кнопок з певним текстом тексту або його відсутністю, тоді ви можете використовувати масив цього типу та прокрутити елементи масиву. під час вимкнення кнопок за допомогою властивості setEnabled (false) Ви можете зробити це під час виклику функції, як це:

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

0

Я вдосконалив відповідь tütü, щоб правильно вимкнути компоненти EditText та RadioButton. Крім того, я ділюсь способом, який, як я виявив, змінює видимість перегляду та додає прозорість у вимкнених поданнях.

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

Мої два центи функціонують без рекурсії

    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

Найпростіший спосіб - створити <View у вашому xml, з match_parent для висоти та ширини, переконайтесь, що подання перевищує всі інші подання, тоді, коли ви хочете запобігти клацанням, зробіть його видимим, додайте onClickListener до цього подання з параметром null .

Приклад:

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

Тоді у вашому коді:

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

0

Мені подобається мати контроль над кореневим видом, тому я додав includeSelfпрапор доdeepForEach

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.  

Це дозволить вам динамічно керувати всіма станами одночасно з батьківського подання.

<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

щоб вимкнути представлення, потрібно викликати метод setEnabled із значенням false для аргументу. напр .:

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

-1

Для мене RelativeLayout або будь-який інший макет у кінці xml-файлу з шириною та висотою, встановленими на match_parent з атрибутом focusable та clickkable встановленим на 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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.