Android: เข้าถึงมุมมองของเด็กจาก ListView


108

ฉันต้องการค้นหาตำแหน่งพิกเซลขององค์ประกอบหนึ่งในรายการที่แสดงโดยใช้ไฟล์ListView. ดูเหมือนว่าฉันควรจะได้รับTextViewอย่างใดอย่างหนึ่งแล้วใช้getTop()แต่ฉันไม่สามารถหาวิธีรับมุมมองลูกของไฟล์ListView.

อัปเดต:ลูกของViewGroupสิ่งนี้ไม่สอดคล้องกับ 1 ต่อ 1 กับรายการในรายการสำหรับกListView. แต่ViewGroupเด็ก ๆ จะสอดคล้องกับมุมมองที่มองเห็นได้ในขณะนี้เท่านั้น ดังนั้นgetChildAt()ดำเนินการกับดัชนีที่อยู่ภายในViewGroupและไม่จำเป็นต้องเกี่ยวข้องกับตำแหน่งในรายการที่ListViewใช้

คำตอบ:


215

ดู: Android ListView: รับดัชนีข้อมูลของรายการที่มองเห็นได้ และรวมกับส่วนหนึ่งของคำตอบของ Feet ด้านบนสามารถให้สิ่งต่างๆเช่น:

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
  Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
  return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);

ข้อดีคือคุณไม่ได้ทำซ้ำกับลูก ๆ ของ ListView ซึ่งอาจได้รับผลกระทบด้านประสิทธิภาพ


10
คำตอบที่ดี แต่ใช้ไม่ได้ผลเมื่อคุณมีมุมมองส่วนหัวในรายการของคุณ งานที่firstPositionควรได้รับint firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();การแก้ไขนี้
pospi

@pospi: ขอบคุณจุดดี! ฉันได้อัปเดตคำตอบของฉันสำหรับบัญชีนั้นแล้ว
โจ

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

2
@VictorDenisov: สิ่งนี้สามารถเกิดขึ้นได้ในเธรด UI เท่านั้น ดังนั้นเธรด UI จะถูกบล็อกในขณะที่โค้ดนี้กำลังดำเนินการดังนั้นมุมมองลูกจะนิ่งและจะไม่มีการแก้ไข ListViewกำลังจัดการ "ย้าย" มุมมองของเด็กไปรอบ ๆ หลังจากรีไซเคิลของเก่าconvertViewฯลฯ ดังนั้นคุณสามารถรับประกันได้ว่าListView.getChildAt(0) เป็นมุมมองแรกที่แนบมาจากอะแดปเตอร์ อาจมองไม่เห็นทั้งหมด (และอาจมองไม่เห็นเลยด้วยซ้ำขึ้นอยู่กับListViewเกณฑ์ของ "การมองเห็น" ก่อนที่จะรีไซเคิลมุมมองที่พิจารณาว่า "เลื่อนออกจากมุมมอง")
โจ

1
@Matheus นั่นไม่ใช่วิธีการทำงานของ Android ListView หากรายการอยู่นอกหน้าจอมุมมองของรายการนั้นจะถูกรีไซเคิลไปแล้วและนำกลับมาใช้ใหม่สำหรับรายการอื่น ๆ ที่อยู่บนหน้าจอ คุณควรคิดใหม่ว่าคุณใช้ ListView อย่างไรหากเป็นข้อกำหนด
โจ

17

รหัสนี้ใช้งานง่ายกว่า:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }

9
ไม่ได้ผลเสมอไป getChildAt นับจากแถวแรกที่มองเห็นไม่ใช่จากด้านบนของข้อมูล
SteelBytes

13
อาร์กิวเมนต์ ViewID สับสน มันคือดัชนี (หรือตำแหน่ง) รหัสข้อมูลพร็อพเพอร์ตี้คือจำนวนเต็มที่สร้างขึ้นโดยพลการโดยเครื่องมือ aapt
Johan Pelgrim

6

การค้นหาเอกสารอย่างรวดเร็วสำหรับคลาส ListView ได้เปิดใช้เมธอด getChildCount () และ getChildAt () ที่สืบทอดมาจาก ViewGroup คุณสามารถทำซ้ำโดยใช้สิ่งเหล่านี้ได้หรือไม่? ฉันไม่แน่ใจ แต่ก็คุ้มค่าที่จะลอง

พบได้ที่นี่


1
ฉันได้ลองทำสิ่งนี้เพื่อทำการเลือก โดยปกติจะใช้งานได้ แต่บางครั้งก็มีข้อผิดพลาดทีละรายการและไม่น่าเชื่อถือ ฉันจะไม่แนะนำที่นี่
Timmmm

ขอบคุณ Timmmm ฉันไม่ได้ลองจริง ๆ เพียงแค่พบในเอกสาร
ฟุต

5
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
        View v;
        int count = parent.getChildCount();
        v = parent.getChildAt(position);
        parent.requestChildFocus(v, view);
        v.setBackground(res.getDrawable(R.drawable.transparent_button));
        for (int i = 0; i < count; i++) {
            if (i != position) {
                v = parent.getChildAt(i);
                v.setBackground(res.getDrawable(R.drawable.not_clicked));
            }
        }
    }
});

โดยพื้นฐานแล้วให้สร้างDrawablesสองรายการ- อันที่โปร่งใสและอีกสีหนึ่งเป็นสีที่ต้องการ ขอโฟกัสที่ตำแหน่งที่คลิก ( int positionตามที่กำหนด) และเปลี่ยนสีของแถวดังกล่าว จากนั้นเดินผ่านผู้ปกครองListViewและเปลี่ยนแถวอื่น ๆ ทั้งหมดตามนั้น บัญชีนี้ใช้เมื่อผู้ใช้คลิกlistviewหลาย ๆ ครั้ง สิ่งนี้ทำได้ด้วยเค้าโครงที่กำหนดเองสำหรับแต่ละแถวในไฟล์ListView. (ง่ายมากเพียงสร้างไฟล์เลย์เอาต์ใหม่ด้วยไฟล์TextView - อย่าตั้งค่าที่โฟกัสได้หรือคลิกได้!)

ไม่ต้องใช้อะแดปเตอร์แบบกำหนดเอง - ใช้ ArrayAdapter


getChildAt สัมพันธ์กับรายการที่เลื่อนในปัจจุบัน สิ่งนี้จะหยุดทำงานหากคุณเลื่อนรายการของคุณเพียงเล็กน้อย
nurettin


-9

ถือว่าคุณรู้ตำแหน่งขององค์ประกอบใน ListView:

  View element = listView.getListAdapter().getView(position, null, null);

จากนั้นคุณจะสามารถเรียกใช้ getLeft () และ getTop () เพื่อกำหนดองค์ประกอบบนตำแหน่งหน้าจอ


43
getView()ถูกเรียกใช้ภายในโดย ListView เมื่อเติมข้อมูลในรายการ คุณไม่ควรใช้เพื่อรับมุมมองที่ตำแหน่งนั้นในรายการเนื่องจากการเรียกgetView()ด้วย null สำหรับconvertViewสาเหตุที่ทำให้อะแด็ปเตอร์ขยายมุมมองใหม่จากทรัพยากรโครงร่างของอะแด็ปเตอร์ (ไม่ได้รับมุมมองที่แสดงอยู่แล้ว)
โจ

1
ตำแหน่งคู่จะเป็นตำแหน่งในหน้าจอภาพไม่ใช่ตำแหน่งแหล่งข้อมูลของอะแด็ปเตอร์
Vikas

@jasonhudgins นี่เป็นวิธีที่ฉันใช้สำหรับฉันคิดว่ามันดีที่สุด แต่เมื่อฉันพยายามทำให้แถบความคืบหน้าในมุมมองเด็กมองไม่เห็น แต่กลับทำให้แถบความคืบหน้าทั้งหมดใน listvew มองไม่เห็น ........ ทั้งหมดใน คำตอบที่ยอมรับทั้งหมดเป็นเคล็ดลับ
Edijae Crusar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.