Làm cách nào để tắt tất cả các chế độ xem bên trong bố cục?


83

Ví dụ tôi có:

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

Có cách nào để tắt (setEnable (false)) tất cả các phần tử bên trong LinearLayout my_layoutkhông?

Câu trả lời:


98

Một cách khác là gọi setEnabled () trên từng đứa trẻ (ví dụ: nếu bạn muốn kiểm tra thêm đối với đứa trẻ trước khi tắt)

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
Tuy nhiên, điều này chỉ hoạt động đối với trẻ cấp đầu tiên, nếu bạn có các chế độ xem lồng nhau thì nó sẽ không hoạt động.
htafoya

Một giải pháp là tạo một hàm đệ quy, truyền một ViewGroup làm tham số. Kiểm tra lớp cho mọi trẻ em của nó, vô hiệu hóa nó nếu đó là một EditText.
StoneLam

125

cái này là đệ quy cho 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);
       }
    }
}

Tốt đoạn, nhưng scrollviews vẫn sẽ cuộn, một số mã khác là cần thiết để biết thêm chức năng
htafoya

Con quay không bị vô hiệu hóa không rõ tại sao :(
Vivek Singh

ViewPager cũng không bị vô hiệu hóa, kể cả các lượt xem bên trong nó.
Raphael C

1
Nó không hoạt động vì việc triển khai setEnabled () nằm trên lớp con của khung nhìn, nói cách khác, nó có thể được triển khai khác nhau cho các khung nhìn khác nhau. Vì vậy, không có cách nào tiếp cận như vậy sẽ làm việc cho tất cả các quan điểm tồn tại
RexSplode

81

Câu trả lời của tutu đang đi đúng hướng, nhưng phần đệ quy của anh ấy hơi khó xử. Tôi nghĩ cái này sạch hơn:

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

Giải pháp tuyệt vời. Cảm ơn
Blodhgard

Đây là câu trả lời đúng. Nó đi qua đệ quy. Câu trả lời được chấp nhận hiện tại chỉ đi sâu một cấp độ.
Stealth Rabbi

24

Thực tế công việc đối với tôi là:

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

và để hoàn tác nó:

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

3
Giải pháp đơn giản tốt đẹp thực hiện công việc!
Schm1

2
Giải pháp này sẽ vô hiệu hóa tất cả các chế độ xem trong hoạt động. Không thực sự giải quyết câu hỏi. Điều gì sẽ xảy ra nếu mục tiêu là chỉ vô hiệu hóa các Nhóm Xem nhất định trong hoạt động?
AlanKley

2
đó chính xác là tôi đang tìm kiếm, cảm ơn !! Nhưng sau đó tôi có thể phát hiện xem người dùng có muốn nhấp vào đâu đó không?
Skizo-ozᴉʞS

1
Lớn giải pháp đơn giản
WHOATEMYNOODLES

1
giải pháp tốt nhất nếu bạn chỉ muốn tắt / bật một hoặc một tập hợp các chế độ xem, hãy sử dụng setEnabled (bool) hoặc nếu tất cả các chế độ xem đều là con của một chế độ xem vòng lặp thông qua tất cả các chế độ xem con của chế độ xem này và vô hiệu hóa tất cả nhưng giải pháp này tôi nghĩ là tốt nhất (Ý tôi là câu trả lời này) cảm ơn Idan
Mohammad Elsayed

21

Nếu bạn quan tâm đến việc tắt chế độ xem trong một ViewGroup cụ thể thì bạn có thể sử dụng tính năng thú vị, có lẽ hơi tối nghĩa duplicateParentState. Trạng thái xem là một tập hợp các thuộc tính boolean như được nhấn, đã bật, đã kích hoạt và các thuộc tính khác. Chỉ cần sử dụng điều này trên mỗi con bạn muốn đồng bộ hóa với ViewGroup mẹ:

android:duplicateParentState="true"

Lưu ý rằng nó sao chép toàn bộ trạng thái chứ không chỉ trạng thái đã bật. Đây có thể là những gì bạn muốn! Tất nhiên, cách tiếp cận này là tốt nhất nếu bạn đang tải XML bố cục.


13

Hãy thay đổi mã của 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);
   }
 }
}

Tôi nghĩ, không có ích gì khi chỉ tắt nhóm xem. Nếu bạn muốn làm điều đó, có một cách khác mà tôi đã sử dụng cho mục đích chính xác. Tạo chế độ xem như một anh chị em của chế độ xem nhóm của bạn:

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

và tại thời điểm chạy, hãy hiển thị nó. Lưu ý: bố cục gốc của chế độ xem nhóm của bạn phải là bố cục tương đối hoặc bố cục khung. Hy vọng điều này sẽ giúp ích.


1
Mã của bạn sẽ không vô hiệu hóa ví dụ như Spinner, vì Spinner kéo dài ViewGroup
qbait

12

Nếu một nhà phát triển tuyệt vọng nào đó cuộn xuống đây, tôi có một lựa chọn khác để làm điều đó. Điều này cũng vô hiệu hóa tính năng cuộn theo như tôi đã thử nghiệm với nó. Ý tưởng là sử dụng phần tử View như phần tử này trong RelativeLayout, trong tất cả các phần tử UI của bạn.

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

Vì vậy, nó được thiết lập là "biến mất" trước một số điều kiện. Và sau đó, bạn đặt khả năng hiển thị của nó thành VISIBLE khi bạn muốn tắt UI của mình. Ngoài ra, bạn phải triển khai OnClickListenercho Chế độ xem này. Điều này onClickListenersẽ bắt sự kiện nhấp chuột và sẽ không chuyển nó cho các phần tử bên dưới.


1
Đó là những gì tôi đang tìm kiếm, vâng, tôi đã rất tuyệt vọng và thấy giải pháp của bạn đang cuộn như điên: D
Skizo-ozᴉʞS

1
Khá giải pháp tốt đẹp, thực sự tôi đã có nó trong tâm trí của tôi và tôi đang tìm kiếm ai đó có ý tưởng tương tự vì vậy tôi không phải là một kẻ cô độc điên; D
Ricard

12

Cá nhân tôi sử dụng một cái gì đó như thế này (duyệt cây dọc bằng cách sử dụng đệ quy)

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

sử dụng :

   viewGroup.deepForEach { isEnabled = false }

1
giải pháp thanh lịch.
Raphael C

forEachTôi đoán đang thiếu phương pháp
Skizo-ozᴉʞS

@ Skizo-ozᴉʞS đó là một androidx.core.viewphương pháp: developer.android.com/reference/kotlin/androidx/core/view/…
Achraf Amil

4

Chi tiết

  • Studio Android 3.1.4
  • Kotlin 1.2.70
  • đã kiểm tra trong minSdkVersion 19

Giải pháp

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

Sử dụng

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  }

Làm việc như một sự quyến rũ;)
Skizo-ozᴉʞS

3

Mặc dù không hoàn toàn giống với việc vô hiệu hóa chế độ xem trong một bố cục, nhưng điều đáng nói là bạn có thể ngăn không cho tất cả trẻ em nhận được các thao tác chạm (mà không cần phải lặp lại cấu trúc phân cấp bố cục) bằng cách ghi đè phương thức 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);
    }

}

Sau đó, bạn có thể ngăn trẻ em nhận các sự kiện chạm:

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

Nếu bạn đã bật trình nghe nhấp chuột layout, nó sẽ vẫn được kích hoạt.


Thích câu trả lời này. Trọng lượng khá nhẹ và hiệu quả so với việc di chuyển liên tục ViewGroup để vô hiệu hóa tất cả trẻ em! Để giải quyết vấn đề với cách bố trí vẫn đáp ứng với nhấp chuột, bạn có thể chỉ cần vô hiệu hóa / kích hoạt bố trí ở 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);
    }
}

và gọi phương thức như thế này:

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

2

Trong Kotlin, bạn có thể sử dụng isDuplicateParentStateEnabled = truetrước khi Viewđược thêm vào ViewGroup.

Như được ghi lại trong setDuplicateParentStateEnabledphương thức, nếu chế độ xem con có các trạng thái bổ sung (như trạng thái đã chọn cho hộp kiểm), thì những trạng thái này sẽ không bị ảnh hưởng bởi chế độ chính.

Tương tự xml là android:duplicateParentState="true".


1

Sử dụng hàm đệ quy bên dưới để hiển thị hoặc biến mất các chế độ xem con của bạn . Đối số đầu tiên là chế độ xem gốc của bạn và đối số thứ hai quyết định xem bạn muốn các phần tử con của chế độ xem gốc hiển thị hay biến mất. true = hiển thị sai = biến mất

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

Đây là một câu trả lời khá trì hoãn, nhưng nó có thể giúp ích cho ai đó. Nhiều câu trả lời được đề cập ở trên có vẻ là tốt. Nhưng nếu layout.xml của bạn có các nhóm xem lồng nhau. Sau đó, các câu trả lời trên có thể không cung cấp kết quả đầy đủ. Do đó tôi đã đăng ý kiến ​​của mình dưới dạng một đoạn trích. Với đoạn mã dưới đây, người ta có thể vô hiệu hóa tất cả các chế độ xem (Bao gồm cả các Nhóm xem lồng nhau).

LƯU Ý: Hãy thử tránh các Nhóm Xem lồng nhau vì chúng không được khuyến khích.

 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

Bộ

android:descendantFocusability="blocksDescendants"

cho chế độ xem ViewGroup của bạn. Tất cả con cháu sẽ không tập trung.


Anh ấy không hỏi về sự tập trung.
Stealth Rabbi

0

Nếu bạn muốn vô hiệu hóa một tập hợp hoặc nói một kiểu xem cụ thể, giả sử bạn muốn tắt một số nút cố định với một số văn bản cụ thể có hoặc không có văn bản thì bạn có thể sử dụng mảng của loại đó và lặp qua các phần tử của mảng trong khi vô hiệu hóa các nút bằng thuộc tính setEnabled (false) Bạn có thể thực hiện việc này trên một lệnh gọi hàm như sau:

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

0

Tôi đã cải thiện phản hồi tütü để vô hiệu hóa đúng cách các thành phần EditText và RadioButton. Bên cạnh đó, tôi đang chia sẻ một cách mà tôi đã tìm thấy để thay đổi chế độ hiển thị của chế độ xem và thêm tính minh bạch trong các chế độ xem bị vô hiệu hóa.

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

Hàm hai xu của tôi không có đệ quy

    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

Cách dễ nhất là tạo một <Chế độ xem trong xml của bạn, với match_parent cho chiều cao và chiều rộng, đảm bảo chế độ xem này ở trên mọi chế độ xem khác, sau đó khi bạn muốn ngăn các nhấp chuột, hãy hiển thị nó, hãy thêm một onClickListener vào chế độ xem đó với tham số là null .

Thí dụ:

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

Sau đó, trong mã của bạn:

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

0

Tôi muốn có quyền kiểm soát chế độ xem gốc nên tôi đã thêm includeSelfcờ vàodeepForEach

fun ViewGroup.deepForEach(includeSelf: Boolean = true, function: View.() -> Unit) {
    if (includeSelf) function()
    forEach {
        it.apply {
            function()
            (this as? ViewGroup)?.apply { deepForEach(includeSelf, function) }
        }
    }
}

-1

Đối với tôi RelativeLayout hoặc bất kỳ bố cục nào khác ở cuối tệp xml với chiều rộng và chiều cao được đặt thành match_parent với thuộc tính có thể tập trung và có thể nhấp được đặt thành 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>

-2

để tắt chế độ xem, bạn phải gọi phương thức setEnabled với đối số là false. Ví dụ:

Button btn = ...
btn.setEnabled(false);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.