폴더블용 디자인

ConstraintLayout 2.1 버전에는 SharedValues, ReactiveGuideMotionLayout의 향상된 애니메이션 지원 등 폴더블 기기를 관리하는 데 도움이 되는 여러 기능이 추가되었습니다.

공유 값

ConstraintLayout에 런타임 값을 삽입하는 새로운 메커니즘을 추가했습니다. 이는 ConstraintLayout의 모든 인스턴스가 값에 액세스할 수 있으므로 시스템 전체 값에 사용하기 위한 것입니다.

폴더블 기기의 컨텍스트에서는 이 메커니즘을 사용하여 런타임에 접힘 위치를 삽입할 수 있습니다.

Kotlin

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)

Java

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);

맞춤 도우미에서는 모든 변경사항에 관한 리스너를 추가하여 공유된 값에 액세스할 수 있습니다.

Kotlin

val sharedValues: SharedValues = ConstraintLayout.getSharedValues()
sharedValues.addListener(mAttributeId, this)

Java

SharedValues sharedValues = ConstraintLayout.getSharedValues();
sharedValues.addListener(mAttributeId, this);

FoldableExperimentals 예에서 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()는 값을 첫 번째 매개변수로 나타내고 두 번째 매개변수로 삽입할 값을 나타내는 ID를 사용합니다.

ReactiveGuide

코드를 작성하지 않고도 레이아웃에서 SharedValue를 활용하는 한 가지 방법은 ReactiveGuide 도우미를 사용하는 것입니다. 이렇게 하면 링크된 SharedValue에 따라 가로 또는 세로 안내선이 배치됩니다.

    <androidx.constraintlayout.widget.ReactiveGuide
        android:id="@+id/fold"
        app:reactiveGuide_valueId="@id/fold"
        android:orientation="horizontal" />

그런 다음 일반 가이드라인과 마찬가지로 사용할 수 있습니다.

MotionLayout(폴더블용)

2.1의 MotionLayout에는 상태를 모핑하는 데 도움이 되는 몇 가지 기능이 추가되었습니다. 이 기능은 일반적으로 가능한 여러 레이아웃 간에 애니메이션을 처리해야 하므로 폴더블에 특히 유용한 기능입니다.

폴더블에 사용할 수 있는 접근 방식에는 두 가지가 있습니다.

  • 런타임 시 현재 레이아웃 (ConstraintSet)을 업데이트하여 접힘 부분을 표시하거나 숨깁니다.
  • 지원하려는 폴더블 상태 (closed, folded, fully open)마다 별도의 ConstraintSet를 사용합니다.

ConstraintSet에 애니메이션 적용

MotionLayoutupdateStateAnimate() 함수가 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를 즉시 업데이트할 수 있습니다.

MotionLayoutReactiveGuide

ReactiveGuideMotionLayout 내에서 사용할 때 유용한 두 속성도 지원합니다.

  • app:reactiveGuide_animateChange="true|false"

  • app:reactiveGuide_applyToAllConstraintSets="true|false"

첫 번째 요소는 현재 ConstraintSet를 수정하고 변경사항에 자동으로 애니메이션을 적용합니다. 두 번째는 ReactiveGuide 위치의 새 값을 MotionLayout의 모든 ConstraintSet에 적용합니다. 폴더블의 일반적인 접근 방식은 접힘 위치를 나타내는 ReactiveGuide를 사용하여 ReactiveGuide을 기준으로 레이아웃 요소를 설정하는 것입니다.

여러 ConstraintSet를 사용하여 폴더블 상태 표현

현재 MotionLayout 상태를 업데이트하는 대신 폴더블을 지원하도록 UI를 설계하는 또 다른 방법은 특정 상태 (closed, folded, fully open)를 별도로 만드는 것입니다.

이 시나리오에서도 ReactiveGuide를 사용하여 접힘을 표시할 수 있지만, 각 상태가 다른 상태로 전환되는 방식을 (현재 ConstraintSet를 업데이트할 때의 자동 애니메이션에 비해) 훨씬 더 세밀하게 제어할 수 있습니다.

이 접근 방식을 사용하면 DeviceState 리스너에서 MotionLayout.transitionToState(stateId) 메서드를 통해 MotionLayout가 특정 상태로 전환되도록 간단히 지시할 수 있습니다.