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

Sci*_*cit 69 android android-layout

例如,我有:

<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>
Run Code Online (Sandbox Code Playgroud)

有没有办法禁用(setEnable(false))LinearLayout中的所有元素my_layout

tüt*_*ütü 116

这个是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);
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 它不起作用,因为 setEnabled() 的实现位于视图的子类上,换句话说,它可以针对不同的视图以不同的方式实现。因此这种方法不可能适用于现有的所有视图 (2认同)

4e6*_*4e6 89

另一种方法是在每个子节点上调用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);
}
Run Code Online (Sandbox Code Playgroud)

  • 但是,这仅适用于第一级子级,如果您有嵌套视图则不起作用. (17认同)

Eri*_*ran 70

图图的答案是在正确的轨道上,但他的递归有点尴尬.我认为这更清洁:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ida*_*led 19

实际上对我来说有用的是:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Run Code Online (Sandbox Code Playgroud)

并撤消它:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Run Code Online (Sandbox Code Playgroud)

  • 很棒的简单解决方案,做到了这一点 (3认同)
  • 此解决方案将禁用活动中的所有视图。并没有真正解决这个问题。如果目标是仅禁用活动中的某些 ViewGroup,该怎么办? (2认同)
  • 这正是我要找的,谢谢!!但是我可以检测用户是否想要点击某个地方? (2认同)

Ach*_*mil 15

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

fun ViewGroup.deepForEach(function: View.() -> Unit) {
    this.forEach { child ->
        child.function()
        if (child is ViewGroup) {
            child.deepForEach(function)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法 :

   viewGroup.deepForEach { isEnabled = false }
Run Code Online (Sandbox Code Playgroud)


bob*_*hox 11

让我们改变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);
   }
 }
}
Run Code Online (Sandbox Code Playgroud)

我认为,只是让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" />
Run Code Online (Sandbox Code Playgroud)

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


and*_*guy 11

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

android:duplicateParentState="true"
Run Code Online (Sandbox Code Playgroud)

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


Rex*_*ode 9

如果一些绝望的开发人员在这里向下滚动,我还有另外一个选择.就我实验而言,这也禁用了滚动.我们的想法是在所有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"/>
Run Code Online (Sandbox Code Playgroud)

因此它在某些条件之前被设置为"消失".然后,当您要禁用UI时,将其可见性设置为VISIBLE.此外,您必须实现OnClickListener此视图.这onClickListener将捕获click事件,并且不会将其传递给底层元素.


Vas*_*huk 8

细节

  • 安卓工作室 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

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  }
Run Code Online (Sandbox Code Playgroud)


ArM*_*372 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

并调用这样的方法:

RelativeLayout rl_root = (RelativeLayout) findViewById(R.id.rl_root);
disableLL(rl_root);
Run Code Online (Sandbox Code Playgroud)


Tra*_*vis 5

虽然与禁用布局中的视图不太一样,但值得一提的是,您可以通过覆盖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);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后你可以阻止孩子接收触摸事件:

InterceptTouchEventFrameLayout layout = (InterceptTouchEventFrameLayout) findViewById(R.id.layout);
layout.setInterceptTouchEvents(true);
Run Code Online (Sandbox Code Playgroud)

如果您在 上设置了点击侦听器layout,它仍会被触发。