Android: Mengakses tampilan anak dari ListView

108

Saya perlu mengetahui posisi piksel dari satu elemen dalam daftar yang telah ditampilkan menggunakan file ListView. Sepertinya saya harus mendapatkan salah satu TextView dan kemudian menggunakannya getTop(), tetapi saya tidak tahu bagaimana cara mendapatkan tampilan anak dari file ListView.

Pembaruan: Anak-anak dari ViewGrouptidak sesuai 1-to-1 dengan item dalam daftar, untuk a ListView. Alih-alih, ViewGroupturunannya hanya sesuai dengan tampilan yang terlihat sekarang. Jadi getChildAt()beroperasi pada indeks yang bersifat internal ViewGroupdan tidak selalu ada hubungannya dengan posisi dalam daftar yang ListViewdigunakan.

sampang
sumber

Jawaban:

215

Lihat: Android ListView: dapatkan indeks data item yang terlihat dan gabungkan dengan bagian dari jawaban Feet di atas, dapat memberi Anda sesuatu seperti:

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

Manfaatnya adalah Anda tidak mengulangi turunan ListView, yang dapat menghasilkan kinerja yang buruk.

Joe
sumber
10
Jawaban yang bagus, tetapi tidak cukup berfungsi saat Anda memiliki tampilan header dalam daftar Anda. Tugasnya firstPositionadalah int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();untuk memperbaiki ini.
pospi
@pospi: terima kasih, poin yang bagus! Saya telah memperbarui jawaban saya untuk menjelaskan itu.
Joe
Jawaban bagus dan berfungsi di sebagian besar kasus, tetapi saya tidak mengerti mengapa Anda yakin bahwa tampilan turunan muncul dalam urutan seperti dalam larik tampilan turunan. Karena tampilan dapat digunakan kembali, bagaimana kita bisa yakin bahwa tampilan pertama tidak mewakili tampilan terakhir yang terlihat?
Victor Denisov
2
@VictorDenisov: ini hanya dapat terjadi di thread UI; oleh karena itu thread UI akan diblokir saat kode ini dijalankan, sehingga tampilan turunannya tidak berubah dan tidak akan diubah. ListViewsudah menangani "memindahkan" tampilan turunan setelah mendaur ulang tampilan lama convertView, dll., jadi Anda dapat dijamin bahwa itu ListView.getChildAt(0) adalah tampilan terlampir pertama dari adaptor. Ini mungkin tidak sepenuhnya terlihat (dan bahkan mungkin tidak terlihat sama sekali, tergantung pada ListViewambang "visibilitas" sebelum mendaur ulang tampilan yang dianggap "digulir keluar dari tampilan")
Joe
1
@Matheus bukan itu cara kerja Android ListView. Jika item daftar di luar layar, tampilannya telah didaur ulang dan digunakan kembali untuk salah satu item daftar lainnya yang ada di layar. Anda harus memikirkan kembali bagaimana Anda menggunakan ListView jika itu adalah persyaratan.
Joe
17

Kode ini lebih mudah digunakan:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }
Kalimah
sumber
9
tidak selalu berhasil. getChildAt menghitung dari baris pertama yang terlihat, bukan dari bagian atas data.
SteelBytes
13
Argumen ViewID membingungkan. Ini adalah indeks (atau posisi). ID tampilan adalah bilangan bulat arbitrer yang dibuat oleh alat aapt.
Johan Pelgrim
6

Pencarian cepat dokumen untuk kelas ListView menghasilkan metode getChildCount () dan getChildAt () yang diwarisi dari ViewGroup. Bisakah Anda mengulanginya menggunakan ini? Saya tidak yakin tapi patut dicoba.

Ketemu di sini

Kaki
sumber
1
Saya sudah mencoba ini, untuk melakukan seleksi. Biasanya berfungsi tetapi terkadang ada kesalahan off-by-one dan tidak dapat diandalkan. Saya tidak akan merekomendasikannya.
Timmmm
Terima kasih Timmmm, saya belum benar-benar mencobanya, baru saja menemukannya di dokumen.
Kaki
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));
            }
        }
    }
});

Pada dasarnya, buat dua Drawable - satu transparan, dan satu lagi warna yang diinginkan. Minta fokus pada posisi yang diklik ( int positionseperti yang ditentukan) dan ubah warna baris tersebut. Kemudian berjalanlah melalui induknya ListView, dan ubah semua baris lainnya sesuai. Ini menjelaskan saat pengguna mengklik listviewbeberapa kali. Ini dilakukan dengan tata letak khusus untuk setiap baris di ListView. (Sangat sederhana, cukup buat file tata letak baru dengan TextView- jangan setel dapat difokuskan atau diklik!).

Tidak perlu adaptor khusus - gunakan ArrayAdapter

Wes
sumber
getChildAt bersifat relatif terhadap item yang digulir saat ini. Ini akan berhenti berfungsi jika Anda menggulir daftar Anda sedikit saja.
nurettin
4
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
Milaaaad
sumber
1
Ceritakan
-9

Ini mengasumsikan Anda mengetahui posisi elemen dalam ListView:

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

Kemudian Anda harus bisa memanggil getLeft () dan getTop () untuk menentukan elemen pada posisi layar.

jasonhudgins
sumber
43
getView()dipanggil secara internal oleh ListView, saat mengisi daftar. Anda tidak boleh menggunakannya untuk mendapatkan tampilan di posisi tersebut dalam daftar, karena memanggil getView()dengan null untuk convertViewpenyebab adaptor memekarkan tampilan baru dari sumber tata letak adaptor (tidak mendapatkan tampilan yang sudah ditampilkan).
Joe
1
Posisi genap akan menjadi posisi di layar visual, bukan ke posisi sumber data adaptor.
Vikas
@jasonhudgins Ini adalah metode yang telah saya gunakan untuk saya pikir ini adalah yang terbaik tetapi ketika saya mencoba membuat bilah kemajuan dalam tampilan anak tidak terlihat, tetapi malah membuat semua bilah kemajuan di listvew tidak terlihat ........ semua masuk semua jawaban yang diterima berhasil
Edijae Crusar