เมื่อรูปแบบของอุปกรณ์ใหม่ๆ มีมากกว่าหน้าจอสัมผัส ระบบอินพุตของ Compose จึงได้รับการพัฒนาเพื่อตอบสนองความท้าทายนี้ สถาปัตยกรรมแบบเลเยอร์เป็นรากฐานที่รองรับทุกอย่างตั้งแต่ท่าทางสัมผัสแทร็กแพดขั้นสูงไปจนถึงอินพุตฮาร์ดแวร์แบบใหม่ได้อย่างราบรื่น
ติดตามวงจรของเหตุการณ์อินพุตตั้งแต่เลเยอร์แพลตฟอร์มระบบปฏิบัติการไปจนถึงเครื่องมือตรวจจับท่าทางสัมผัสและคอมโพเนนต์ UI ของ Compose ผ่านรายละเอียดสถาปัตยกรรมที่ชัดเจนและตัวอย่างโค้ดที่ใช้งานได้จริง คุณจะได้เรียนรู้วิธีติดตามเหตุการณ์ในสแต็กทั้งหมด ใช้รูปแบบสถาปัตยกรรมที่สำคัญสำหรับประเภทอินพุตใหม่ๆ และแก้ไขข้อบกพร่องของการโต้ตอบด้วยท่าทางสัมผัสที่ซับซ้อนในแอปของคุณเองได้อย่างมั่นใจ
performTrackpadInput API เหล่านี้มีแพลตฟอร์มการทดสอบที่คุ้นเคยเพื่อตรวจสอบว่าแอปจัดการอุปกรณ์ที่ไม่ใช่ระบบสัมผัสได้อย่างถูกต้องข้อความถอดเสียง
สวัสดีทุกคน
หวังว่าคุณจะได้รับประสบการณ์ที่ดีในงาน Android Developer Summit และขอขอบคุณที่เข้าร่วมการบรรยายของเรา
ผม Alex Vanyo วิศวกรซอฟต์แวร์ในทีม Compose และ Jeremy ซึ่งเป็นวิศวกรซอฟต์แวร์ในทีม Compose เช่นกัน
เราทั้งคู่ได้ทำงานเพื่อปรับปรุงระบบการป้อนข้อมูลของ Jetpack Compose และวันนี้เราจะพูดถึงวิธีที่เราได้ขยายระบบดังกล่าวให้ครอบคลุมมากกว่าหน้าจอสัมผัส เพื่อให้รองรับการป้อนข้อมูลที่ไม่ใช่การป้อนข้อมูลด้วยการสัมผัสได้ง่ายขึ้นตั้งแต่แกะกล่อง
โดยกว้างๆ แล้ว อินพุตจะบันทึกวิธีที่ผู้ใช้โต้ตอบกับแอปของคุณ
หน้าจอสัมผัสอาจเป็นสิ่งแรกที่คุณนึกถึงสำหรับแอปบนอุปกรณ์เคลื่อนที่ แต่ก็ไม่ใช่ประเภทอินพุตเพียงประเภทเดียวอย่างแน่นอน
อินพุตประเภทอื่นๆ ได้แก่ แป้นพิมพ์จริง เมาส์ แทร็กแพด สไตลัส คอนโทรลเลอร์ และอุปกรณ์แบบหมุน
นอกจากนี้ เรายังเห็นอินพุตประเภทใหม่ๆ ด้วย เช่น แทร็กแพดบนแว่นตาอัจฉริยะ การติดตามการเคลื่อนไหวของดวงตาและการติดตามการเคลื่อนไหวของมือใน XR รวมถึงการเคลื่อนไหวนิ้วและการเคลื่อนไหวข้อมือใน Wear
และหากต้องการดูข้อมูลทั่วไปเพิ่มเติม ก็ยังมีอินพุตประเภทอื่นๆ ด้วย เช่น IME ของซอฟต์แวร์สำหรับเครื่องมือแก้ไขข้อความ ไมโครโฟน กล้อง และเซ็นเซอร์อื่นๆ ของอุปกรณ์
คุณต้องคาดหวังว่าแอปของคุณจะถูกใช้กับอินพุตประเภทต่างๆ มากมาย
สาเหตุหนึ่งคืออุปกรณ์ที่แอปพลิเคชันทำงานอยู่มีความหลากหลายมากขึ้นเรื่อยๆ และอุปกรณ์เหล่านั้นก็มีความสามารถในการปรับตัวมากขึ้น
รูปแบบของอุปกรณ์อาจมีวิธีการป้อนข้อมูลที่พบบ่อยที่สุด แต่สิ่งสำคัญคืออย่าคิดว่ารูปแบบของอุปกรณ์หนึ่งๆ จะหมายถึงการใช้วิธีการป้อนข้อมูลประเภทหนึ่งๆ
แม้ว่า Chromebook จะมีแทร็กแพดและแป้นพิมพ์ในตัว แต่ก็ไม่ได้ทำให้ประเภทอินพุตเหล่านั้นเป็นเอกลักษณ์เฉพาะสำหรับรูปแบบของอุปกรณ์ดังกล่าว
คุณควรคาดหวังว่าผู้ใช้จะใช้แป้นพิมพ์จริง แทร็กแพด และเมาส์ในโทรศัพท์ แท็บเล็ต และทีวีด้วย และทีวีบางรุ่นยังมีหน้าจอสัมผัสอีกด้วย
เหตุผลสำคัญประการที่ 2 ที่ควรคาดหวังและรองรับอินพุตหลายประเภทคือการช่วยเหลือพิเศษ
การอนุญาตให้ผู้ใช้ใช้อุปกรณ์ป้อนข้อมูลที่ต้องการและอนุญาตให้เปลี่ยนอุปกรณ์ป้อนข้อมูลได้ตามที่เห็นสมควรเป็นสิ่งที่ถูกต้องในการทำให้แอปพลิเคชันเข้าถึงได้และใช้งานได้มากขึ้น
และอาจมีข้อกำหนดทางกฎหมายให้มีลักษณะการทำงานที่เฉพาะเจาะจงและเข้ากันได้ในแอปพลิเคชันสำหรับอินพุตประเภทเหล่านี้ โดยเฉพาะอย่างยิ่งเกี่ยวกับสิ่งต่างๆ เช่น แป้นพิมพ์และเมาส์ ทั้งนี้ขึ้นอยู่กับเขตอำนาจศาล
กล่าวโดยย่อคือ คุณควรสร้างการรองรับอินพุตประเภทต่างๆ ไม่ว่าจะเป็นอุปกรณ์รูปแบบใดก็ตาม
มาดูกันว่า Jetpack Compose ช่วยให้แอปของคุณตอบสนองความต้องการของผู้ใช้เหล่านี้ได้อย่างไร
โดยทั่วไปแล้ว ปรัชญาของ Compose คือประเภทอินพุตที่แตกต่างกันเหล่านี้ควรทำงานอย่างเหมาะสมตั้งแต่แกะกล่องด้วยคอมโพเนนต์มาตรฐานโดยที่คุณไม่ต้องทำอะไรเป็นพิเศษ
จากนั้น คุณควรมีเครื่องมือที่จำเป็นในการปรับแต่งและปรับเปลี่ยนลักษณะการทำงานตามที่เห็นสมควร
ดังนั้น นอกเหนือจากประเภทอินพุตเริ่มต้นเหล่านั้นแล้ว เมื่อแพลตฟอร์มที่เกี่ยวข้องรองรับประเภทอินพุตมากขึ้น เราจึงตั้งเป้าที่จะสร้างการรองรับประเภทอินพุตเหล่านั้นในคอมโพเนนต์ Compose ซึ่งจะช่วยปรับปรุงลักษณะการทำงานของแอปพลิเคชันได้เพียงแค่อัปเดตเวอร์ชันของ Compose
เราจะมาดูตัวอย่าง 2 รายการในการพูดคุยครั้งนี้ ซึ่งทั้ง 2 รายการเป็นส่วนเสริมล่าสุดของ Compose
ทั้ง 2 อย่างนี้เป็นอุปกรณ์ที่คล้ายกับแทร็กแพด แต่คุณจะเห็นว่ามีการใช้งานที่แตกต่างกันมาก
เรามาเริ่มกันที่งานล่าสุดเกี่ยวกับแทร็กแพดของแล็ปท็อปประเภทต่างๆ
แทร็กแพดเป็นอุปกรณ์อินพุตที่ใช้ตัวชี้
กล่าวอย่างเจาะจงคือ เมื่อใช้แทร็กแพด คุณจะได้พิกัด 2 มิติ
แต่พิกัดของนิ้วบนแทร็กแพดจะไม่ได้อยู่ในพื้นที่พิกัดของ UI โดยตรงเหมือนกับหน้าจอสัมผัส
แต่สำหรับแทร็กแพดที่เหมือนแล็ปท็อป จะมีการแปลเป็นการควบคุมเคอร์เซอร์
ในการแปลนี้ คุณจะเห็นการแปลงแพลตฟอร์มที่ซับซ้อนมากมาย เช่น การเร่งความเร็วเคอร์เซอร์และการปฏิเสธฝ่ามือ
ดังนั้น สิ่งที่คุณจะได้รับในฝั่ง Compose คือตัวชี้ที่สอดคล้องกับตำแหน่งเคอร์เซอร์ซึ่งโดยปกติจะทำหน้าที่เหมือนอินพุตจากเมาส์
จากแพลตฟอร์ม Android เราจะได้รับข้อมูลการวางเมาส์เหนือ การคลิก รวมถึงการคลิกครั้งที่ 2 หรือ 3 และข้อมูลทั้งหมดนี้จะรวมอยู่ใน MotionEvent
เพื่อให้เข้าใจว่าเราได้ปรับปรุงลักษณะการทำงานใน Compose เวอร์ชันล่าสุดอย่างไร ก่อนอื่นมาดูภาพรวมคร่าวๆ เกี่ยวกับวิธีที่ Compose จัดการเหตุการณ์เคอร์เซอร์เหล่านี้อย่างละเอียดยิ่งขึ้น
เราจะแบ่งออกเป็น 6 ระยะ และจะอธิบายแต่ละระยะตามลำดับ
ระยะแรกคือการย้าย MotionEvent ไปยัง Compose
ดังนั้น Compose จึงเป็นเพียงมุมมองหนึ่งที่อยู่เบื้องหลัง ซึ่งเป็นมุมมองที่ซับซ้อนมากและทำสิ่งต่างๆ ได้มากมาย แต่ก็เป็นเพียงมุมมองหนึ่งเท่านั้น ซึ่งหมายความว่าต้องทำงานภายในระบบ Android โดยรวมสำหรับการป้อนข้อมูลด้วยเคอร์เซอร์
ดังนั้นใน Compose หมายความว่า Compose ซึ่งอยู่ในหน้าต่างปกติภายในกิจกรรมปกติจะได้รับ MotionEvent ซึ่งเป็น MotionEvent ของแพลตฟอร์ม Android
จากนั้น Compose จะต้องจัดการเหตุการณ์เหล่านั้นและทำทุกอย่างที่คุณต้องการทำภายใน Compose เกี่ยวกับอินพุตเคอร์เซอร์
ระยะแรกคือการแปล MotionEvent เหล่านั้นเป็นการแสดงผลภายในที่ไม่ขึ้นอยู่กับแพลตฟอร์มใน Compose ซึ่งเราเรียกว่า PointerInputEvent
ซึ่งเป็นประเภทภายใน คุณจึงจะไม่เห็นโดยตรง
และหากต้องการดูรายละเอียดทั้งหมดของสิ่งที่เกิดขึ้นที่นี่ คุณสามารถดู MotionEventAdapter ได้ แต่เราจะข้ามรายละเอียดเหล่านั้นไป
ตอนนี้เราจึงมีตัวแทนของ MotionEvent ใน Compose ที่ไม่ขึ้นอยู่กับแพลตฟอร์ม
ถัดไป ปรากฏว่าข้อมูลที่ป้อนมักจะเกิดขึ้นเมื่อเวลาผ่านไป
คุณจะได้รับเหตุการณ์อินพุตจำนวนมากตามลำดับ ดังนั้นการทราบสิ่งที่เกิดขึ้นเมื่อเวลาผ่านไปจึงมีประโยชน์อย่างยิ่ง
สิ่งต่างๆ เช่น ท่าทางสัมผัส การติดตามความเร็ว การตรวจจับการเลื่อน ทั้งหมดนี้ต้องอาศัยความเข้าใจเกี่ยวกับสิ่งที่เกิดขึ้นในแต่ละช่วงเวลา
ดังนั้น ขั้นตอนถัดไปในไปป์ไลน์การประมวลผลนี้คือการเพิ่มข้อมูลเวลา และจะทำการประมวลผลล่วงหน้าบางอย่างโดยอิงตามเหตุการณ์ตัวชี้ที่ต่อเนื่องกัน
ในโค้ด คุณสามารถมองว่านี่เป็นการนำ PointerInputEvent ปัจจุบันมารวมกับสิ่งที่เกิดขึ้นกับเหตุการณ์ก่อนหน้า จากนั้นเราจะสร้าง InternalPointerEvent ที่คำนึงถึงเวลา
นี่เป็นประเภทภายในอีกประเภทหนึ่งตามที่ชื่อบอกไว้ แต่คุณสามารถคิดว่านี่เป็นแผนที่ของรหัสตัวชี้ต่างๆ สำหรับการเปลี่ยนแปลง PointerInputChanges และ PointerInputChanges เป็นประเภทสาธารณะ
นี่คือรายการแรก
และสิ่งที่คุณอาจสังเกตเห็นเมื่อนึกถึงรหัสตัวชี้ต่างๆ ก็คือตอนนี้เราทราบถึงการติดตามเวลาแล้ว เราจึงติดตามได้ด้วยว่ารหัสตัวชี้จะมาและไปเมื่อใด
ไม่ได้มีแค่คนเดียว
หากคุณใช้นิ้วหลายนิ้วบนหน้าจอสัมผัส คุณอาจมีตัวชี้หลายตัวที่ปรากฏขึ้นและหายไปพร้อมกัน และเราต้องจัดการกับตัวชี้เหล่านั้น
ขอย้ำอีกครั้งว่าหากต้องการเจาะลึกรายละเอียด คุณสามารถดู PointerInputChangeEventProducer ซึ่งทำสิ่งเหล่านี้ทั้งหมด แต่เราจะข้ามไป
เรายังมีเรื่องที่ต้องพูดถึงอีกมาก
ตอนนี้เราจึงมีอินพุตที่แสดงถึง Compose และมีข้อมูลเวลา
ขั้นตอนถัดไปคือการพิจารณาว่าจะทำอย่างไรกับเหตุการณ์นั้น
เราจะส่งไปที่ไหน
ซึ่งนำไปสู่การทดสอบเส้นทาง Hit
ลองจินตนาการถึงสถานการณ์ที่เรามี MotionEvent ที่ส่งผ่าน และ ComposeView นี้กำลังเติมเต็มทั้งหน้าต่างหรือทั้งหน้าจอ
เราต้องทราบว่าจะส่งไปที่ใด
และเนื่องจาก Compose เป็นเพียงมุมมอง แต่เรามีสิ่งต่างๆ มากมายภายใน Compose ไม่ว่าจะเป็นโหนด ปุ่ม และสิ่งต่างๆ ที่คุณโต้ตอบด้วย เราจึงต้องดำเนินการทั้งหมดใน Compose เพื่อค้นหาว่าจะส่งเหตุการณ์ที่เกิดขึ้นในตำแหน่งที่เฉพาะเจาะจงไปที่ใด และค้นหาว่าโหนดใดที่สนใจเหตุการณ์นั้นจริงๆ
โหนดเลย์เอาต์เหล่านี้มีพิกัด มีขอบเขต และมีรูปร่าง ดังนั้นเราจึงต้องพิจารณาว่าโหนดใด (หากมี) ที่ถูกกด
แต่นั่นก็ไม่ใช่มุมมองที่พบบ่อยที่สุด
ปรากฏว่าเราชอบใส่องค์ประกอบที่โต้ตอบได้ไว้ในองค์ประกอบที่โต้ตอบได้อื่นๆ เช่น การใส่ปุ่มไว้ในรายการ
ซึ่งเราทำแบบนั้นบ่อยมาก
ดังนั้น กรณีทั่วไปที่สมบูรณ์ในที่นี้คือเหตุการณ์การป้อนข้อมูลที่เฉพาะเจาะจงจะสร้างเส้นทางการแตะแบบเต็มซึ่งผ่านโหนดที่โต้ตอบได้ทุกโหนดที่พิกัดของเหตุการณ์การป้อนข้อมูลแตะโดน
ดังนั้น ในกรณีนี้จึงมี 3 รายการตามลำดับชั้นที่ซ้อนกัน
เราจึงมีเส้นทาง Hit แต่ก็ยังไม่เพียงพอ
จำได้ไหมที่ผมบอกว่าเรามีเหตุการณ์อินพุตตัวชี้หลายรายการ ตัวชี้หลายตัวที่อาจกดลง
เราจำเป็นต้องมี Hit Path Tree แบบเต็ม
เมื่อมีตัวชี้หลายตัว เส้นทางการกดปุ่มจะไม่ได้มีเพียงเส้นทางเดียว
นั่นคือขั้นตอนถัดไป ซึ่งก็คือการสร้างและอัปเดต Hit Path Tree นี้
นี่คือข้อมูลโดยละเอียดเกี่ยวกับสิ่งที่เกิดขึ้น
ทางด้านซ้าย เรามีโหนดที่จัดวางเป็นภาพ และทางด้านซ้ายล่าง คุณจะเห็นการแสดงผลตามลำดับชั้น โหนดใดอยู่ภายในโหนดอื่นๆ โหนดใดเป็นบรรพบุรุษหรือลูกหลานของกันและกัน
เมื่อตัวชี้เลื่อนลง เราจะติดตาม Hit Path ซึ่งเป็นเส้นทางทั้งหมดผ่านโครงสร้าง จากนั้นเราจะได้รับ Hit Path สำหรับตัวชี้นั้นๆ
เส้นทางการตีนี้จะกลายเป็นต้นไม้เมื่อเราได้ตัวชี้ที่ 2
โดยอาจตัดกับโหนดเดียวกันกับอีกเส้นทางหนึ่ง แต่ก็อาจโต้ตอบกับโหนดอื่นๆ ด้วยเช่นกัน
ดังนั้น ทางด้านขวาคือ Hit Path Tree ที่เราดูแลรักษาอยู่ในปัจจุบัน
และพอยน์เตอร์อาจปรากฏขึ้นและหายไป ดังนั้นเราจึงต้องรักษาพอยน์เตอร์นี้ไว้ตลอดเวลาเพื่อให้แน่ใจว่าเราได้รับรายการโหนดทั้งหมดที่สนใจเหตุการณ์ที่กำลังดำเนินอยู่ทุกเหตุการณ์ ณ ขณะนี้
โอเค
ตอนนี้เรามี Hit Path Tree ที่เราดูแลรักษาสำหรับเหตุการณ์อินพุตเหล่านี้ ซึ่งหมายความว่าเรากำลังเข้าสู่ระยะถัดไป
ตอนนี้เราทราบแล้วว่าจะส่งเหตุการณ์อินพุตตัวชี้เหล่านี้ไปที่ใด และโหนดใดสนใจเหตุการณ์ที่เฉพาะเจาะจงแต่ละรายการ
เมื่อทราบแล้ว เราก็สามารถทำการแปลงพิกัดได้
ซึ่งจะดีมากหากโหนดได้รับเหตุการณ์อินพุตภายในพื้นที่พิกัดในเครื่องของตัวเอง คุณจึงไม่ต้องคำนวณพิกัดเองทั้งหมด
ดังนั้น เมื่อเราทราบข้อมูลดังกล่าวแล้ว เราจะนำเหตุการณ์อินพุตตัวชี้ไปรวมกับพิกัดของโหนดที่สนใจ จากนั้นระบบจะสร้าง PointerEvent สาธารณะที่จะส่งไปยังคุณทุกคนและตัวแก้ไขอินพุตตัวชี้
และนั่นคือสิ่งสุดท้ายในเฟสที่ 6 ซึ่งก็คือการส่งเหตุการณ์ออกไปในที่สุด
นี่คือเหตุการณ์อินพุตตัวชี้ที่เกิดขึ้น และส่งไปยังโหนดเพื่อดำเนินการตามที่ต้องการ
เราดำเนินการนี้ใน 3 ขั้นตอนที่แตกต่างกัน
เรามีบัตรผ่านเริ่มต้น บัตรผ่านหลัก และบัตรผ่านสุดท้าย
เหตุผลที่มีการส่งผ่าน 3 แบบคือเพื่อให้โหนดสื่อสารกันและสื่อสารความสนใจในส่วนที่เฉพาะเจาะจงของเหตุการณ์อินพุตตัวชี้ที่เฉพาะเจาะจง จากนั้นจึงใช้ส่วนต่างๆ ของเหตุการณ์เหล่านั้นเป็นส่วนหนึ่งของการส่ง
ดังนั้น การส่งผ่านครั้งแรกหรือการส่งผ่านเริ่มต้นจะส่งจากระดับบนลงล่าง
ตัวอย่างที่ฟีเจอร์นี้มีประโยชน์คือ หากโหนดเลย์เอาต์ด้านนอกบางโหนดอาจเป็นคอนเทนเนอร์การเลื่อน และโหนดทราบว่าได้เริ่มเลื่อนแล้ว และต้องการหยุดเหตุการณ์เคอร์เซอร์ทั้งหมดไม่ให้เข้าถึงโหนดย่อยใดๆ
ซึ่งในการส่งผ่านครั้งแรกจะทำให้สามารถใช้เหตุการณ์ได้ และองค์ประกอบย่อยจะไม่ได้รับเหตุการณ์ใดๆ อีก
บัตรที่ 2 คือบัตรหลัก
และนี่เป็นเพียงความสัมพันธ์เดียวที่เปลี่ยนจากผู้สืบทอดเป็นบรรพบุรุษ
ตามชื่อที่บอกไว้ บัตรนี้เป็นบัตรหลักสำหรับทำสิ่งต่างๆ
ตัวอย่างเช่น นี่คือตำแหน่งที่องค์ประกอบสืบทอดจะใช้เหตุการณ์การกดลง เริ่มจัดการการคลิก และมีโอกาสทำเช่นนั้นก่อนองค์ประกอบหลักหากคุณมีองค์ประกอบที่คลิกได้ที่ซ้อนกัน
และรอบสุดท้ายซึ่งเป็นรอบสุดท้ายจะมีลักษณะเหมือนกับรอบแรก โดยจะเริ่มจากระดับบนสุดไปยังระดับล่างสุด
ซึ่งเป็นจุดที่องค์ประกอบย่อยสามารถแจ้งองค์ประกอบหลักว่าองค์ประกอบหลักได้ใช้ส่วนหนึ่งของเหตุการณ์ไปแล้ว
ดังนั้น หากคอมโพเนนต์ย่อยเริ่มจัดการการคลิก แต่คอมโพเนนต์หลักเริ่มเลื่อน คอมโพเนนต์ย่อยจะเห็นว่าคอมโพเนนต์หลักทำเช่นนั้น แล้วคอมโพเนนต์ย่อยจะยกเลิกการคลิกที่เริ่มจัดการได้
ทั้งหมดนี้คือ 3 รอบและ 6 ระยะ
ซึ่งเป็นรากฐานสำหรับทุกอย่างที่อยู่เหนือระบบอินพุตตัวชี้
การจัดการท่าทางสัมผัสทั้งหมด การเลื่อน การลากได้ การคลิก และอินพุตเคอร์เซอร์ที่กำหนดเองทั้งหมดสร้างขึ้นจากรากฐานนี้
จากที่กล่าวมาทั้งหมด ตอนนี้เราจะพูดถึงรายละเอียดเล็กน้อยเกี่ยวกับวิธีที่เราปรับปรุงการรองรับลักษณะการทำงานของแทร็กแพดใน Compose
ดังนั้นก่อน Compose 1.12 ระบบจะรายงานเหตุการณ์การป้อนข้อมูลจากแทร็กแพดเป็นประเภทตัวชี้ของการแตะ เนื่องจากเป็นการใช้นิ้วโต้ตอบกับแทร็กแพดเพื่อควบคุมเคอร์เซอร์
อย่างไรก็ตาม ผู้ใช้คาดหวังว่าอินพุตประเภทนี้จะทำงานคล้ายกับเมาส์จริงมากกว่า
เราจึงเปลี่ยนประเภทตัวชี้จาก PointerType.Touch เป็น PointerType.Mouse
การเปลี่ยนแปลงนี้จะช่วยให้ผู้ใช้เห็นประสบการณ์การใช้งานเมาส์และแทร็กแพดที่สอดคล้องกันมากขึ้นสำหรับคอมโพเนนต์ที่ดูข้อมูลนี้
ตัวอย่างเช่น ลักษณะการทำงานของเคล็ดลับเครื่องมือ คุณอาจต้องการให้แทร็กแพดและเมาส์มีลักษณะการทำงานเหมือนกันสำหรับเคล็ดลับเครื่องมือ
การเปลี่ยนแปลงครั้งใหญ่ครั้งที่ 2 ที่เราทำเกี่ยวกับแทร็กแพดเกี่ยวข้องกับท่าทางสัมผัสแบบหลายนิ้วที่คุณจะทำบนแทร็กแพด
ก่อนหน้านี้ Compose ได้ผ่านแนวคิดที่ชาญฉลาดแต่ค่อนข้างน่ากลัวเกี่ยวกับนิ้วปลอมของแพลตฟอร์ม Android
มาดูกันว่าหมายความว่าอย่างไร
เมื่อคุณใช้ 2 นิ้วบนแทร็กแพดเพื่อเลื่อน Android จะสร้างนิ้วจำลองบนหน้าจอสัมผัส 1 นิ้วซึ่งจะแตะลงตรงตำแหน่งเคอร์เซอร์
จากนั้น เมื่อคุณขยับนิ้วบนแทร็กแพด นิ้วจำลองบนหน้าจอสัมผัสจะขยับตามระยะทางและทิศทางที่ถูกต้องเพื่อเลียนแบบลักษณะการทำงานที่ต้องการ แล้วจึงปล่อย
ดังนั้น การเลื่อน 2 นิ้วขึ้นบนแทร็กแพดจะได้รับการแปลเป็นนิ้วปลอม 1 นิ้วบนหน้าจอสัมผัส ซึ่งเลื่อนขึ้นด้วยเช่นกัน ซึ่งจะทำให้เกิดการเลื่อนลง
สิ่งที่น่าสนใจคือ หากคุณใช้ฟีเจอร์การเลื่อนแทร็กแพดแบบย้อนกลับเหมือนฉัน คุณก็คงต้องการให้การเลื่อนไปในทิศทางตรงกันข้ามจริงๆ
และวิธีที่ทำได้คือการพลิกทิศทางของนิ้วปลอม
ดังนั้นตอนนี้ การใช้ 2 นิ้วบนแทร็กแพดที่เลื่อนขึ้นจะถูกแปลเป็นนิ้วปลอมนิ้วเดียวบนหน้าจอสัมผัสที่เลื่อนลง ซึ่งจะทำให้เกิดการเลื่อนขึ้น ซึ่งตรงกันข้ามกับสิ่งที่เรามีก่อนหน้านี้
การปรับขนาดก็ทำงานในลักษณะที่คล้ายกัน
เมื่อคุณใช้ 2 นิ้วบนแทร็กแพดเพื่อปรับขนาด Android จะสร้างนิ้วจำลองบนหน้าจอสัมผัส 2 นิ้วที่กดลง แล้วเลื่อนเข้าหากันหรือออกจากกัน โดยขึ้นอยู่กับท่าทางสัมผัส เพื่อเลียนแบบลักษณะการซูมเข้าหรือซูมออกที่ต้องการ
ดังนั้น ตั้งแต่ Compose 1.12 สำหรับการเลื่อน และ Compose 1.13 สำหรับการปรับขนาด ตอนนี้เราจะสกัดกั้นนิ้วปลอมเหล่านั้น
เราจะไม่ส่งเหตุการณ์เหล่านั้นผ่านแพลตฟอร์มที่ให้มา แต่จะตีความเหตุการณ์เหล่านั้นใหม่เป็นประเภทเหตุการณ์ตัวชี้ใหม่ ได้แก่ PanStart, PanMove และ PanEnd สำหรับการแพน และ ScaleStart, ScaleChange และ ScaleEnd สำหรับการปรับขนาด
และเราจะทำเช่นนี้ในระยะการแปลงเหตุการณ์ Android เป็น Compose ที่ฉันพูดถึงก่อนหน้านี้
ดังนั้น เราจึงแปลงเหตุการณ์ Fake Finger เป็นประเภทที่เหมาะสม แล้วส่งผ่านท่าทางสัมผัสที่แพลตฟอร์มกำหนดนี้ไปยัง Hit Path ที่สอดคล้องกับเคอร์เซอร์
มาดูกันว่าทำไมเรื่องนี้จึงสำคัญ
ทำไมเราจึงทำเช่นนี้
สมมติว่ากล่องนี้เป็นรูปภาพสวยๆ ที่เราต้องการปรับขนาดให้ใหญ่ขึ้น
เมื่อคุณใช้ 2 นิ้วบนแทร็กแพดเพื่อปรับขนาด เป็นไปได้ว่านิ้วปลอมนิ้วใดนิ้วหนึ่งอาจไม่โดนองค์ประกอบ
เส้นทางการกดแป้นจะไม่ตัดกับรูปภาพ และจะเริ่มต้นนอกขอบเขต
ดังนั้น สิ่งที่จะเกิดขึ้นแทนการปรับขนาดคือรูปภาพอาจเลื่อนแทน
จากนั้นหากมีองค์ประกอบที่เลื่อนได้อีกรายการหนึ่งอยู่นอกรูปภาพ องค์ประกอบนั้นก็อาจเริ่มเลื่อนไปพร้อมกันด้วย
ซึ่งไม่ใช่สิ่งที่ผู้ใช้ต้องการ
บริษัทต้องการขยายธุรกิจ
ดังนั้น สิ่งที่เราทำในตอนนี้คือแทนที่จะส่งผ่านนิ้วปลอมเหล่านั้น ตอนนี้เราจะส่งท่าทางการปรับขนาดไปยังองค์ประกอบที่อยู่ใต้ตำแหน่งเคอร์เซอร์เท่านั้น ซึ่งจะนำไปสู่ลักษณะการทำงานที่ถูกต้อง
ไม่ว่าเคอร์เซอร์จะอยู่ที่ใดหรืออยู่ใกล้กับขอบขององค์ประกอบที่ต้องการปรับขนาดมากเพียงใด ตอนนี้องค์ประกอบจะปรับขนาดได้อย่างถูกต้อง
ข่าวดีสำหรับทุกคนก็คือ ระบบจะใช้เหตุการณ์อินพุตที่ตีความใหม่เหล่านี้โดยค่าเริ่มต้นในคอมโพเนนต์ต่างๆ เช่น scrollable และ transformable เพื่อให้พฤติกรรมที่มีคุณภาพสูงขึ้นสำหรับอินพุตแทร็กแพด หากคุณใช้บล็อกพื้นฐานเหล่านั้น
และหากคุณใช้สิ่งที่สร้างขึ้นจาก API เหล่านี้ คุณจะได้รับลักษณะการทำงานที่ปรับปรุงแล้วเพียงแค่อัปเดต Compose เป็นเวอร์ชันล่าสุด
และหากคุณกำลังเขียนตัวปรับแต่งอินพุตตัวชี้ที่กำหนดเอง เราขอแนะนำให้คุณดู API ใหม่เหล่านี้และตรวจสอบว่าคุณรองรับ API ดังกล่าวเพื่อมอบประสบการณ์การใช้งานที่ดีที่สุดแก่ผู้ใช้ในอุปกรณ์อินพุตที่แตกต่างกันทั้งหมดเหล่านี้
และแน่นอนว่าเรายังเพิ่ม API การทดสอบด้วย ซึ่งคุณสามารถตรวจสอบได้ว่าแอปของคุณจัดการอินพุตประเภทต่างๆ เหล่านี้อย่างถูกต้องหรือไม่
ดังนั้น performTrackpadInput จึงดูคล้ายกับ API การทดสอบที่มีอยู่สำหรับเมาส์และการสัมผัสอย่างมาก
onNodeWithContentDescription("Photo")
.performTrackpadInput {
click(center)
pan(Offset(0f, 100f))
scale(0.9f)
}และเมื่อใช้ทั้งหมดนี้ คุณจะตรวจสอบได้ว่าแอปทำงานอย่างถูกต้องไม่ว่าผู้ใช้จะใช้อุปกรณ์อินพุตใดในอุปกรณ์ของคุณ
หวังว่าข้อมูลนี้จะช่วยให้คุณเข้าใจได้ดียิ่งขึ้นว่าเหตุการณ์เคอร์เซอร์ทำงานอย่างไรตั้งแต่การใช้นิ้วแตะทัชแพดไปจนถึงการทำงานในแอป
ต่อไปฉันจะส่งต่อให้ Jeremy พูดถึงวิธีที่แตกต่างออกไปอย่างมากในการใช้แทร็กแพด
ขอขอบคุณ
โอเค
สวัสดี ฉันชื่อ Jeremy Walker
ฉันทำงานเกี่ยวกับอินพุตเป็นจำนวนมาก และคิดว่าน่าสนใจหากจะบอกคุณเกี่ยวกับสิ่งใหม่ๆ ที่เรากำลังทำกับอินพุต Compose และผลกระทบที่มีต่อคุณ
และโดยเฉพาะอย่างยิ่งกับอินพุตประเภททางอ้อมนี้ ซึ่งเกิดขึ้นเนื่องจากอินพุตใหม่ที่อิงตามรูปแบบของอุปกรณ์ใหม่ นั่นคือแว่นตาอัจฉริยะ
ดังนั้น เมื่อคุณรับข้อมูลจากแว่นตา คุณสามารถทำได้ 2 วิธี คือ คุณสามารถมองไปที่บางสิ่ง คุณสามารถใช้เสียง คุณสามารถใช้ท่าทางสัมผัส แต่ฉันจะพูดถึงทัชแพดโดยเฉพาะ
ซึ่งแตกต่างจากที่ Alex พูดถึงเล็กน้อยตรงที่อยู่ด้านข้างของศีรษะ เป็นแนวตั้ง กว้างมาก และสั้นมาก
ดังนั้นเมื่อเราคิดถึงวิธีการทำงานของฟีเจอร์นี้ใน Compose หากคุณจินตนาการว่ากำลังมองปุ่มเล็กๆ ตรงหน้า หากคุณเลื่อนเคอร์เซอร์เพื่อพยายามแตะปุ่มนั้น ประสบการณ์การใช้งานก็คงไม่ดีนักใช่ไหม
แล้วเราจะรองรับการใช้งานอย่างไร
นี่คือหน้าตาของ UI ของแว่นตา
โดยได้รับการออกแบบมาเป็นพิเศษเพื่อวางเนื้อหาให้กลมกลืนกับขอบเขตการมองเห็นของคุณ
แต่ก็เป็นเรื่องง่ายๆ เราพยายามทำให้เข้าใจง่าย
และหากดูตัวอย่างที่นี่ คุณจะเห็นว่านี่คือรายการ
โดยเน้นที่องค์ประกอบบางอย่างตรงกลาง
เราต้องการทำอะไรกันแน่
เราต้องการเลือก หรืออาจย้ายไปยังรายการก่อนหน้าหรือถัดไป
เราไม่จำเป็นต้องทราบตำแหน่งของหน้าจอ
และตัวเลือกนี้จะซับซ้อนขึ้นมาอีกนิด แต่คุณจะเห็นว่ามีตัวเลือกพื้นฐาน 3 อย่าง ได้แก่ วางสาย เปิดเสียง หรือปิดวิดีโอ
แต่จริงๆ แล้ว คุณต้องการเลือกรายการนั้น หรือย้ายไปยังรายการอื่นแล้วเลือกรายการนั้น
เราจึงคิดว่าไม่จำเป็นต้องแมปกับตำแหน่งบนหน้าจอโดยตรง หรือในกรณีนี้คือดวงตาของคุณ
นี่คือหน้าตาของฟีเจอร์นี้
ตัวอย่างเช่น คุณจะเห็นได้ที่นี่ว่าฉันกำลังเลื่อนไปมาระหว่างองค์ประกอบต่างๆ และนี่คือ UI ของแว่นตา ซึ่งตรงกับสิ่งที่เราต้องการ
และคุณสามารถแตะบัตรนั้นได้
เราจึงพิจารณา Android เพื่อดูว่ามีอะไรบ้างที่เราสามารถใช้เพื่อรองรับการทำงานนี้ได้
และถ้าคุณเคยได้รับ โอ้ ขอโทษที
ซึ่งเป็นการข้ามไปข้างหน้า
ขอย้อนกลับไปก่อน
เริ่มเลยนะคะ
โอเค
ดังนั้น หากคุณเคยใช้อุปกรณ์เหล่านี้และลิงก์กับอุปกรณ์ Android คุณจะทราบว่าสามารถย้ายจากองค์ประกอบ UI หนึ่งไปยังอีกองค์ประกอบหนึ่งได้อย่างง่ายดาย
เช่น ด้วยรีโมต คุณจะเห็นว่าคุณสามารถ หากคุณจินตนาการหรือคุณได้ลิงก์กับ Google TV และคุณมีตารางภาพยนตร์ทั้งหมด คุณสามารถกดปุ่มลูกศรเพื่อไปยังภาพยนตร์ที่ต้องการ และคุณสามารถกดปุ่มเพื่อเลือกภาพยนตร์นั้น ปุ่มตกลง
หากมีเมนูเกมและมีคอนโทรลเลอร์นี้ คุณสามารถใช้ D-pad หรือจอยสติ๊กเพื่อไปยังองค์ประกอบ UI เช่น ในเมนู แล้วเลือกองค์ประกอบนั้น
แป้นพิมพ์ก็เช่นกัน
ซึ่งตรงกับสิ่งที่เราต้องการใน Compose
และนี่คือตัวอย่างเพื่อให้คุณเห็นภาพว่าหน้าตาเป็นอย่างไร
และหากย้อนกลับไปอีกหน่อย ก็มีทัชแพดประเภทนี้ที่จับคู่กับทีวี และใช้สิ่งที่เรียกว่าการแตะเพื่อไปยังส่วนต่างๆ
และแนวคิดก็คือพิกัด X และ Y จะไม่ถูกแตะต้องและไม่เชื่อมโยงกับหน้าจอเลย
แต่จะใช้เพื่อตรวจจับท่าทางสัมผัสเท่านั้น
สิ่งที่คุณทำได้คือ หากปัดไปทางขวา ก็จะเหมือนกับการกดชอบ ลูกศรจะเลื่อนไป
หากปัดไปทางซ้าย คุณจะไปทางซ้าย ขึ้น และลง
ดังนั้น วิธีนี้จึงช่วยให้เราได้สิ่งที่ต้องการเป็นส่วนใหญ่
คุณใช้เฉพาะ x และ y สำหรับการติดตามความเร็วเพื่อดูการลากและการปัด เป็นต้น ซึ่งจะช่วยให้เราได้ข้อมูลส่วนใหญ่ที่ต้องการเพื่อเริ่มต้นใช้งาน Compose
ซึ่งไม่ตรงกันทั้งหมดเพราะมีการแมปกับทีวีด้วย เราจึงต้องตรวจสอบว่าไม่ได้ใช้เส้นทางทีวีและไม่ทำให้ทีวีมีปัญหาในภายหลัง ดังนั้นเราจึงต้องแยกทั้ง 2 อย่างออกจากกัน แต่เราจะพูดถึงเรื่องนี้ในอีกสักครู่
แต่ก็ช่วยให้เรามีจุดเริ่มต้น
เพื่อให้เราใช้การไปยังส่วนต่างๆ ด้วยการสัมผัสประเภทนี้ได้
เอาล่ะ
การออกแบบ API จะมีลักษณะอย่างไร
ใน Compose อินพุตที่พบบ่อยที่สุดคือการแตะใช่ไหม
ดังนั้นเราจึงมีงานที่ต้องทำเกี่ยวกับเรื่องนี้มากมาย
เราจึงต้องหาวิธีที่ทำให้เนื้อหาเกี่ยวข้องกับเรื่องนั้น
โปรดทราบว่า PointerEvent มีลักษณะดังนี้
คุณจะเห็นว่ามีประเภทซึ่งเป็นการเคลื่อนไหวแบบกดลงในเหตุการณ์การกดขึ้น จากนั้นคุณจะมี PointerInputChange ซึ่งเป็นเพียงรายการ คุณอาจคิดว่ามันเป็นนิ้วก็ได้
หากคุณพับนิ้วลง 3 นิ้ว คุณจะมี 3 รายการในลิสต์
เราจึงอยากให้มีลักษณะคล้ายกับแบบนี้
นี่ไม่ใช่โมดูล UI ซึ่งเป็นโมดูลที่ต่ำกว่าที่นักพัฒนาแอปส่วนใหญ่ใช้เมื่อจัดการกับอินพุต
โดยจะอยู่เหนือชั้นพื้นฐานขึ้นไปอีกชั้นหนึ่ง
และนั่นคือที่ที่ตัวตรวจจับท่าทางสัมผัสทั้งหมดของเราอยู่
เพราะในฐานะนักพัฒนาซอฟต์แวร์ คุณไม่จำเป็นต้องสนใจรายละเอียดเล็กๆ น้อยๆ เหล่านี้
คุณเพียงต้องการทราบว่ามีการลาก การคลิก หรือการปัดเกิดขึ้นหรือไม่ จากนั้นจึงดำเนินการตามนั้น
เราจึงมีโค้ดจำนวนมากที่ทำหน้าที่ดังกล่าวให้คุณ และโค้ดเหล่านี้ทำงานโดยใช้สิ่งต่างๆ เหล่านี้ในเบื้องหลัง
เราจึงเริ่มคิดว่าต้องทำให้โค้ดที่มีอยู่ในรากฐานสามารถรองรับประเภทใหม่เหล่านี้ได้อย่างง่ายดายที่สุด
เราจึงสร้างประเภทใหม่ที่มีลักษณะคล้ายกันมาก
แต่จะเรียกว่าการแทรกพรอมต์โดยอ้อม
ส่วนการโต้ตอบทางอ้อมหมายความว่าไม่ได้แตะหน้าจอโดยตรง
ดังนั้น ระบบจะแจ้งให้คุณทราบว่าฟีเจอร์นี้กำลังจะมา และอย่าคิดถึงฟีเจอร์นี้จากมุมมองของการแตะ
ลองนึกภาพว่าเรากำลังจัดการท่าทางสัมผัสและไปยังส่วนต่างๆ ระหว่างองค์ประกอบ UI
ประเภทเหมือนกัน
มีรายชื่อนิ้วอยู่
ในกรณีนี้คือ IndirectPointerInputChange
เราจึงทำตามนั้นและได้ผลดีมาก
แต่ยังมีอีกรายการหนึ่งที่เราพบซึ่งเรียกว่าแกนการเคลื่อนไหวตามทิศทางหลัก
ชื่ออาจจะยาวไปหน่อย แต่คุณจะเข้าใจเมื่อเราอธิบาย เพราะที่มาของชื่อนี้ค่อนข้างน่าสนใจ
แล้วฟีเจอร์นี้เกิดขึ้นได้อย่างไร
อีกครั้ง คุณมีทัชแพดนี้ที่ด้านข้างของศีรษะ ซึ่งมีลักษณะกว้างและสั้น
และในตอนนี้ เราก็มีแนวคิดที่ว่า เรามีการนำทางด้วยการสัมผัสแล้ว
เราจึงปัดไปทางซ้ายและขวาได้
ซึ่งก็ใช้ได้ดีเลย
แต่ถ้าคุณนึกถึงแทร็กแพดที่มีอยู่ในปัจจุบัน
เมื่อคุณเลื่อนไปทางซ้ายหรือขวา คุณจะเลื่อนไปทางซ้ายหรือขวาบนแทร็กแพดพร้อมกับเนื้อหา UI
หากเลื่อนขึ้นหรือลง คุณจะเลื่อนดูรายการขึ้นหรือลง
ดังนั้นหากคุณพยายามทำแบบนั้นโดยสวมแว่นตา แบบนี้ก็ไม่แย่เกินไปใช่ไหม
แต่ถ้าคุณทำแบบนี้ ประสบการณ์ที่ได้ก็จะไม่ดีนัก
เราพบว่าการเคลื่อนไหวที่เป็นธรรมชาติที่สุดคือการแตะ แต่เป็นการปัดไปตามด้านข้างของแว่นตา
เราจึงทำการศึกษาหลายอย่างกับผู้ใช้ และพบว่าจริงๆ แล้วผู้ใช้คาดหวังว่าเมื่อปัดในแนวนอน เนื้อหาจะไม่เลื่อนในแนวนอน แต่จะเลื่อนในแนวตั้ง
คุณอาจลองนึกภาพตามในหัว เช่น เมื่อปัดที่นี่ หากมีรายการอยู่ตรงหน้า เช่น ไปข้างหน้า คุณสามารถเลื่อนไปข้างหน้าในรายการหรือจะเลื่อนย้อนกลับในรายการก็ได้
เราจึงนำอินพุต 2 มิติมาพยายามคิดแบบ 1 มิติ
และนั่นคือที่มาของแนวคิดเรื่องแกนการเคลื่อนไหวหลัก ซึ่งคุณสามารถเลื่อนในแนวนอนและจะเลื่อนในแนวตั้งได้
คุณจึงระบุในอุปกรณ์ได้
คุณอาจจะบอกว่า เฮ้ นี่ไม่ใช่แทร็กแพดธรรมดาๆ นะ
ฉันต้องการให้ทิศทางหลักเป็นแนวนอน และนั่นก็เป็นแกนหลักเพียงแกนเดียวที่ฉันต้องการเคลื่อนที่ไปตามนั้น
นั่นคือที่มาของชื่อนี้
ตกลง
เราจึงรู้สึกดีกับเรื่องนี้มาก
Compose จะจัดการทุกอย่างเอง
และคุณมีการใช้งานแนวตั้งที่ยอดเยี่ยมนี้
คุณลองพิจารณาเรื่องนี้ได้
ดังนั้น วิธีที่เราแมปก็คือตอนนี้คุณมีคำจำกัดความแนวนอนแล้ว เรามีแค่ไปข้างหน้าและย้อนกลับ
เราไม่มีทิศทางขึ้น ลง ซ้าย ขวา
เรามีแค่ปุ่มไปข้างหน้าและย้อนกลับ
จากนั้นเราจะแมปได้หากคุณคุ้นเคยกับการโฟกัสด้วยถัดไปและก่อนหน้า
ตอนนี้เราก็แค่เลื่อนไปยังรายการถัดไปและก่อนหน้า
ซึ่งวิธีนี้ใช้ได้ดีกับวิดีโอแนวตั้ง
และยังดูดีขึ้นด้วย
ซึ่งใช้ได้กับวิดีโอแนวนอนทันทีที่แกะกล่องใช่ไหม
เพราะคุณมีรายการที่โฟกัสอยู่หลายรายการ
คุณเพียงแค่ไปที่รายการถัดไปหรือก่อนหน้า และจะใช้ได้กับทั้ง 2 รายการ
ดังนั้นนี่จึงเป็นกรณีที่เกิดขึ้นกับ Compose ซึ่งเราได้กำหนดและคิดเรื่องนี้ทั้งหมดใน Compose แต่จะดีมากหากอุปกรณ์สามารถบอกได้เอง เพราะอุปกรณ์รู้ว่ามีรูปร่างแปลกๆ และรู้ว่าต้องการเพียงแกนหลักนี้ แต่ไม่มีวิธีกำหนดสิ่งนั้น
ดังนั้นตอนนี้เราจึงต้องนำแนวคิดนี้กลับไปที่แพลตฟอร์มและบอกว่า เราต้องกำหนดแนวคิดนี้ในแพลตฟอร์มเพื่อให้สามารถกำหนดมาตรฐานและอุปกรณ์เหล่านี้สามารถระบุได้เอง เพื่อให้ Compose รองรับได้อย่างเต็มที่
ดังนั้นจึงมีกรณีที่เราทำงานใน Compose และพัฒนาต่อไปใน Compose และทำงานย้อนกลับ และนำมาใช้ร่วมกัน
เราจึงทำตามนั้น
เราสร้าง API ใหม่นี้ขึ้นมาเพื่อให้คุณหรืออุปกรณ์สามารถระบุข้อมูลดังกล่าวได้
InputDevice.ViewBehavior
.getPrimaryDirectionalMotionAxis()และหากคุณจำได้ก่อนหน้านี้ ตอนที่ฉันพูดถึงการป้อนข้อมูลด้วยการสัมผัสหรือการไปยังส่วนต่างๆ ด้วยการสัมผัส ฉันกำลังพูดถึงวิธีที่ออกแบบมาสำหรับทีวีเป็นหลัก
เราไม่ต้องการให้การติดตั้งใช้งานเหล่านั้นหยุดทำงาน
เราจึงเพิ่มอีกช่องหนึ่งเพื่อระบุอินพุตกระจกประเภทใหม่นี้
ตกลง
แล้วสุดท้ายแล้ว สิ่งนี้มีความหมายต่อคุณอย่างไร
นี่เป็นเวอร์ชันที่เจาะจงมากขึ้นของสิ่งที่คุณได้รับในฐานะเครื่องมือตรวจจับท่าทางสัมผัส
// Glimmer Library
Box(
modifier =
Modifier.fillMaxSize()
.onIndirectPointerGesture(
enabled = true,
onSwipeForward = { /* onSwipeForward */ },
onSwipeBackward = { /* onSwipeBackward */ },
onClick = { /* onClick */ },
)
.focusTarget()
) {
// App()หากคุณใช้ Foundation อยู่แล้ว ระบบจะทำงานร่วมกับเครื่องมือตรวจจับท่าทางสัมผัสได้ทันที
เราได้ดำเนินการให้คุณแล้ว คุณจึงไม่ต้องทำอะไรเลย
แต่ถ้าคุณต้องการสร้างแอปสำหรับแว่นตา คุณสามารถใช้ไลบรารี Glimmer ของเราได้ และเรายังมีเครื่องมือตรวจจับท่าทางสัมผัสพิเศษ ซึ่งจะช่วยให้คุณไม่ต้องรวมท่าทางสัมผัสเข้าด้วยกัน คุณสามารถใช้เพียงท่าทางสัมผัสเดียวนี้เพื่อรับการคลิก เฟรมไปข้างหน้า และเฟรมย้อนกลับ
ตกลง
เราได้พูดถึงการทำงานของ API ในแพลตฟอร์มและใน Compose ไปแล้ว
แล้วการทดสอบล่ะ
นี่คือลักษณะของการแตะเมื่อคุณต้องการทดสอบการแตะ
@Test
clickTest {
rule.onNodeWithTag(defaultTag)
.performTouchInput
{ click(center) }
}คุณแค่พูดว่า performTouchInput แล้วทำท่าทางสัมผัส
มีท่าทางสัมผัสที่แตกต่างกันมากมาย และเราสร้างเหตุการณ์เล็กๆ ทั้งหมดเพื่อทำให้ท่าทางสัมผัสเกิดขึ้น
การทำงานในระดับสูงเป็นอย่างไร
คุณมีโมดูล Compose UI, โมดูล UI Testing และโมดูลเหล่านี้จะสื่อสารกัน อย่างน้อยก็ในแง่ของอินพุต โดยใช้ MotionEvent
นอกจากนี้ โมดูลการทดสอบ UI ยังใช้กลไกการจัดคิว ซึ่งทั้งหมดอิงตาม MotionEvent
ทำไมเราจึงบอกคุณเรื่องนี้
เนื่องจากคุณไม่สามารถสร้าง MotionEvent แบบเป็นโปรแกรมที่เหมือนกับเหตุการณ์อินพุตทางอ้อมได้ ซึ่งเป็นเรื่องดีสำหรับฉันเพราะนั่นหมายความว่าฉันต้องเขียนการสื่อสารทั้งหมดระหว่างโมดูลและระบบจัดคิวใหม่
แต่ฉันก็ทำได้
แล้วเรื่องนี้มีความหมายต่อคุณอย่างไร
หากคุณคุ้นเคยกับการทดสอบการป้อนข้อมูลด้วยการสัมผัส นี่คือสิ่งที่คุณจะได้รับสำหรับการป้อนข้อมูลทางอ้อม
คุณเพียงแค่เพิ่มคำว่า "ทางอ้อม" ลงในชื่อ
@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput (
IndirectPointerEventPrimaryDirectionalMotionAxis.X,
inputDeviceSize,
)
{ click(center) }
}ตอนนี้ฉันได้ส่งพารามิเตอร์เพิ่มเติมบางรายการแล้ว
คุณอาจคุ้นเคยกับส่วนแรก ซึ่งเป็นส่วนที่คุณระบุแนวนอน
และขนาดอินพุตก็จะเป็นขนาดของทัชแพดอย่างเห็นได้ชัด
ซึ่งการดำเนินการนี้ไม่ได้เปลี่ยนแปลงอะไรมากนัก
ดังนั้น หากดูซอร์สโค้ด คุณจะเห็นว่าฉันเพิ่งเขียนฟังก์ชันส่วนขยายและมีลักษณะดังนี้
@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput
{ click(center) }
}ตกลง
ข้อมูลนี้จะช่วยให้คุณเห็นภาพงานทั้งหมดที่เราทำเพื่อรองรับแทร็กแพดบนกรอบแว่นหรือแว่นตาอัจฉริยะ
แต่เรากำลังทำสิ่งเหล่านี้อยู่ ฉันกำลังทำแบบฝึกหัดเหล่านี้สำหรับการติดตามการเคลื่อนไหวของดวงตาและการติดตามการเคลื่อนไหวของมือด้วย ดังนั้นจะมีอะไรอีกมากมายตามมา
และในภาพรวม สิ่งที่ผมอยากให้คุณจดจำจากส่วนของผมคืออะไร
ดังนั้น ไม่ว่าคุณจะใช้แทร็กแพดกับโทรศัพท์ แว่นตา หรืออินพุตอื่นๆ เราก็คำนึงถึงเรื่องนี้และพยายามทำงานล่วงหน้า
ดังนั้น หากคุณใช้ตัวตรวจจับท่าทางสัมผัสของ Foundation เหล่านี้ ก็จะใช้งานได้ทันที
นั่นคือข้อแรก
ข้อ 2 Compose เป็นชุดเครื่องมือ UI หลัก และเราจะยังคงสำรวจและรองรับอินพุตประเภทใหม่ๆ ทั้งในแพลตฟอร์มและในชุดเครื่องมือ ซึ่งคุณจะเห็นว่าฉันทำอะไรที่นี่
และแน่นอนว่าสำหรับการทดสอบ API เราต้องการรักษาอินเทอร์เฟซและรูปแบบที่คุ้นเคยไว้เพื่อให้คุณย้ายข้อมูลและทดสอบประเภทใหม่เหล่านี้ได้ง่ายที่สุด
ขอบคุณ หวังว่าข้อมูลนี้จะช่วยคุณได้
onNodeWithContentDescription("Photo")
.performTrackpadInput {
click(center)
pan(Offset(0f, 100f))
scale(0.9f)
}InputDevice.ViewBehavior
.getPrimaryDirectionalMotionAxis()// Glimmer Library
Box(
modifier =
Modifier.fillMaxSize()
.onIndirectPointerGesture(
enabled = true,
onSwipeForward = { /* onSwipeForward */ },
onSwipeBackward = { /* onSwipeBackward */ },
onClick = { /* onClick */ },
)
.focusTarget()
) {
// App()@Test
clickTest {
rule.onNodeWithTag(defaultTag)
.performTouchInput
{ click(center) }
}@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput (
IndirectPointerEventPrimaryDirectionalMotionAxis.X,
inputDeviceSize,
)
{ click(center) }
}@Test
clickTest {
rule.onNodeWithTag(defaultTag)
// .performTouchInput
.performIndirectPointerInput
{ click(center) }
}