Penafian: yang berikut ini terutama merupakan hasil eksperimen saya sendiri di React Native 0.50. The ScrollView
dokumentasi saat ini hilang banyak informasi yang tercakup di bawah ini; misalnya onScrollEndDrag
sama sekali tidak terdokumentasi. Karena semua yang ada di sini bergantung pada perilaku yang tidak terdokumentasi, sayangnya saya tidak dapat berjanji bahwa informasi ini akan tetap benar setahun atau bahkan sebulan dari sekarang.
Juga, segala sesuatu di bawah ini mengasumsikan tampilan gulir vertikal murni yang offset y nya kita minati; menterjemahkan ke x offset, bila diperlukan semoga menjadi latihan yang mudah bagi pembaca.
Berbagai penangan acara sedang ScrollView
mengambil event
dan membiarkan Anda mendapatkan posisi gulir saat ini melalui event.nativeEvent.contentOffset.y
. Beberapa penangan ini memiliki perilaku yang sedikit berbeda antara Android dan iOS, seperti yang dijelaskan di bawah ini.
Di Android
Menyalakan setiap bingkai saat pengguna menggulir, pada setiap bingkai saat tampilan gulir meluncur setelah pengguna melepaskannya, pada bingkai terakhir saat tampilan gulir berhenti, dan juga setiap kali offset tampilan gulir berubah sebagai akibat dari bingkainya berubah (misalnya karena rotasi dari lanskap ke potret).
Di iOS
Kebakaran saat pengguna menyeret atau saat tampilan gulir meluncur, pada frekuensi tertentu yang ditentukan oleh scrollEventThrottle
dan paling banyak sekali per frame saat scrollEventThrottle={16}
. Jika pengguna melepaskan tampilan gulir saat memiliki cukup momentum untuk meluncur, onScroll
penangan juga akan aktif saat berhenti setelah meluncur. Namun, jika pengguna menyeret dan kemudian melepaskan pandangan gulir sementara itu stasioner, onScroll
yang tidak dijamin api untuk posisi akhir kecuali scrollEventThrottle
telah diatur sedemikian rupa sehinggaonScroll
kebakaran setiap frame bergulir.
Ada biaya kinerja untuk pengaturan scrollEventThrottle={16}
yang dapat dikurangi dengan mengaturnya ke angka yang lebih besar. Namun, ini berarti onScroll
tidak akan mengaktifkan setiap frame.
Kebakaran saat tampilan gulir berhenti setelah meluncur. Tidak menyala sama sekali jika pengguna melepaskan tampilan gulir saat tidak bergerak sehingga tidak meluncur.
onScrollEndDrag
Kebakaran saat pengguna berhenti menyeret tampilan gulir - terlepas dari apakah tampilan gulir tidak bergerak atau mulai meluncur.
Mengingat perbedaan perilaku ini, cara terbaik untuk melacak penggantian kerugian bergantung pada keadaan Anda yang sebenarnya. Dalam kasus yang paling rumit (Anda perlu mendukung Android dan iOS, termasuk menangani perubahan dalam ScrollView
bingkai karena rotasi, dan Anda tidak ingin menerima penalti kinerja pada Android dari pengaturan scrollEventThrottle
ke 16), dan Anda perlu menangani mengubah konten dalam tampilan gulir juga, maka itu benar-benar berantakan.
Kasus paling sederhana adalah jika Anda hanya perlu menangani Android; gunakan saja onScroll
:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Untuk lebih mendukung iOS, jika Anda senang untuk mengaktifkan onScroll
handler setiap frame dan menerima implikasi kinerja dari itu, dan jika Anda tidak perlu menangani perubahan frame, maka ini hanya sedikit lebih rumit:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>
Untuk mengurangi overhead kinerja di iOS sambil tetap menjamin bahwa kami merekam posisi apa pun yang ditetapkan oleh tampilan gulir, kami dapat meningkatkan scrollEventThrottle
dan juga menyediakan onScrollEndDrag
penangan:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>
Tetapi jika kita ingin menangani perubahan bingkai (misalnya karena kita mengizinkan perangkat untuk diputar, mengubah ketinggian yang tersedia untuk bingkai tampilan gulir) dan / atau perubahan konten, maka kita harus menerapkan keduanya onContentSizeChange
dan onLayout
untuk melacak ketinggian keduanya. bingkai tampilan gulir dan kontennya, dan dengan demikian terus menghitung offset maksimum yang mungkin dan menyimpulkan saat offset secara otomatis berkurang karena bingkai atau ukuran konten berubah:
<ScrollView
onLayout={event => {
this.frameHeight = event.nativeEvent.layout.height;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onContentSizeChange={(contentWidth, contentHeight) => {
this.contentHeight = contentHeight;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
scrollEventThrottle={160}
>
Ya, itu sangat mengerikan. Saya juga tidak 100% yakin bahwa ini akan selalu berfungsi dengan benar jika Anda secara bersamaan mengubah ukuran bingkai dan konten tampilan gulir. Tapi itu yang terbaik yang bisa saya hasilkan, dan sampai fitur ini ditambahkan dalam kerangka itu sendiri , saya pikir ini adalah yang terbaik yang bisa dilakukan siapa pun.