【问题标题】:How can I disable all views inside the layout?如何禁用布局内的所有视图?
【发布时间】:2011-08-15 18:19:39
【问题描述】:

例如我有:

<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 内的所有元素?

【问题讨论】:

    标签: android android-layout


    【解决方案1】:

    这个对于 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);
           }
        }
    }
    

    【讨论】:

    • 不错的 sn-p,但滚动视图仍然可以滚动,需要更多代码来实现附加功能
    • 纺纱机没有被禁用不知道为什么:(
    • ViewPagers 也不会被禁用,包括其中的视图。
    • 它不起作用,因为 setEnabled() 的实现位于视图的子类上,换句话说,它可以针对不同的视图以不同的方式实现。因此,这种方法不可能适用于现有的每个视图
    【解决方案2】:

    我个人使用这样的东西(使用递归的垂直树遍历)

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

    用法:

       viewGroup.deepForEach { isEnabled = false }
    

    【讨论】:

    【解决方案3】:

    tutu 的答案是在正确的轨道上,但他的递归有点尴尬。我认为这更干净:

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

    【讨论】:

    • 这是正确的答案。它递归地进行。当前接受的答案只深一层。
    • 这是最好的答案。这禁用了布局内的所有触摸。这就是我想要的。谢谢!
    【解决方案4】:

    另一种方法是在每个孩子上调用 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);
    }
    

    【讨论】:

    • 但是这仅适用于第一级子级,如果您有嵌套视图,它将不起作用。
    • 一种解决方案是创建一个递归函数,将 ViewGroup 作为参数传递。检查每个孩子的班级,如果它是 EditText,则禁用它。
    【解决方案5】:

    其实对我有用的是:

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

    并撤消它:

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

    【讨论】:

    • 此解决方案将禁用活动中的所有视图。并没有真正解决这个问题。如果目标是仅禁用 Activity 中的某些 ViewGroup 怎么办?
    • 这正是我要找的,谢谢!!但是我可以检测到用户是否想点击某个地方?
    • 如果您只想禁用/启用一个或一组视图,请使用 setEnabled(bool) 或者如果视图都是一个视图的所有子视图,则循环遍历该视图的所有子视图并全部禁用它们但我认为这个解决方案是最好的(我的意思是这个答案)谢谢 Idan
    【解决方案6】:
      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);
        }
    }
    

    并像这样调用方法:

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

    【讨论】:

      【解决方案7】:

      详情

      • Android 工作室 3.1.4
      • Kotlin 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  }
      

      【讨论】:

        【解决方案8】:

        如果您有兴趣禁用特定 ViewGroup 中的视图,那么您可以使用有趣的,也许有点晦涩的duplicateParentState。视图状态是一组布尔属性,例如按下、启用、激活等。只需在您要同步到父 ViewGroup 的每个孩子上使用它:

        android:duplicateParentState="true"
        

        请注意,它会复制整个状态,而不仅仅是启用状态。这可能是你想要的!当然,如果您正在加载布局 XML,这种方法是最好的。

        【讨论】:

          【解决方案9】:

          我改进了 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);
          }
          

          【讨论】:

            【解决方案10】:

            虽然与禁用布局中的视图不太一样,但值得一提的是,您可以防止所有子级接收触摸(无需递归布局层次结构) 通过覆盖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() 中禁用/启用布局
            • 如何将上下文传递给 cinstructor?没有上下文就无法创建视图
            • 这是生产应用程序最有效的解决方法。
            【解决方案11】:
            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>
            

            【讨论】:

              【解决方案12】:

              如果一些绝望的开发者向下滚动到这里,我还有另一个选择。据我试验,这也禁用了滚动。我们的想法是在所有 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"/>
              

              所以它在某些条件之前被设置为“消失”。然后,当您想禁用 UI 时,将其可见性设置为 VISIBLE。您还必须为此视图实施OnClickListener。这个onClickListener 将捕获点击事件并且不会将其传递给底层元素。

              【讨论】:

              • 这就是我一直在寻找的,是的,我很绝望,发现你的解决方案像疯了一样滚动:D
              • 相当不错的解决方案,实际上我已经想到了,我正在寻找其他有相同想法的人,所以我不是一个疯狂的孤独者;D
              【解决方案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);
                 }
               }
              }
              

              我认为,仅仅禁用视图组是没有意义的。如果你想这样做,我还有另一种方法用于完全相同的目的。将视图创建为 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" />
              

              并在运行时使其可见。注意:您的 groupview 的父布局应该是相对布局或框架布局。希望这会有所帮助。

              【讨论】:

              • 您的代码不会禁用,例如Spinner,因为 Spinner 扩展了 ViewGroup
              【解决方案14】:

              要禁用视图,您必须调用 setEnabled 方法,参数为 false。 例如:

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

              【讨论】:

                【解决方案15】:

                在 Kotlin 中,您可以在将 View 添加到 ViewGroup 之前使用 isDuplicateParentStateEnabled = true

                setDuplicateParentStateEnabled 方法中所述,如果子视图具有其他状态(例如复选框的选中状态),则这些状态不会受到父视图的影响。

                xml 类比是android:duplicateParentState="true"

                【讨论】:

                  【解决方案16】:

                  设置

                  android:descendantFocusability="blocksDescendants"
                  

                  用于您的 ViewGroup 视图。所有后代都不会聚焦。

                  【讨论】:

                  • 他不是在问焦点。
                  【解决方案17】:

                  这是一个相当延迟的答案。但它可能会对某人有所帮助。上面提到的许多答案似乎都很好。但是如果你的 layout.xml 有嵌套的视图组。那么上面的答案可能无法提供完整的结果。因此,我以 sn-p 的身份发表了我的意见。使用下面的代码可以禁用所有视图(包括嵌套视图组)。

                  注意:尽量避免嵌套 ViewGroup,因为不推荐使用它们。

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

                  【讨论】:

                    【解决方案18】:

                    对于我来说,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>
                    

                    【讨论】:

                      【解决方案19】:

                      使用以下递归函数使您的子视图可见消失。 第一个参数是您的父视图,第二个参数决定您是否希望父视图的子视图可见或消失。 真 = 可见假 = 消失

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

                      【讨论】:

                      • 问题是关于禁用而不是隐藏视图
                      【解决方案20】:

                      最简单的方法是在您的 xml 中创建一个

                      例子:

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

                      【讨论】:

                        【解决方案21】:

                        如果您想禁用一组或说一种特定类型的视图。假设您想禁用具有某些特定文本或没有文本的固定数量的按钮 然后您可以使用该类型的数组并循环遍历数组元素,同时使用 setEnabled(false) 属性禁用按钮您可以在这样的函数调用中执行此操作:

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

                        【讨论】:

                          【解决方案22】:

                          我的两分钱函数没有递归

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

                          【讨论】:

                            【解决方案23】:

                            我喜欢控制根视图,所以我将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) }
                                    }
                                }
                            }
                            

                            【讨论】:

                              猜你喜欢
                              • 2013-11-17
                              • 2012-02-23
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2010-12-12
                              • 1970-01-01
                              • 2016-11-20
                              相关资源
                              最近更新 更多