Например у меня есть:
<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
?
это рекурсивно для 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); } } }
источник
Туту ответ на верный путь, но его рекурсия немного неудобна. Думаю, это чище:
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); } } }
источник
Собственно, что для меня работа:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
и отменить его:
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
источник
Если вас интересует отключение представлений в определенной ViewGroup, вы можете использовать интересный, возможно, немного неясный
duplicateParentState
. Состояние представления - это набор логических атрибутов, таких как нажатие, включение, активация и другие. Просто используйте это для каждого дочернего элемента, который вы хотите синхронизировать с родительской ViewGroup:android:duplicateParentState="true"
Обратите внимание, что он дублирует все состояние, а не только включенное состояние. Это может быть то, что вы хотите! Конечно, этот подход лучше всего, если вы загружаете XML макета.
источник
Давайте изменим код 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); } } }
Думаю, нет смысла просто отключать viewgroup. Если вы хотите сделать это, я использовал другой способ для той же цели. Создайте представление как одно из двух представлений группы:
<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, подобный этому, в RelativeLayout под всеми вашими элементами пользовательского интерфейса.
<View android:id="@+id/shade" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/primaryShadow" android:visibility="gone"/>
Таким образом, он должен «исчезнуть» перед определенным условием. И затем вы устанавливаете его видимость на ВИДИМОСТЬ, когда хотите отключить свой пользовательский интерфейс. Также вы должны реализовать
OnClickListener
это представление. ЭтоonClickListener
перехватит событие щелчка и не передаст его базовым элементам.источник
Я лично использую что-то вроде этого (обход вертикального дерева с использованием рекурсии)
fun ViewGroup.deepForEach(function: View.() -> Unit) { this.forEach { child -> child.function() if (child is ViewGroup) { child.deepForEach(function) } } }
Применение :
viewGroup.deepForEach { isEnabled = false }
источник
forEach
Мне кажется, не хватает методаandroidx.core.view
метод: developer.android.com/reference/kotlin/androidx/core/view/ ...Детали
Решение
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 }
источник
Хотя это не совсем то же самое, что отключение представлений в макете, стоит упомянуть, что вы можете запретить всем дочерним элементам получать касания (без необходимости повторять иерархию макета), переопределив метод 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
, он все равно будет запускаться.источник
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);
источник
В Kotlin вы можете использовать
isDuplicateParentStateEnabled = true
доView
добавления вViewGroup
.Как указано в
setDuplicateParentStateEnabled
методе, если дочернее представление имеет дополнительные состояния (например, отмеченное состояние для флажка), они не будут затронуты родителем.Аналог xml есть
android:duplicateParentState="true"
.источник
Используйте рекурсивную функцию ниже, чтобы сделать ваши дочерние представления видимыми или исчезнувшими . Первый аргумент - это ваше родительское представление, а второй аргумент решает, хотите ли вы, чтобы дочерние элементы родительского представления были видны или исчезли. истина = видимая ложь = ушла
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); } }
источник
Это довольно запоздалый ответ, но он может кому-то помочь. Многие ответы, упомянутые выше, кажутся хорошими. Но если ваш layout.xml имеет вложенные группы просмотра. Тогда приведенные выше ответы могут не дать полного результата. Поэтому я опубликовал свое мнение в виде фрагмента. С помощью приведенного ниже кода можно отключить все представления (включая вложенные группы просмотра).
ПРИМЕЧАНИЕ. Старайтесь избегать вложенных групп просмотра, поскольку они не рекомендуются.
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); } } }
источник
Набор
android:descendantFocusability="blocksDescendants"
для вашего просмотра ViewGroup. Всех потомков в фокус не возьмут.
источник
Если вы хотите отключить набор или, скажем, определенный вид представления. Допустим, вы хотите отключить фиксированное количество кнопок с определенным текстом или без текста, тогда вы можете использовать массив этого типа и перебирать элементы массива при отключении кнопок с помощью свойства setEnabled (false). Это можно сделать при вызове функции следующим образом:
public void disable(){ for(int i=0;i<9;i++){ if(bt[i].getText().equals("")){//Button Text condition bt[i].setEnabled(false); } } }
источник
Я улучшил ответ 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); }
источник
Мои два цента работают без рекурсии
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 } } } }
источник
Самый простой способ - создать <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)
источник
Мне нравится контролировать корневое представление, поэтому я добавил
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) } } } }
источник
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>
источник
чтобы отключить представление, вы должны вызвать метод setEnabled с false в качестве аргумента. пример:
Button btn = ... btn.setEnabled(false);
источник
Для меня RelativeLayout или любой другой макет в конце файла xml с шириной и высотой, установленными на match_parent, с атрибутом focusable и clickable, установленным на 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>
источник