Android - ให้เด็ก ๆ อยู่ในมุมมอง?


169

ได้รับมุมมองฉันจะดูมุมมองเด็กได้อย่างไร

ดังนั้นฉันมีมุมมองที่กำหนดเองและดีบักเกอร์แสดงว่าภายใต้mChildrenมีมุมมองอื่น ๆ อีก 7 รายการ ฉันต้องการวิธีเข้าถึงมุมมองเหล่านี้ แต่ดูเหมือนว่าจะไม่มี API สาธารณะในการทำเช่นนี้

ข้อเสนอแนะใด ๆ

แก้ไข:

มุมมองที่กำหนดเองของฉันสืบทอดมาจาก AdapterView

คำตอบ:


313
for(int index = 0; index < ((ViewGroup) viewGroup).getChildCount(); index++) {
    View nextChild = ((ViewGroup) viewGroup).getChildAt(index);
}

มันจะทำอย่างไร


2
วิธีที่ดีที่สุดในการทำแบบนี้วนซ้ำและดังนั้นจึงสร้างมุมมองวัตถุ JSON การสืบทอด
jimbob

สมมติว่ามุมมองหลักมีชื่อว่าviewGroup
Prime624

57

หากคุณไม่เพียง แต่ต้องการให้มีลูกโดยตรงทั้งหมด แต่เด็กทุกคนและอื่น ๆ คุณต้องทำซ้ำ:

private ArrayList<View> getAllChildren(View v) {

    if (!(v instanceof ViewGroup)) {
        ArrayList<View> viewArrayList = new ArrayList<View>();
        viewArrayList.add(v);
        return viewArrayList;
    }

    ArrayList<View> result = new ArrayList<View>();

    ViewGroup vg = (ViewGroup) v;
    for (int i = 0; i < vg.getChildCount(); i++) {

        View child = vg.getChildAt(i);

        ArrayList<View> viewArrayList = new ArrayList<View>();
        viewArrayList.add(v);
        viewArrayList.addAll(getAllChildren(child));

        result.addAll(viewArrayList);
    }
    return result;
}

หากต้องการใช้ผลลัพธ์คุณสามารถทำสิ่งนี้:

    // check if a child is set to a specific String
    View myTopView;
    String toSearchFor = "Search me";
    boolean found = false;
    ArrayList<View> allViewsWithinMyTopView = getAllChildren(myTopView);
    for (View child : allViewsWithinMyTopView) {
        if (child instanceof TextView) {
            TextView childTextView = (TextView) child;
            if (TextUtils.equals(childTextView.getText().toString(), toSearchFor)) {
                found = true;
            }
        }
    }
    if (!found) {
        fail("Text '" + toSearchFor + "' not found within TopView");
    }

8
การโทรนี้ไม่ได้รับการบันทึกเช่นเด็กสามารถเป็นประเภท View และไม่ใช่ ViewGroup ดังนั้นการเรียกซ้ำของ getAllChildren อาจทำให้เกิดข้อยกเว้นเนื่องจากการส่งล้มเหลว ดังนั้นคุณควรเพิ่ม if (! (v instanceof ViewGroup)) return; ก่อนที่นักแสดง
ฟิล

2
ข้อเสนอแนะเล็ก ๆ : แทนที่ for for loop ด้วยfor (int i = 0, n = vg.getChildCount(); i < n; i++) On Android การเข้าถึงตัวแปรโลคัลแทนการเรียกใช้เมธอดมีแนวโน้มที่จะเร็วกว่ามาก วิธีนี้มีการเรียกใช้เมธอดเพียงครั้งเดียวต่อกลุ่มการดูและจากนั้นจะมีการใช้ตัวแปรโลคัล
ArtOfWarfare

ฉันเปลี่ยนรหัสเนื่องจากข้อเสนอแนะของ Phil Diegmann หวังว่านี่จะช่วยได้ ได้ผลสำหรับฉัน
IHeartAndroid

1
เย็น. ฉันขอแนะนำให้เพิ่มบูลีน 'includeViewGroups' เท่านั้นและถ้าเป็นจริง, iewArrayList.add (v); สิ่งนี้มีประโยชน์สำหรับการวนซ้ำในอะแดปเตอร์ (และฉันต้องการเพียงใบไม้) ขอบคุณ!
JRun

20

คุณสามารถเข้าถึงมุมมองเด็กได้ตลอดเวลาผ่าน View.findViewById () http://developer.android.com/reference/android/view/View.html#findViewById(int )

ตัวอย่างเช่นภายในกิจกรรม / มุมมอง:

...
private void init() {
  View child1 = findViewById(R.id.child1);
}
...

หรือถ้าคุณมีการอ้างอิงถึงมุมมอง:

...
private void init(View root) {
  View child2 = root.findViewById(R.id.child2);
}

ฉันไม่สามารถเข้าถึงรหัส, UI ถูกสร้างขึ้นผ่านรหัส, ฉันกำลังเขียนระบบอัตโนมัติโดยใช้ robotium, ดังนั้นสิ่งที่ฉันสามารถทำได้มี จำกัด
aryaxt

@ jonson ไม่เป็นประโยชน์เลยถ้าคุณต้องการรับลูกทั้งหมด
Pacerier

นอกจากนี้ยังquora.com/unanswered/...
Pacerier

17

ฉันแค่จะให้คำตอบนี้เป็นทางเลือกอัลกอริทึมแบบเรียกซ้ำ @ IHeartAndroid สำหรับการค้นพบเด็กทุกคนViewในลำดับชั้นการดู โปรดทราบว่าในขณะที่เขียนนี้โซลูชันแบบเรียกซ้ำนั้นมีข้อบกพร่องซึ่งจะมีการซ้ำซ้อนในผลลัพธ์

สำหรับผู้ที่มีปัญหาในการล้อมรอบการเรียกซ้ำนี่เป็นทางเลือกที่ไม่ใช่แบบเรียกซ้ำ คุณจะได้รับคะแนนโบนัสสำหรับการตระหนักว่านี่เป็นทางเลือกการค้นหาที่กว้างเป็นอันดับแรกสำหรับแนวทางเชิงลึกของโซลูชันแบบเรียกซ้ำ

private List<View> getAllChildrenBFS(View v) {
    List<View> visited = new ArrayList<View>();
    List<View> unvisited = new ArrayList<View>();
    unvisited.add(v);

    while (!unvisited.isEmpty()) {
        View child = unvisited.remove(0);
        visited.add(child);
        if (!(child instanceof ViewGroup)) continue;
        ViewGroup group = (ViewGroup) child;
        final int childCount = group.getChildCount();
        for (int i=0; i<childCount; i++) unvisited.add(group.getChildAt(i));
    }

    return visited;
}

การทดสอบอย่างรวดเร็วสองสามข้อ (ไม่มีอะไรเป็นทางการ) แนะนำให้ทางเลือกนี้ยังเร็วกว่าแม้ว่าจะมีแนวโน้มที่จะทำกับจำนวนของArrayListอินสแตนซ์ใหม่ที่คำตอบอื่น ๆ สร้างขึ้น นอกจากนี้ผลลัพธ์อาจแตกต่างกันไปตามลำดับชั้นของมุมมองแนวตั้ง / แนวนอน

ข้ามโพสต์จาก: Android | รับองค์ประกอบลูกทั้งหมดของ ViewGroup


7

นี่คือข้อเสนอแนะ: คุณสามารถรับID(ระบุเช่นโดยandroid:id="@+id/..My Str..) ซึ่งสร้างขึ้นRโดยใช้ชื่อที่ให้ไว้ (เช่นMy Str) ข้อมูลโค้ดโดยใช้getIdentifier()วิธีการนั้นจะเป็น:

public int getIdAssignedByR(Context pContext, String pIdString)
{
    // Get the Context's Resources and Package Name
    Resources resources = pContext.getResources();
    String packageName  = pContext.getPackageName();

    // Determine the result and return it
    int result = resources.getIdentifier(pIdString, "id", packageName);
    return result;
}

จากภายใน Activityตัวอย่างการใช้งานควบคู่ไปกับfindViewByIdจะเป็น:

// Get the View (e.g. a TextView) which has the Layout ID of "UserInput"
int rID = getIdAssignedByR(this, "UserInput")
TextView userTextView = (TextView) findViewById(rID);

3

เป็นการอัปเดตสำหรับผู้ที่พบคำถามนี้หลังจากปี 2018 หากคุณใช้ Kotlin คุณสามารถใช้ViewGroup.childrenส่วนขยายของAndroid KTXเพื่อรับลำดับของลูก ๆ ของ View ได้ทันที


0

เพื่อรีเฟรชเลย์เอาต์ของตาราง (TableLayout) ฉันต้องใช้วิธีเรียกซ้ำที่กล่าวถึงข้างต้นเพื่อให้ลูก ๆ ของเด็ก ๆ ทุกคนและอื่น ๆ

สถานการณ์ของฉันค่อนข้างง่ายขึ้นเพราะฉันต้องการทำงานกับ LinearLayout เท่านั้นและคลาสเหล่านั้นขยายจากนั้นเช่น TableLayout และฉันสนใจที่จะหาเด็ก TextView เท่านั้น แต่ฉันคิดว่ามันยังใช้ได้กับคำถามนี้

คลาสสุดท้ายรันเป็นเธรดแยกซึ่งหมายความว่าสามารถทำสิ่งอื่น ๆ ในพื้นหลังก่อนที่จะแยกวิเคราะห์สำหรับเด็ก รหัสมีขนาดเล็กและเรียบง่ายและสามารถพบได้ที่ github: https://github.com/jkincali/Android-LinearLayout-Parser


0

วิธีนี้ใช้มุมมองทั้งหมดภายในเค้าโครงคล้ายกับคำตอบของ Alexander Kulyakhtin ความแตกต่างคือมันยอมรับเลย์เอาต์หลักใด ๆ และส่งคืนรายการมุมมอง Array

public List<View> getAllViews(ViewGroup layout){
        List<View> views = new ArrayList<>();
        for(int i =0; i< layout.getChildCount(); i++){
            views.add(layout.getChildAt(i));
        }
        return views;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.