Сброс Motion Layout при навигации между действиями

Я использую макет движения в моей основной деятельности. Это работает пропеллерно. Однако, когда я перехожу к другим действиям и возвращаюсь к своей основной деятельности, иногда действие сбрасывается, и макет находится в своем начальном состоянии. Как мне этого избежать? Помимо этого у меня есть еще один вопрос о макете движения, который я задал здесь

6 ответов

Я добавил поле, конкретное логическое поле и использовал жизненный цикл для его обработки.

    private var hasMotionScrolled = false

    override fun onResume() {
        super.onResume()
        if (hasMotionScrolled) motionLayout.progress = MOTION_TRANSITION_COMPLETED
    }

    override fun onPause() {
        super.onPause()
        hasMotionScrolled = motionLayout.progress > MOTION_TRANSITION_INITIAL
    }


    companion object {
        private const val MOTION_TRANSITION_COMPLETED = 1F
        private const val MOTION_TRANSITION_INITIAL = 0F
    }

Итак, в моем случае макет движения выполняет анимацию, связанную с прокруткой. Если это не ваш случай, возможно, вы можете использовать непосредственноmotionLayout.progress. Моя проблема с использованиемprogress непосредственно было то, что промежуточные состояния делают другие элементы невидимыми при переходе назад, поэтому реализован логический флаг все или ничего.

Я не считаю это чистым решением, флаг - это всегда то, что означает, что что-то еще могло быть лучше, если вы найдете что-то официальное, дайте мне знать в комментариях.

Вы должны сохранить / восстановить прогресс вашего MotionLayout:

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putFloat("progress", motionLayout.progress)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        if (savedInstanceState != null)
            motionLayout.progress = savedInstanceState.getFloat("progress", 0f)
        ...
    }

Вот как я это делаю с

Создайте переменную экземпляра в своем классе:

      var motionProgress = 0f // 0f being initial state

На вашей onViewCreatedфункция, передайте текущее значение макету:

      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    binding.motionLayout.progress = motionProgress
}

Наконец, при выходе из Fragment, обновить значение motionProgressпо функции onPause:

      override fun onPause() {
    super.onPause()

    motionProgress = binding.motionLayout.progress
}

Вы можете добавить слушателя перехода к макету движения и сохранить флаг, когда переход завершен. После этого, когда действие воссоздается, вы можете прочитать этот флаг и использовать что-то вроде: motionLayout.setState(R.id.end, ConstraintSet.WRAP_CONTENT, ConstraintSet.WRAP_CONTENT) - где R.id.end является идентификатором из свойства constraintSetEnd.

class ExtMotionLayout : MotionLayout {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    override fun onSaveInstanceState(): Parcelable? {
        return SavedState(progress, super.onSaveInstanceState())
    }

    override fun onRestoreInstanceState(state: Parcelable?) {
        if (state is SavedState) {
            progress = state.progress
            super.onRestoreInstanceState(state.superState)
        } else super.onRestoreInstanceState(state)
    }

    class SavedState : BaseSavedState {
        val progress: Float

        constructor(progress: Float, source: Parcelable?) : super(source) {
            this.progress = progress
        }

        constructor(superState: Parcel) : super(superState) {
            progress = superState.readFloat()
        }

        override fun writeToParcel(out: Parcel, flags: Int) {
            super.writeToParcel(out, flags)
            out.writeFloat(progress)
        }
    }
}
      class CustomMotionLayout(context: Context, attrs: AttributeSet) : MotionLayout(context, attrs) {
    init {
        isSaveEnabled = true
    }

    override fun onSaveInstanceState(): Parcelable {
        return SavedState(progress, super.onSaveInstanceState())
    }

    override fun onRestoreInstanceState(state: Parcelable?) {
        if (state is SavedState) {
            progress = state.progress
            super.onRestoreInstanceState(state.superState)
        } else super.onRestoreInstanceState(state)
    }

    class SavedState(val progress: Float, source: Parcelable?) : BaseSavedState(source) {

        override fun writeToParcel(out: Parcel, flags: Int) {
            super.writeToParcel(out, flags)
            out.writeFloat(progress)
        }
    }
}

Использовать CustomMotionLayoutвместо MotionLayout по умолчанию Просто имейте в виду, чтобы предоставить идентификатор для вашего макета движения

Другие вопросы по тегам