레이아웃 내의 모든보기를 비활성화하려면 어떻게해야합니까?


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>

LinearLayout 내부의 모든 요소를 ​​비활성화 (setEnable (false))하는 방법이 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 2012-07-12

한 가지 해결책은 재귀 함수를 만들고 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);
       }
    }
}

좋은 조각은,하지만 scrollviews 여전히 스크롤 될 것입니다, 좀 더 코드가 추가 기능을 위해 필요
— htafoya

스피너가 왜 비활성화되지 않았는지 확실하지 않습니다 :(
— Vivek Singh

ViewPagers는 내부 뷰를 포함하여 비활성화되지 않습니다.
— Raphael C

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 2015-08-16

이것이 정답입니다. 재귀 적으로 진행됩니다. 현재 받아 들여지는 답변은 한 단계 만 진행됩니다.
— Stealth Rabbi

이것이 최고의 답변입니다. 이것은 레이아웃 내부의 모든 터치를 비활성화했습니다. 그것이 내가 원했던 것입니다. 감사!
— Dinith Rukshan Kumara

24

실제로 나를 위해 일하는 것은 :

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

실행 취소하려면 :

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

3
작업을 수행하는 멋진 간단한 솔루션!
— Schm1 2010 년

2
이 솔루션은 활동의 모든보기를 비활성화합니다. 실제로 질문을 해결하지 않습니다. 활동에서 특정 ViewGroup 만 비활성화하는 것이 목표 인 경우 어떻게됩니까?
— AlanKley

2
바로 제가 찾고 있던 것입니다. 감사합니다 !! 하지만 사용자가 어딘가를 클릭하고 싶은지 감지 할 수 있습니까?
— Skizo-ozᴉʞS

1
훌륭한 간단한 솔루션
— WHOATEMYNOODLES

1
하나 또는 뷰 세트 만 비활성화 / 활성화하려면 setEnabled (bool)를 사용하거나 뷰가이 뷰의 모든 자식을 통해 한 뷰 루프의 모든 자식 인 경우 모두 비활성화하지만이 솔루션은 최선이라고 생각합니다. (나는이 대답을 의미합니다) 감사합니다 Idan
— Mohammad Elsayed

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

뷰 그룹을 비활성화하는 데는 의미가 없다고 생각합니다. 당신이 그것을 원한다면, 정확히 같은 목적으로 사용한 또 다른 방법이 있습니다. 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" />

런타임에 표시되도록합니다. 참고 : 그룹보기의 상위 레이아웃은 상대 레이아웃이거나 프레임 레이아웃이어야합니다. 이것이 도움이되기를 바랍니다.


1
Spinner가 ViewGroup을 확장하기 때문에 귀하의 코드는 예를 들어 Spinner를 비활성화하지 않습니다
— qbait

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클릭 이벤트를 포착하고 기본 요소로 전달하지 않습니다.


1
그게 제가 찾던 것입니다. 네, 필사적이었고 당신의 솔루션이 미친 듯이 스크롤되는 것을 발견했습니다. : D
— Skizo-ozᴉʞS

1
꽤 좋은 해결책, 실제로 나는 그것을 내 마음에 가지고 있었고 나는 같은 생각을 가진 다른 사람을 찾고 있었기 때문에 나는 미친 외톨이가 아닙니다 .D
— Ricard

12

나는 개인적으로 이와 같은 것을 사용합니다 (재귀를 사용한 수직 트리 순회)

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

사용법 :

   viewGroup.deepForEach { isEnabled = false }

1
우아한 솔루션.
— Raphael C

forEach내가 추측 하는 방법을 놓치고있다
— Skizo-ozᴉʞS

Skizo - ozᴉʞS @ 그것은이다 androidx.core.view방법 : developer.android.com/reference/kotlin/androidx/core/view/...
— 라프 Amil

5

세부

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

매력처럼 일했습니다;)
— 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

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

코 틀린에서는 사용할 수 isDuplicateParentStateEnabled = true가되기 전에 View받는 사람에 추가됩니다 ViewGroup.

setDuplicateParentStateEnabled메서드에 설명 된대로 자식보기에 추가 상태 (예 : 확인란에 대해 선택된 상태)가 있으면 부모의 영향을받지 않습니다.

xml 아날로그는 android:duplicateParentState="true".


1

아래의 재귀 함수를 사용하여 자식보기를 표시 하거나 사라 집니다. 첫 번째 인수는 부모보기이고 두 번째 인수는 부모보기의 자식을 표시할지 여부를 결정합니다. 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);
    }
}

1

이것은 꽤 지연된 답변이지만 누군가에게 도움이 될 수 있습니다. 위에서 언급 한 많은 답변이 좋은 것 같습니다. 그러나 layout.xml에 중첩 된 뷰 그룹이있는 경우. 그러면 위의 답변이 완전한 결과를 제공하지 못할 수 있습니다. 따라서 나는 내 의견을 스 니펫으로 게시했습니다. 아래 코드를 사용하면 모든 뷰를 비활성화 할 수 있습니다 (중첩 된 뷰 그룹 포함).

참고 : 중첩 된 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);
        }
    }
}

0

세트

android:descendantFocusability="blocksDescendants"

ViewGroup보기를 위해. 모든 후손은 초점을 맞추지 않습니다.


그는 초점에 대해 묻지 않습니다.
— Stealth Rabbi

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

EditText 및 RadioButton 구성 요소를 제대로 비활성화하기 위해 tütü 응답을 개선했습니다 . 게다가 뷰 가시성을 변경하고 비활성화 된 뷰에 투명성을 추가하는 방법을 공유하고 있습니다.

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

내 2 센트는 재귀없이 작동합니다.

    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

가장 쉬운 방법은 높이와 너비에 대해 match_parent를 사용하여 <View를 XML에 만들고보기가 다른 모든보기 위에 있는지 확인한 다음 클릭을 방지하려면 해당보기에 onClickListener를 매개 변수로 추가하여 표시되도록하는 것입니다. .

예:

<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

뷰를 비활성화하려면 인수에 대해 false를 사용하여 setEnabled 메서드를 호출해야합니다. 전의:

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

-1

나를 위해 RelativeLayout 또는 너비와 높이가 match_parent로 설정된 xml 파일 끝에있는 다른 레이아웃과 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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.