简体   繁体   English

如何禁用布局内的所有视图?

[英]How can I disable all views inside the layout?

For example I have:例如我有:

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

Is there a way to disable (setEnable(false)) all elements inside LinearLayout my_layout ?有没有办法禁用 (setEnable(false)) LinearLayout my_layout的所有元素?

this one is recursive for ViewGroups这个对于 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);
       }
    }
}

Another way is to call setEnabled() on each child (for example if you want to do some extra check on child before disabling)另一种方法是在每个孩子上调用 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);
}

tutu's answer is on the right track, but his recursion is a little awkward. tutu的答案是在正确的轨道上,但他的递归有点尴尬。 I think this is cleaner:我认为这更清洁:

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

Actully what work for me is:实际上对我有用的是:

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

and to undo it:并撤消它:

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

If you're interested in disabling views in a specific ViewGroup then you can use the interesting, perhaps slightly obscure duplicateParentState .如果您对禁用特定 ViewGroup 中的视图感兴趣,那么您可以使用有趣的,也许有点晦涩的duplicateParentState A view state is a set of boolean attributes such as pressed, enabled, activated, and others.视图 state 是一组 boolean 属性,例如按下、启用、激活等。 Just use this on each child you want to sync to parent ViewGroup:只需在要同步到父 ViewGroup 的每个孩子上使用它:

android:duplicateParentState="true"

Note that it duplicates the entire state and not just the enabled state.请注意,它复制了整个 state 而不仅仅是启用的 state。 This may be what you want, Of course.当然,这可能是您想要的。 this approach is best if you're loading layout XML.如果您正在加载布局 XML,这种方法是最好的。

I personally use something like this (vertical tree traversal using recursion)我个人使用这样的东西(使用递归的垂直树遍历)

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

usage:用法:

   viewGroup.deepForEach { isEnabled = false }

Let's change tütü's code让我们更改 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);
   }
 }
}

I think, there is no point in just making viewgroup disable.我认为,仅仅禁用视图组是没有意义的。 If you want to do it, there is another way I have used for exactly the same purpose.如果你想这样做,我还有另一种方法用于完全相同的目的。 Create view as a sibling of your groupview:将视图创建为 groupview 的兄弟:

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

and at run-time, make it visible.并在运行时使其可见。 Note: your groupview's parent layout should be either relative or frame layout.注意:您的 groupview 的父布局应该是相对布局或框架布局。 Hope this will help.希望这会有所帮助。

If some desperate developer scrolls down here, I have another option to do it.如果一些绝望的开发人员在这里向下滚动,我还有另一种选择。 Which also disables scrolling as far as I experimented with it.据我试验,这也禁用了滚动。 The idea is to use View element like this one in a RelativeLayout, under all your UI elements.这个想法是在所有 UI 元素下的 RelativeLayout 中使用像这样的 View 元素。

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

So it is set to be "gone" before some condition.所以它在某些条件之前被设置为“消失”。 And then you set it's visibility to VISIBLE when you want to disable your UI.然后,当您想禁用 UI 时,将其可见性设置为 VISIBLE。 Also you have to implement OnClickListener for this View.您还必须为此视图实现OnClickListener This onClickListener will catch click event and won't pass it to the underlying elements.onClickListener将捕获单击事件,并且不会将其传递给底层元素。

Details细节

  • Android studio 3.1.4 Android工作室3.1.4
  • Kotlin 1.2.70 Kotlin 1.2.70
  • checked in minSdkVersion 19签入 minSdkVersion 19

Solution解决方案

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

Usage用法

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  }

Although not quite the same as disabling views within a layout, it is worth mentioning that you can prevent all children from receiving touches (without having to recurse the layout hierarchy) by overriding the ViewGroup#onInterceptTouchEvent(MotionEvent) method:虽然与禁用布局中的视图不太一样,但值得一提的是,您可以通过覆盖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);
    }

}

Then you can prevent children from receiving touch events:然后可以防止孩子接收触摸事件:

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

If you have a click listener set on layout , it will still be triggered.如果您在layout上设置了点击监听器,它仍然会被触发。

  private void disableLL(ViewGroup layout){
    for (int i = 0; i < layout.getChildCount(); i++) {
        View child = layout.getChildAt(i);
        child.setEnabled(false);
        child.setClickable(false);
        if (child instanceof ViewGroup)
            disableLL((ViewGroup) child);
    }
}

and call method like this:并像这样调用方法:

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

In Kotlin, you can use isDuplicateParentStateEnabled = true before the View is added to the ViewGroup .在 Kotlin 中,您可以在将View添加到ViewGroup之前使用isDuplicateParentStateEnabled = true

As documented in the setDuplicateParentStateEnabled method, if the child view has additional states (like checked state for a checkbox), these won't be affected by the parent.setDuplicateParentStateEnabled方法中所述,如果子视图具有其他状态(例如选中 state 的复选框),则这些状态不会受到父视图的影响。

The xml analogue is android:duplicateParentState="true" . xml 模拟是android:duplicateParentState="true"

I improved the tütü response to properly disable EditText and RadioButton componentes.我改进了tütü响应以正确禁用 EditText 和 RadioButton 组件。 Besides, I'm sharing a way that I found to change the view visibility and add transparency in the disabled views.此外,我正在分享一种我发现的更改视图可见性并在禁用视图中添加透明度的方法。

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

This is a pretty delayed answer.But it might help someone.这是一个相当延迟的答案。但它可能会对某人有所帮助。 Many answers mentioned above seem to be good.上面提到的许多答案似乎都很好。 But if your layout.xml has nested viewgroups.但是如果你的 layout.xml 有嵌套的视图组。 Then above answers may not provide full result.那么上面的答案可能无法提供完整的结果。 Hence i have posted my opinion as a snippet.因此,我将我的意见作为片段发布。 With the code below one can disable all views (Including Nested ViewGroups).使用下面的代码可以禁用所有视图(包括嵌套视图组)。

NOTE: Try avoiding nested ViewGroups as they are not recommended.注意:尽量避免嵌套视图组,因为不推荐使用它们。

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

I like to have a control over the root view so I added the includeSelf flag to deepForEach我喜欢控制根视图,所以我将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) }
        }
    }
}

usage:用法:

   viewGroup.deepForEach (includeSelf: true) { isEnabled = false }
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.  

This will allow you to dynamically control all states at once from the parent view.这将允许您从父视图一次动态控制所有状态。

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

Set

android:descendantFocusability="blocksDescendants"

for yor ViewGroup view.用于您的 ViewGroup 视图。 All descendants will not take focus.所有的后代都不会集中注意力。

Use below recursive function to make your child views visible or gone .使用下面的递归 function 使您的子视图可见消失 First argument is your parent view and second argument decides if you want childs of parent view visible or gone.第一个参数是您的父视图,第二个参数决定您是否希望父视图的子视图可见或消失。 true = visible false = gone真 = 可见假 = 消失了

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

If you want to disable a set of, or say a particular kind of view.Let's say you want to disable a fixed number of buttons with some particular text of or no text then you can use array of that type and loop through the array elements while disabling the buttons using setEnabled(false) property You can do it on a function call like this:如果您想禁用一组视图,或者说一种特定类型的视图。假设您想禁用具有某些特定文本或没有文本的固定数量的按钮,那么您可以使用该类型的数组并循环遍历数组元素在使用 setEnabled(false) 属性禁用按钮时,您可以在 function 调用上执行此操作,如下所示:

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

My two cents function without recursion我的两分钱 function 无递归

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

Many answers are good here.这里有很多答案都很好。 But if child views may be change during initialization (eg in the case of RecyclerView ) you can use the Handler :但是如果子视图在初始化期间可能会发生变化(例如在RecyclerView的情况下),您可以使用Handler

fun ViewGroup.setEnabledDeep(enabled: Boolean) {
    Handler(Looper.getMainLooper()).post {
        isEnabled = enabled
        for (i: Int in 0..childCount) {
            val child: View = getChildAt(i) ?: continue
            child.isEnabled = enabled
            if (child is ViewGroup) {
                child.setEnabledDeep(enabled)
            }
        }
    }
}

Then:然后:

recyclerView.setEnabledDeep(false)

to disable a view, you must call the method setEnabled with false for argument.要禁用视图,您必须调用 setEnabled 方法,参数为 false。 ex:前任:

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

For me RelativeLayout or any other layout at the end of the xml file with width and height set to match_parent with attribute focusable and clickable set to true.对我来说,RelativeLayout 或 xml 文件末尾的任何其他布局,宽度和高度设置为 match_parent,属性可聚焦和可点击设置为 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>

The easiest way is creating a <View in your xml, with match_parent for height and width, make sure the view is above every other views, then when you want to prevent clicks, make it visible add an onClickListener to that view with null as parameter.最简单的方法是在 xml 中创建一个 <View,使用 match_parent 作为高度和宽度,确保该视图高于其他所有视图,然后当您想防止点击时,使其可见,使用 null 作为参数向该视图添加一个 onClickListener .

Example:例子:

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

Then in your code:然后在您的代码中:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何访问页脚xml布局内的视图? 安卓系统 - How can I access the views inside of a footer xml layout? Android 计时器运行时如何禁用所有布局的事件? - How can I disable the events of all the layout when timer is running? 如何在布局中独立视图 - How Can I independent the views in a layout 当从其中一个视图中按下ContextMenu项时,如何更新TabHost内部的所有视图? - How can I update the all the views inside a TabHost when pressing on a ContextMenu item from within one of the views? 如何使所有子视图在表布局中具有相同的长度? - How can I make all the child views have the same length in the table layout? 我如何保存线性布局及其所有内部视图并在以后的android中使用 - How I can save a linear layout and all its inner views and use it later android 如何判断布局(及其所有子视图)何时完全充气? - How can I tell when a Layout (and all its child Views) has fully finished inflating? 如何在相对布局或任何布局中动态添加视图 - How can I add Views dynamically in a Relative layout or in any Layout 如何在布局中包含 listView 以及布局中的其他视图 - How can I include listView in a layout with other views in the layout already 如何禁用android中线性布局内的所有内容? - How to disable all content inside linear layout in android?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM