Düzen içindeki tüm görünümleri nasıl devre dışı bırakabilirim?


84

Örneğin:

<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 içindeki tüm öğeleri devre dışı bırakmanın (setEnable (false)) bir yolu var mı my_layout?

Yanıtlar:


98

Diğer bir yol, her çocuk için setEnabled () işlevini çağırmaktır (örneğin, devre dışı bırakmadan önce çocuk üzerinde fazladan kontrol yapmak istiyorsanız)

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
Ancak bu yalnızca birinci düzey çocuklar için işe yarar, iç içe görünümleriniz varsa işe yaramaz.
htafoya

Çözümlerden biri, özyinelemeli bir işlev yapmak, bir ViewGroup'u parametre olarak iletmektir. Sınıfı her alt öğesi için kontrol edin, bir EditText ise devre dışı bırakın.
StoneLam

126

bu ViewGroups için özyinelemeli

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

İyi snippet, ancak
kaydırma görünümleri

İplikçiler devre dışı kalmıyor neden emin değilim :(
Vivek Singh

ViewPager'lar, içindeki görünümler de dahil olmak üzere devre dışı bırakılmaz.
Raphael C

1
SetEnabled () uygulaması görünümün alt sınıfında yer aldığından, başka bir deyişle farklı görünümler için farklı şekilde uygulanabildiğinden işe yaramaz. Yani orada böyle bir yaklaşım varlığını tüm görünümler için çalışacak hiçbir şekilde
RexSplode

83

tutu'nun cevabı doğru yoldadır, ancak yinelemesi biraz tuhaftır. Bunun daha temiz olduğunu düşünüyorum:

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

Mükemmel çözüm. Teşekkürler
Blodhgard

Bu doğru cevap. Yinelemeli olarak geçer. Şu anda kabul edilen cevap yalnızca bir seviye derine iniyor.
Stealth Rabbi

Bu en iyi cevap. Bu, düzen içindeki tüm dokunuşları devre dışı bıraktı. İstediğim buydu. Teşekkürler!
Dinith Rukshan Kumara

24

Aslında benim için işe yarayan şey:

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

ve geri almak için:

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

3
İşi yapan güzel basit çözüm!
Schm1

2
Bu çözüm, faaliyetteki tüm görünümleri devre dışı bırakacaktır. Soruyu gerçekten ele almıyor. Ya amaç, etkinlikteki yalnızca belirli Görünüm Gruplarını devre dışı bırakmaksa?
AlanKley

2
tam olarak arıyordum, teşekkürler !! Ama sonra kullanıcının bir yere tıklamak isteyip istemediğini tespit edebilir miyim?
Skizo-ozᴉʞS

1
Harika basit çözüm
WHOATEMYNOODLES

1
Yalnızca bir veya bir dizi görünümü devre dışı bırakmak / etkinleştirmek istiyorsanız en iyi çözüm setEnabled (bool) 'u kullanın veya görünümler bu görünümün tüm alt öğeleri boyunca bir görünüm döngüsünün tüm alt öğeleri ise ve hepsini devre dışı bırakın ama bu çözümün en iyisi olduğunu düşünüyorum (Bu cevabı kastediyorum) teşekkürler İdan
Mohammad Elsayed

21

Belirli bir ViewGroup'taki görünümleri devre dışı bırakmakla ilgileniyorsanız, ilginç, belki biraz belirsiz olanı kullanabilirsiniz duplicateParentState. Görünüm durumu, basılmış, etkinleştirilmiş, etkinleştirilmiş ve diğerleri gibi bir dizi boole öznitelikleridir. Bunu ana ViewGroup ile senkronize etmek istediğiniz her çocukta kullanın:

android:duplicateParentState="true"

Yalnızca etkin durumu değil, tüm durumu kopyaladığını unutmayın. İstediğin bu olabilir! Elbette, bu yaklaşım, düzen XML'i yüklüyorsanız en iyisidir.


13

Tütü'nün kodunu değiştirelim

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

Bence, sadece görüntüleme grubunu devre dışı bırakmanın bir anlamı yok. Bunu yapmak istiyorsanız, tamamen aynı amaç için kullandığım başka bir yol var. Grup görünümünüzün kardeşi olarak görünüm oluşturun:

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

ve çalışma zamanında görünür hale getirin. Not: Grup görünümünüzün ana düzeni, göreceli veya çerçeve düzeni olmalıdır. Umarım bu yardımcı olur.


1
Kodunuz örneğin Spinner'ı devre dışı bırakmayacak, çünkü Spinner ViewGroup'u genişletiyor
qbait

12

Çaresiz bir geliştirici buraya kaydırırsa, bunu yapmak için başka bir seçeneğim var. Bu da denediğim kadarıyla kaydırmayı devre dışı bırakıyor. Buradaki fikir, tüm UI öğelerinizin altında RelativeLayout'ta bunun gibi View öğesini kullanmaktır.

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

Bu nedenle, bazı koşullardan önce "gitmiş" olacak şekilde ayarlanmıştır. Ve ardından, kullanıcı arayüzünüzü devre dışı bırakmak istediğinizde görünürlüğünü GÖRÜNÜR olarak ayarlarsınız. Ayrıca OnClickListenerbu Görünüm için uygulamanız gerekir . Bu onClickListener, tıklama olayını yakalar ve onu temeldeki öğelere iletmez.


1
İşte aradığım buydu, evet çaresizdim ve çözümünüzü çılgın gibi
kayarken buldum

1
Oldukça güzel bir çözüm, aslında aklımdaydım ve aynı fikre sahip başka birini arıyordum, bu yüzden çılgın bir yalnız değilim; D
Ricard,

12

Ben şahsen bunun gibi bir şey kullanıyorum (özyineleme kullanarak dikey ağaç geçişi)

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

kullanım:

   viewGroup.deepForEach { isEnabled = false }

1
zarif çözüm.
Raphael C

forEachSanırım yöntem eksik
Skizo-ozᴉʞS

@ Skizo-ozᴉʞS bir androidx.core.viewyöntemdir: developer.android.com/reference/kotlin/androidx/core/view/…
Achraf Amil

5

Detaylar

  • Android studio 3.1.4
  • Kotlin 1.2.70
  • minSdkVersion 19'da kontrol edildi

Çözüm

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

Kullanım

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  }

Bir cazibe gibi çalıştı;)
Skizo-ozᴉʞS

3

Bir mizanpaj içindeki görünümleri devre dışı bırakmakla tamamen aynı olmasa da , ViewGroup # onInterceptTouchEvent (MotionEvent) yöntemini geçersiz kılarak tüm çocukların dokunma almasını (mizanpaj hiyerarşisini tekrarlamak zorunda kalmadan) engelleyebileceğinizi belirtmek gerekir :

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

}

Böylece çocukların dokunma olaylarını almasını önleyebilirsiniz:

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

Ayarlanmış bir tıklama dinleyiciniz layoutvarsa, yine de tetiklenecektir.


Bu cevabı seviyorum. Tüm çocukları devre dışı bırakmak için sürekli ViewGroup'a kıyasla oldukça hafif ve verimli! Düzenin tıklamalara yanıt vermeye devam ettiği sorunu çözmek için,
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);
    }
}

ve şu şekilde arama yöntemi:

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

2

KOTLIN olarak, kullanabilirsiniz isDuplicateParentStateEnabled = trueönce Vieweklenir ViewGroup.

setDuplicateParentStateEnabledYöntemde belgelendiği gibi , alt görünümde ek durumlar varsa (bir onay kutusu için işaretli durum gibi), bunlar üst öğe tarafından etkilenmeyecektir.

Xml analogu android:duplicateParentState="true".


1

Özyinelemeli işlevi aşağıda kullanın çocuğunuzun görünümleri yapmak için görünür veya gitti . İlk argüman ebeveyn görünümünüzdür ve ikinci argüman ebeveyn görünümünün çocuklarının görünür mü yoksa kaybolmasını mı istediğinize karar verir. true = görünür yanlış = gitti

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

Bu oldukça gecikmiş bir cevap ama birine yardımcı olabilir. Yukarıda bahsedilen birçok cevap iyi görünüyor. Ancak layout.xml dosyanız iç içe görünüm gruplarına sahipse. O halde yukarıdaki cevaplar tam sonuç vermeyebilir. Bu yüzden fikrimi bir pasaj olarak yayınladım. Aşağıdaki kod ile tüm görünümler devre dışı bırakılabilir (İç İçe Görünüm Grupları Dahil).

NOT: Önerilmedikleri için iç içe geçmiş Görünüm Gruplarından kaçınmayı deneyin.

 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

Ayarlamak

android:descendantFocusability="blocksDescendants"

ViewGroup görünümü için. Tüm torunlar odaklanmayacak.


Odaklanma hakkında soru sormuyor.
Stealth Rabbi

0

Bir dizi görünümü devre dışı bırakmak veya belirli bir görünüm türünü söylemek istiyorsanız, belirli bir metin içeren veya metin içermeyen sabit sayıda düğmeyi devre dışı bırakmak istediğinizi varsayalım, bu türden bir dizi kullanabilir ve dizi öğeleri arasında döngü yapabilirsiniz. setEnabled (false) özelliğini kullanarak düğmeleri devre dışı bırakırken Bunu aşağıdaki gibi bir işlev çağrısında yapabilirsiniz:

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

0

EditText ve RadioButton bileşenlerini düzgün bir şekilde devre dışı bırakmak için tütü yanıtını geliştirdim . Ayrıca, görünüm görünürlüğünü değiştirdiğim ve devre dışı bırakılan görünümlere şeffaflık kattığım bir yolu paylaşıyorum.

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

Benim iki sentim özyineleme olmadan çalışıyor

    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

En kolay yol, xml'nizde yükseklik ve genişlik için match_parent ile bir <View oluşturmaktır, görünümün diğer tüm görünümlerin üzerinde olduğundan emin olun, ardından tıklamaları önlemek istediğinizde, o görünüme parametre olarak null ile bir onClickListener ekleyin .

Misal:

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

Sonra kodunuzda:

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

0

Eklediğim yüzden kök görünümüne üzerinde kontrol sahibi olmak includeSelfiçin bayrağı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.  

Bu, tüm durumları aynı anda üst görünümden dinamik olarak kontrol etmenizi sağlar.

<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

bir görünümü devre dışı bırakmak için, setEnabled yöntemini argüman için false ile çağırmalısınız. ör:

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

-1

Benim için RelativeLayout veya xml dosyasının sonundaki genişlik ve yükseklik odaklanabilir ve tıklanabilir niteliği true olarak ayarlanmış, match_parent olarak ayarlanmış başka bir düzen.

 <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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.