ฉันจะกำหนด ID ให้กับมุมมองโดยทางโปรแกรมได้อย่างไร


202

ในไฟล์ XML เราสามารถกำหนด ID ให้กับมุมมองที่ชอบandroid:id="@+id/something"แล้วโทรfindViewById()แต่เมื่อสร้างมุมมองโดยทางโปรแกรมฉันจะกำหนด ID ได้อย่างไร

ฉันคิดว่าsetId()ไม่เหมือนกับการมอบหมายเริ่มต้น setId()เป็นพิเศษ

ใครสามารถแก้ไขฉันได้ไหม


1
เซตย่อย: วิธีสร้าง ID เฉพาะ: stackoverflow.com/questions/1714297/…
Ciro Santilli ill 郝海东病病六四事件法轮功

คำตอบ:


521

idภาพรวมAndroid

Android idเป็นจำนวนเต็มที่ใช้เพื่อระบุมุมมอง สิ่งนี้idสามารถกำหนดผ่านทาง XML (เมื่อเป็นไปได้) และผ่านทางรหัส (โดยทางโปรแกรม) สิ่งidที่มีประโยชน์มากที่สุดสำหรับการรับการอ้างอิงสำหรับ XML ที่กำหนดโดยViews ที่สร้างโดยInflater(เช่นโดยใช้setContentView)

กำหนดidผ่านXML

  • เพิ่มแอตทริบิวต์ของandroid:id="@+id/somename "ให้กับมุมมองของคุณ
  • เมื่อแอปพลิเคชันของคุณถูกสร้างขึ้นandroid:idจะมีการกำหนดค่าเฉพาะ intสำหรับใช้ในรหัส
  • การอ้างอิงของคุณandroid:id's intค่าในการใช้รหัส ' R.id.somename'(อย่างมีประสิทธิภาพอย่างต่อเนื่อง.)
  • สิ่งนี้intสามารถเปลี่ยนจาก build เป็น buildดังนั้นอย่าคัดลอก idจากgen/package.name/ R.javaเพียงแค่ใช้ " R.id.somename"
  • (นอกจากนี้การidกำหนดให้กับPreferenceใน XML จะไม่ถูกใช้เมื่อPreferenceสร้างขึ้นView)

กำหนดidรหัสผ่าน (โดยทางโปรแกรม)

  • ตั้งค่าด้วยตนเองidโดยใช้someView.setId(int);
  • intต้องเป็นบวก แต่อย่างอื่น arbitrary- มันอาจเป็นสิ่งที่คุณต้องการ (ให้อ่านถ้านี้เป็นที่น่าตกใจ.)
  • ตัวอย่างเช่นหากการสร้างและกำหนดจำนวนมุมมองหลายรายการที่เป็นตัวแทนของรายการคุณสามารถใช้หมายเลขรายการได้

เอกลักษณ์ของidเอส

  • XMLที่ได้รับมอบหมายidจะไม่ซ้ำกัน
  • รหัสที่ได้รับมอบหมายids ทำไม่ได้จะต้องไม่ซ้ำกัน
  • รหัสที่ได้รับมอบหมายids สามารถ (ทฤษฎี) ความขัดแย้งกับXML-assigned ids
  • เหล่านี้ขัดแย้งids จะไม่ว่าถ้าถามอย่างถูกต้อง(อ่านเก็บ)

เมื่อ (และทำไม) ความขัดแย้งidไม่สำคัญ

  • findViewById(int)จะย้ำความลึกแรกซ้ำผ่านลำดับชั้นดูจากมุมมองที่คุณระบุและกลับคนแรกที่จะพบกับการจับคู่Viewid
  • ตราบใดที่ไม่มีการกำหนดรหัสไว้idก่อนที่ XML จะถูกกำหนดidในลำดับชั้นfindViewById(R.id.somename)จะส่งคืนมุมมองที่กำหนดโดย XML ดังนั้นid'd

แบบไดนามิกการสร้างมุมมองและการกำหนดIDs

  • ในรูปแบบ XML กำหนดที่ว่างเปล่ากับViewGroupid
  • เช่นกับLinearLayoutandroid:id="@+id/placeholder"
  • ใช้รหัสเพื่อเติมตัวยึดตำแหน่งViewGroupด้วยViews
  • หากคุณต้องการหรือต้องการกำหนดสิ่งidที่สะดวกสำหรับแต่ละมุมมอง
  • เคียวรีมุมมองชายด์เหล่านี้โดยใช้ placeholder.findViewById (convenientInt);

  • API 17 ที่แนะนำView.generateViewId()ซึ่งช่วยให้คุณสร้าง ID ที่ไม่ซ้ำ

หากคุณเลือกที่จะเก็บอ้างอิงถึงมุมมองของคุณไปรอบ ๆให้แน่ใจว่าพวกเขาด้วยการยกตัวอย่างและให้แน่ใจว่าแต่ละชุดการอ้างอิงถึงโมฆะในgetApplicationContext() onDestroyเห็นได้ชัดว่าการรั่วไหลActivity (ที่แขวนอยู่บนมันหลังจากที่มีการถูกทำลาย) เป็นสิ้นเปลือง .. :)

จอง XML android:idเพื่อใช้ในรหัส

API 17 ที่แนะนำ View.generateViewId() ซึ่งสร้าง ID เฉพาะ (ขอบคุณที่รับโอกาส - เปลี่ยนแปลงเพื่อชี้เรื่องนี้) *

หากViewGroupไม่สามารถกำหนดผ่าน XML (หรือคุณไม่ต้องการให้เป็น) คุณสามารถจอง id ผ่านทาง XML เพื่อให้แน่ใจว่ายังคงไม่ซ้ำกัน:

ที่นี่ค่า / ids.xmlกำหนดแบบกำหนดเองid:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="reservedNamedId" type="id"/>
</resources>

จากนั้นเมื่อสร้าง ViewGroup หรือ View แล้วคุณสามารถแนบ id ที่กำหนดเองได้

myViewGroup.setId(R.id.reservedNamedId);

idตัวอย่างที่ขัดแย้งกัน

เพื่อความชัดเจนของตัวอย่างที่ทำให้งงงวยให้ตรวจสอบสิ่งที่เกิดขึ้นเมื่อมีidความขัดแย้งเบื้องหลัง

รูปแบบ / mylayout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/placeholder"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
</LinearLayout>

ในการจำลองข้อขัดแย้งสมมติว่าบิลบอร์ดล่าสุดของเราได้รับมอบหมายR.id.placeholder( @+id/placeholder) intค่าของ 12 ..

ถัดไปMyActivity.javaกำหนดบางมุมมองเพิ่มโดยทางโปรแกรม (ผ่านรหัส):

int placeholderId = R.id.placeholder; // placeholderId==12
// returns *placeholder* which has id==12:
ViewGroup placeholder = (ViewGroup)this.findViewById(placeholderId);
for (int i=0; i<20; i++){
    TextView tv = new TextView(this.getApplicationContext());
    // One new TextView will also be assigned an id==12:
    tv.setId(i);
    placeholder.addView(tv);
}

ดังนั้นplaceholderหนึ่งในสิ่งใหม่ของเราTextViewทั้งคู่ก็มีid12 ข้อ! แต่นี่ไม่ใช่ปัญหาจริง ๆ หากเราค้นหามุมมองย่อยของตัวยึดตำแหน่ง:

// Will return a generated TextView:
 placeholder.findViewById(12);

// Whereas this will return the ViewGroup *placeholder*;
// as long as its R.id remains 12: 
Activity.this.findViewById(12);

*ไม่ได้เลวร้าย


9
นอกจากนี้อาจเป็นประโยชน์สำหรับบางคนในการเข้ารหัสวิธีแก้ปัญหาที่คุ้นเคยเพื่อให้ทราบ View.generateViewId () ใน API> 17 สำหรับรหัสที่ไม่ขัดแย้งกัน
AllDayAmazing

โปรดทราบว่าfindViewByIdจะทำการสำรวจเชิงลึกครั้งแรกดังนั้น "ตราบใดที่ไม่มีรหัสที่กำหนดรหัสไว้เหนือรหัสที่กำหนดโดย XML ในลำดับชั้น" ไม่ถูกต้องทางเทคนิค มันคือ "ก่อนหน้า" มากกว่า "ด้านบน"
Karu

ในเครื่องมือนักพัฒนา Android รุ่นที่ใหม่กว่าการตั้งค่า ID เป็นค่าโดยพลการทางโปรแกรมจะถูกตั้งค่าสถานะเป็นข้อผิดพลาดของคอมไพเลอร์ ค่าคาดว่าจะเป็น ID ทรัพยากรที่แท้จริง
ThomasW

ผมเชื่อว่านี่เป็นแม้กระทั่งกรณีที่เมื่อฉันตอบนี้ห้าปีที่ผ่านมา - ids.xmlที่ว่าทำไมรหัสที่กำหนดเองที่จะต้องมีการกำหนดไว้ใน สำหรับ ID โดยพลการอย่างแท้จริงให้ใช้View.generateViewId()(API 17) (โปรดอธิบายประเด็นของคุณหากฉันพลาด)
CodeShane

> (นอกจากนี้ ID ที่กำหนดให้กับการตั้งค่าใน XML จะไม่ถูกใช้เมื่อการตั้งค่าสร้างมุมมองของตน) ให้ความสนใจอย่างมาก รหัสของฉันสืบทอดมาจากPreferenceDialogFragmentCompatดูเหมือนว่ารหัสจากR.idไม่ตรงกับลำดับชั้นการดู วิธีนี้ฉันไม่พบมุมมองตาม ID
UrK

6

คุณสามารถใช้View.setId(integer)สำหรับสิ่งนี้ ใน XML แม้ว่าคุณจะตั้งค่า String id แต่สิ่งนี้จะถูกแปลงเป็นจำนวนเต็ม เนื่องจากสิ่งนี้คุณสามารถใช้จำนวนเต็มบวก (บวก) ใด ๆ สำหรับViews คุณเพิ่มโดยทางโปรแกรม

ตามViewเอกสารประกอบ

ตัวระบุไม่จำเป็นต้องไม่ซ้ำกันในลำดับชั้นของมุมมองนี้ ตัวระบุควรเป็นจำนวนบวก

ดังนั้นคุณสามารถใช้จำนวนเต็มบวกใด ๆ ที่คุณชอบ แต่ในกรณีนี้อาจมีบางมุมมองที่มี id เทียบเท่า หากคุณต้องการค้นหามุมมองบางอย่างในลำดับชั้นการโทรไปยัง setTag ด้วยวัตถุสำคัญบางอย่างอาจมีประโยชน์

ให้เครดิตกับคำตอบนี้


5

ใช่คุณสามารถโทรsetId(value)ในมุมมองใด ๆ กับใด ๆ (บวก) findViewById(value)ค่าจำนวนเต็มที่คุณชอบแล้วพบว่ามันในภาชนะแม่ใช้ โปรดทราบว่ามันถูกต้องในการโทรsetId()ด้วยค่าเดียวกันสำหรับมุมมองพี่น้องที่แตกต่างกัน แต่findViewById()จะส่งกลับเฉพาะมุมมองแรกเท่านั้น


1
โปรดทราบว่าคุณต้องใช้จำนวนเต็มมากกว่าศูนย์
ปีเตอร์ Ajtai

แม้ว่าfindViewById (int) จะวนซ้ำแบบซ้ำ ๆ ตามลำดับชั้นของมุมมองจากมุมมองที่คุณระบุและส่งกลับมุมมองแรกที่พบพร้อมกับรหัสการจับคู่ที่ระบุในคำตอบที่ 1 ถูกต้องที่สุด
Aniket Thakur

ใช่การโทรหาfindViewByIdบรรพบุรุษที่รู้จักเป็นความคิดที่ดีสำหรับเหตุผลด้านประสิทธิภาพ แต่ก็ไม่รับประกันว่าจะพบเด็กคนหนึ่งทันทีหากมี ID ที่ถูกต้อง
Karu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.