ในConstraintLayout
รุ่น 2.1 มีการเพิ่มฟีเจอร์หลายอย่างเพื่อช่วย
จัดการอุปกรณ์แบบพับได้ ซึ่งรวมถึง SharedValues
ReactiveGuide
และการรองรับภาพเคลื่อนไหวที่ดียิ่งขึ้นด้วย MotionLayout
ค่าที่ใช้ร่วมกัน
เราได้เพิ่มกลไกใหม่เพื่อแทรกค่ารันไทม์ใน ConstraintLayout
–
ใช้สำหรับค่าสำหรับทั้งระบบ ดังเช่น
ConstraintLayout
มีสิทธิ์เข้าถึงค่าดังกล่าว
ในบริบทของอุปกรณ์แบบพับได้ เราสามารถใช้กลไกนี้เพื่อแทรก ตำแหน่งของเส้นแบ่งหน้าขณะรันไทม์:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
ในผู้ช่วยที่กำหนดเอง คุณสามารถเข้าถึงค่าที่แชร์ได้โดยการเพิ่ม Listener สำหรับ การเปลี่ยนแปลงใดๆ:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
คุณสามารถดูตัวอย่าง Foldable Experiments
เพื่อดูว่าเราจับภาพตำแหน่งเส้นแบ่งหน้าโดยใช้
ไลบรารี Jetpack WindowManager และแทรก
ตำแหน่งลงใน ConstraintLayout
Kotlin
inner class StateContainer : Consumer<WindowLayoutInfo> { override fun accept(newLayoutInfo: WindowLayoutInfo) { // Add views that represent display features for (displayFeature in newLayoutInfo.displayFeatures) { val foldFeature = displayFeature as? FoldingFeature if (foldFeature != null) { if (foldFeature.isSeparating && foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL ) { // The foldable device is in tabletop mode val fold = foldPosition(motionLayout, foldFeature) ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold) } else { ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0); } } } } }
Java
class StateContainer implements Consumer<WindowLayoutInfo> { @Override public void accept(WindowLayoutInfo newLayoutInfo) { // Add views that represent display features for (DisplayFeature displayFeature : newLayoutInfo.getDisplayFeatures()) { if (displayFeature instanceof FoldingFeature) { FoldingFeature foldFeature = (FoldingFeature)displayFeature; if (foldFeature.isSeparating() && foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL ) { // The foldable device is in tabletop mode int fold = foldPosition(motionLayout, foldFeature); ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold); } else { ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0); } } } } }
fireNewValue()
จะใช้รหัสที่แสดงถึงค่านั้นเป็นพารามิเตอร์แรก และ
ค่าที่จะแทรกเป็นพารามิเตอร์ที่ 2
ReactiveGuide
วิธีหนึ่งในการใช้ประโยชน์จาก SharedValue
ในเลย์เอาต์โดยไม่ต้อง
เขียนโค้ด คือการใช้ ReactiveGuide
ผู้ช่วยอัตโนมัติ ซึ่งจะวางหลักเกณฑ์เป็นแนวนอนหรือแนวตั้งตาม
ลิงก์เมื่อ SharedValue
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
ซึ่งสามารถใช้ในลักษณะเดียวกับการใช้หลักเกณฑ์ปกติได้
MotionLayout
สำหรับอุปกรณ์แบบพับได้
เราได้เพิ่มฟีเจอร์หลายอย่างใน MotionLayout
ในเวอร์ชัน 2.1 ที่ช่วยในการปรับเปลี่ยนรูปแบบ
สถานะ – เป็นอุปกรณ์ที่มีประโยชน์อย่างยิ่งสำหรับอุปกรณ์แบบพับได้ ตามที่เรามัก
ต้องจัดการกับภาพเคลื่อนไหว
ระหว่างเลย์เอาต์ที่เป็นไปได้ต่างๆ
อุปกรณ์แบบพับได้มี 2 วิธีให้เลือกดังนี้
- เมื่อรันไทม์ ให้อัปเดตเลย์เอาต์ปัจจุบัน (
ConstraintSet
) เพื่อแสดงหรือซ่อน เส้นแบ่งหน้า - ใช้
ConstraintSet
แยกกันสำหรับแต่ละอุปกรณ์แบบพับได้ที่ต้องการ การสนับสนุน (closed
,folded
หรือfully open
)
กำลังทำให้ ConstraintSet
เคลื่อนไหว
เพิ่มฟังก์ชัน updateStateAnimate()
ใน MotionLayout
แล้วในเวอร์ชัน 2.1
รุ่น:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
ฟังก์ชันนี้จะทำให้การเปลี่ยนแปลงเคลื่อนไหวโดยอัตโนมัติเมื่ออัปเดต
ConstraintSet
แทนที่จะอัปเดตทันที (ซึ่งทำได้กับ
updateState(stateId, constraintset)
) ซึ่งจะช่วยให้คุณอัปเดต UI ได้ใน
ขึ้นอยู่กับการเปลี่ยนแปลง เช่น สถานะของคุณเป็นแบบพับได้
ReactiveGuide
ใน MotionLayout
ReactiveGuide
ยังรองรับแอตทริบิวต์ที่มีประโยชน์ 2 รายการเมื่อใช้ภายใน
MotionLayout
:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
รายการแรกจะแก้ไข ConstraintSet
ปัจจุบันและทำให้การเปลี่ยนแปลงเคลื่อนไหว
โดยอัตโนมัติ ตัวระบุที่ 2 จะใช้ค่าใหม่ของ ReactiveGuide
ตำแหน่งเป็น ConstraintSet
ทั้งหมดใน MotionLayout
แนวทางทั่วไปสำหรับ
อุปกรณ์แบบพับได้จะใช้ ReactiveGuide
ที่แทนตำแหน่งเส้นแบ่ง
ตั้งค่าองค์ประกอบเลย์เอาต์ให้สัมพันธ์กับ ReactiveGuide
การใช้ ConstraintSet
หลายชิ้นเพื่อแสดงสถานะอุปกรณ์พับได้
อีกวิธีหนึ่งในการออกแบบสถาปัตยกรรม แทนที่จะอัปเดตสถานะ MotionLayout
ปัจจุบัน
UI เพื่อรองรับอุปกรณ์แบบพับได้คือการสร้างสถานะเฉพาะ (รวมถึง
closed
, folded
และ fully open
)
ในสถานการณ์นี้ คุณอาจยังคงต้องการใช้ ReactiveGuide
เพื่อแสดง
แต่คุณจะควบคุมได้มากขึ้นมาก (เมื่อเทียบกับ
ภาพเคลื่อนไหวเมื่ออัปเดต ConstraintSet
ปัจจุบัน) ว่าแต่ละสถานะจะ
เปลี่ยนไปเป็นอีกเครื่องหนึ่งได้
ด้วยวิธีการนี้ ใน Listener DeviceState
คุณเพียงแค่กำหนด
MotionLayout
เพื่อเปลี่ยนเป็นรัฐที่เจาะจงผ่าน
MotionLayout.transitionToState(stateId)