Trong ConstraintLayout
Phiên bản 2.1, một số tính năng đã được thêm vào để giúp
quản lý thiết bị có thể gập lại, bao gồm SharedValues
,
ReactiveGuide
và tính năng hỗ trợ nâng cao cho ảnh động với MotionLayout
.
Giá trị chung
Chúng tôi đã thêm một cơ chế mới để chèn các giá trị thời gian chạy vào ConstraintLayout
–
mã này được sử dụng cho các giá trị trên toàn hệ thống, vì tất cả các phiên bản của
ConstraintLayout
có thể truy cập vào giá trị này.
Trong bối cảnh của thiết bị có thể gập lại, chúng ta có thể sử dụng cơ chế này để chèn vị trí của nếp gấp trong thời gian chạy:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
Trong một trình trợ giúp tuỳ chỉnh, bạn có thể truy cập vào các giá trị được chia sẻ bằng cách thêm trình nghe cho bất kỳ thay đổi nào:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Bạn có thể xem Ví dụ về Có thể gập lại
để xem cách chúng tôi nắm bắt vị trí của đường ranh giới phần hiển thị bằng cách sử dụng
Thư viện Jetpack WindowManager và chèn
vị trí vào 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()
lấy mã nhận dạng đại diện cho giá trị làm tham số đầu tiên và
giá trị cần chèn làm tham số thứ hai.
ReactiveGuide
Có một cách để tận dụng SharedValue
trong bố cục mà không cần phải
viết bất kỳ mã nào, tức là sử dụng ReactiveGuide
của chúng tôi. Việc này sẽ định vị nguyên tắc ngang hoặc dọc theo
liên kết SharedValue
.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Sau đó, bạn có thể sử dụng phương pháp này như cách áp dụng quy tắc thông thường.
MotionLayout
cho thiết bị có thể gập lại
Chúng tôi đã thêm một số tính năng trong MotionLayout
trong phiên bản 2.1 để giúp cải tiến
trạng thái – một tính năng đặc biệt hữu ích cho thiết bị có thể gập lại, như chúng ta thường thấy
phải xử lý ảnh động giữa các bố cục khác nhau có thể có.
Có 2 phương pháp dành cho thiết bị có thể gập lại:
- Trong thời gian chạy, hãy cập nhật bố cục hiện tại (
ConstraintSet
) để hiện hoặc ẩn màn hình đầu tiên. - Sử dụng một
ConstraintSet
riêng cho từng trạng thái gập mà bạn muốn support (closed
,folded
hoặcfully open
).
Tạo ảnh động cho ConstraintSet
Hàm updateStateAnimate()
trong MotionLayout
đã được thêm vào phiên bản 2.1
bản phát hành:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Hàm này sẽ tự động tạo ảnh động cho các thay đổi khi cập nhật một giá trị
ConstraintSet
thay vì thực hiện cập nhật ngay lập tức (bạn có thể làm điều này bằng
updateState(stateId, constraintset)
). Thao tác này cho phép bạn cập nhật giao diện người dùng trên
bay, tuỳ thuộc vào các thay đổi, chẳng hạn như bạn đang ở trạng thái nào của thiết bị có thể gập lại.
ReactiveGuide
bên trong một MotionLayout
ReactiveGuide
cũng hỗ trợ hai thuộc tính hữu ích khi được dùng bên trong một
MotionLayout
:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
Thao tác đầu tiên sẽ sửa đổi ConstraintSet
hiện tại và tạo ảnh động cho thay đổi đó
tự động. Hành động thứ hai sẽ áp dụng giá trị mới của ReactiveGuide
cho tất cả ConstraintSet
trong MotionLayout
. Một phương pháp tiếp cận điển hình cho
có thể gập lại sẽ sử dụng ReactiveGuide
đại diện cho vị trí gập,
khi thiết lập các phần tử bố cục tương ứng với ReactiveGuide
.
Sử dụng nhiều ConstraintSet
để biểu thị trạng thái có thể gập lại
Thay vì cập nhật trạng thái MotionLayout
hiện tại, hãy thiết kế một cách khác
giao diện người dùng hỗ trợ thiết bị có thể gập lại cần tạo các trạng thái riêng biệt (bao gồm
closed
, folded
và fully open
).
Trong trường hợp này, có thể bạn vẫn muốn sử dụng ReactiveGuide
để biểu thị
nhưng bạn sẽ có nhiều quyền kiểm soát hơn (so với
ảnh động khi cập nhật ConstraintSet
hiện tại) về cách mỗi trạng thái sẽ
sang một tên khác.
Với phương pháp này, trong trình nghe DeviceState
, bạn chỉ cần hướng dẫn
MotionLayout
để chuyển sang các tiểu bang cụ thể thông qua
MotionLayout.transitionToState(stateId)
.