คำเตือน: สิ่งต่อไปนี้เป็นผลมาจากการทดลองของฉันเองใน React Native 0.50 ScrollView
เอกสารปัจจุบันจะหายไปจำนวนมากข้อมูลที่ครอบคลุมด้านล่าง; ตัวอย่างเช่นonScrollEndDrag
ไม่มีเอกสารทั้งหมด เนื่องจากทุกสิ่งที่นี่ขึ้นอยู่กับพฤติกรรมที่ไม่มีเอกสารเราจึงไม่สามารถให้คำมั่นสัญญาได้ว่าข้อมูลนี้จะยังคงถูกต้องในหนึ่งปีหรือแม้แต่หนึ่งเดือนนับจากนี้
นอกจากนี้ทุกอย่างดังต่อไปนี้ถือว่า scrollview แนวตั้งอย่างหมดจดมีYชดเชยเรามีความสนใจใน; การแปลเป็นx offsets หากจำเป็นหวังว่าจะเป็นแบบฝึกหัดที่ง่ายสำหรับผู้อ่าน
จัดการเหตุการณ์ต่างๆบนScrollView
ใช้เวลาและปล่อยให้คุณได้รับการเลื่อนตำแหน่งในปัจจุบันผ่านevent
event.nativeEvent.contentOffset.y
เครื่องจัดการเหล่านี้บางตัวมีพฤติกรรมที่แตกต่างกันเล็กน้อยระหว่าง Android และ iOS ตามรายละเอียดด้านล่าง
บน Android
เริ่มทำงานทุกเฟรมในขณะที่ผู้ใช้กำลังเลื่อนในทุกเฟรมในขณะที่มุมมองแบบเลื่อนกำลังเลื่อนหลังจากที่ผู้ใช้ปล่อยเฟรมในเฟรมสุดท้ายเมื่อมุมมองการเลื่อนหยุดลงและเมื่อใดก็ตามที่ออฟเซ็ตของมุมมองการเลื่อนเปลี่ยนไปอันเป็นผลมาจากเฟรม การเปลี่ยนแปลง (เช่นเนื่องจากการหมุนจากแนวนอนเป็นแนวตั้ง)
บน iOS
ไฟไหม้ขณะที่ผู้ใช้ลากหรือในขณะที่มุมมองเลื่อนจะร่อนที่ความถี่บางกำหนดโดยและที่มากที่สุดครั้งหนึ่งต่อกรอบเมื่อscrollEventThrottle
หากผู้ใช้ออกจากมุมมองแบบเลื่อนในขณะที่มีโมเมนตัมเพียงพอที่จะเลื่อนตัวจัดการจะยิงเมื่อมันหยุดนิ่งหลังจากร่อน อย่างไรก็ตามหากผู้ใช้ลากแล้วปล่อยมุมมองการเลื่อนในขณะที่อยู่กับที่จะไม่รับประกันว่าจะยิงในตำแหน่งสุดท้ายเว้นแต่จะได้รับการตั้งค่าไว้เช่นนั้นซึ่งจะทำให้ทุกเฟรมของการเลื่อนเริ่มทำงานscrollEventThrottle={16}
onScroll
onScroll
scrollEventThrottle
onScroll
มีต้นทุนด้านประสิทธิภาพในการตั้งค่าscrollEventThrottle={16}
ที่สามารถลดลงได้โดยการตั้งค่าเป็นจำนวนที่มากขึ้น อย่างไรก็ตามหมายความว่าonScroll
จะไม่ยิงทุกเฟรม
เริ่มทำงานเมื่อมุมมองการเลื่อนหยุดลงหลังจากเลื่อน จะไม่เริ่มทำงานเลยหากผู้ใช้ปล่อยมุมมองแบบเลื่อนในขณะที่อยู่กับที่เพื่อไม่ให้เลื่อน
onScrollEndDrag
เริ่มทำงานเมื่อผู้ใช้หยุดลากมุมมองการเลื่อนไม่ว่ามุมมองการเลื่อนจะอยู่นิ่ง ๆ หรือเริ่มเลื่อน
เนื่องจากความแตกต่างในพฤติกรรมเหล่านี้วิธีที่ดีที่สุดในการติดตามการชดเชยขึ้นอยู่กับสถานการณ์ที่แน่นอนของคุณ ในกรณีที่ซับซ้อนที่สุด (คุณต้องรองรับ Android และ iOS รวมถึงการจัดการการเปลี่ยนแปลงในScrollView
เฟรมเนื่องจากการหมุนและคุณไม่ต้องการยอมรับการลงโทษประสิทธิภาพบน Android จากการตั้งค่าscrollEventThrottle
เป็น 16) และคุณต้องจัดการ การเปลี่ยนแปลงเนื้อหาในมุมมองแบบเลื่อนด้วยแล้วมันก็เป็นระเบียบ
กรณีที่ง่ายที่สุดคือหากคุณต้องการจัดการกับ Android เท่านั้น เพียงใช้onScroll
:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
หากต้องการรองรับ iOS เพิ่มเติมหากคุณพอใจที่จะยิงonScroll
ตัวจัดการทุกเฟรมและยอมรับผลกระทบด้านประสิทธิภาพของสิ่งนั้นและหากคุณไม่จำเป็นต้องจัดการกับการเปลี่ยนแปลงเฟรมก็จะซับซ้อนขึ้นเล็กน้อย:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>
เพื่อลดค่าใช้จ่ายด้านประสิทธิภาพบน iOS ในขณะที่ยังคงรับประกันว่าเราบันทึกตำแหน่งใด ๆ ที่มุมมองเลื่อนกำหนดเราสามารถเพิ่มscrollEventThrottle
และจัดหาonScrollEndDrag
ตัวจัดการเพิ่มเติมได้:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>
แต่ถ้าเราต้องการจัดการการเปลี่ยนแปลงเฟรม (เช่นเนื่องจากเราอนุญาตให้หมุนอุปกรณ์เปลี่ยนความสูงที่มีอยู่สำหรับเฟรมของมุมมองการเลื่อน) และ / หรือการเปลี่ยนแปลงเนื้อหาเราจะต้องใช้ทั้งสองอย่างเพิ่มเติมonContentSizeChange
และonLayout
เพื่อติดตามความสูงของทั้งสองอย่าง เฟรมของมุมมองแบบเลื่อนและเนื้อหาและด้วยเหตุนี้จึงคำนวณค่าชดเชยสูงสุดที่เป็นไปได้อย่างต่อเนื่องและอนุมานเมื่อออฟเซ็ตถูกลดลงโดยอัตโนมัติเนื่องจากการเปลี่ยนแปลงขนาดเฟรมหรือเนื้อหา:
<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}
>
ใช่มันค่อนข้างน่ากลัว ฉันยังไม่ 100% บางอย่างที่มันก็จะทำงานที่ถูกต้องในกรณีที่คุณไปพร้อม ๆ กันเปลี่ยนขนาดของทั้งกรอบและเนื้อหาของมุมมองเลื่อน แต่เป็นสิ่งที่ดีที่สุดที่ฉันสามารถทำได้และจนกว่าคุณสมบัตินี้จะถูกเพิ่มเข้าไปในเฟรมเวิร์กฉันคิดว่านี่เป็นสิ่งที่ดีที่สุดที่ทุกคนสามารถทำได้