Как анимировать линию внутри представления

Я изо всех сил пытаюсь понять, почему не происходит анимация от верхней части View1 до нижней части View1. При анимации он начинает анимироваться снизу, и я не знаю, почему.

Это мой макет.

....
    <View
        android:id="@+id/view_reader"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@drawable/ic_view_finder"
        app:layout_constraintBottom_toBottomOf="@+id/surfaceView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/scannerBar"
        android:layout_width="280dp"
        android:layout_height="2dp"
        android:background="@color/colorAccent"
        app:layout_constraintBottom_toBottomOf="@+id/view_reader"
        app:layout_constraintEnd_toEndOf="@+id/view_reader"
        app:layout_constraintStart_toStartOf="@+id/view_reader"
        app:layout_constraintTop_toTopOf="@+id/view_reader"
        app:layout_constraintVertical_bias="0.0" />
...

Итак, я хочу, чтобы этот scannerBar начинал анимацию с верхней части view_reader и начинал снова, когда он доходит до нижней части view_reader.

И я сделал свою анимацию следующим образом:

val vto: ViewTreeObserver = binding.scannerBar.viewTreeObserver
        val listener = ViewTreeObserver.OnGlobalLayoutListener {

            val destinationScanView = (binding.viewReader.y +
                    binding.viewReader.height)
            ObjectAnimator.ofFloat(
                binding.scannerBar, "translationY",
                binding.viewReader.y,
                destinationScanView
            ).apply {
                repeatMode = ValueAnimator.REVERSE
                repeatCount = ValueAnimator.INFINITE
                interpolator = AccelerateDecelerateInterpolator()
                duration = 3000
            }.start()

        }
        vto.addOnGlobalLayoutListener(listener)

Что мне не хватает? Есть ли другой способ анимировать вид проще, чем этот?

РЕДАКТИРОВАТЬ

Простой вопрос: как анимировать с помощью translationY scanBar (View) верхнюю часть view_reader (View) до нижней части view_reader (View)?

С MotionLayout проще?


person StuartDTO    schedule 31.10.2020    source источник
comment
Пожалуйста, опишите вашу проблему более конкретно с большим количеством кода и xml. Я не уверен, в чем ваша проблема.   -  person Adhikarimayum Krishanta    schedule 31.10.2020
comment
Я просто хочу анимировать представление scanBanner сверху view_reader до верха view_reader.   -  person StuartDTO    schedule 31.10.2020
comment
почему бы вам не использовать Path() val path = Path().apply { arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true) } val pathInterpolator = PathInterpolator(path)   -  person Akash kumar    schedule 31.10.2020
comment
Не могли бы вы привести пример, пожалуйста? Я не знаком с Path, и как я могу назначить его своему представлению?   -  person StuartDTO    schedule 31.10.2020


Ответы (1)


Простая анимация через translationY:

view.setTranslationY(0);
view.animate().translationY(200).setDuration(500).start();

Проблема в том, что вам нужно знать, сколько переводов вы должны использовать. На разных устройствах вы получите разные результаты.

Лучше:

Да, это будет более интуитивно понятно с макетом движения, так как вам просто нужно настроить свои ограничения и не нужно беспокоиться о каком-либо относительном переводе.

<ConstraintSet android:id="@+id/start">
    <Constraint android:id="@+id/scannerBar"
        android:layout_width="280dp"
        android:layout_height="2dp"
        android:background="@color/colorAccent"
        app:layout_constraintEnd_toEndOf="@+id/view_reader"
        app:layout_constraintStart_toStartOf="@+id/view_reader"
        app:layout_constraintTop_toTopOf="@+id/view_reader"/>
    <Constraint android:id="@+id/view_reader"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@drawable/ic_view_finder"
        app:layout_constraintBottom_toBottomOf="@+id/surfaceView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint android:id="@+id/scannerBar"
        android:layout_width="280dp"
        android:layout_height="2dp"
        android:background="@color/colorAccent"
        app:layout_constraintBottom_toBottomOf="@+id/view_reader"
        app:layout_constraintEnd_toEndOf="@+id/view_reader"
        app:layout_constraintStart_toStartOf="@+id/view_reader"/>
    <Constraint android:id="@+id/view_reader"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@drawable/ic_view_finder"
        app:layout_constraintBottom_toBottomOf="@+id/surfaceView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>

<Transition
    android:id="@+id/transition"
    app:constraintSetEnd="@id/end"
    app:constraintSetStart="@+id/start"
    app:autoTransition="none"
    app:duration="1000"/>

С этим scene1.xml он будет двигаться сверху вниз! Поскольку это ограничение сверху в начале, а затем ограничение снизу в конце.

Как это настроить:

В вашем файле макета сделайте motionLayout родителем представления, которое вы хотите анимировать!

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/motion_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/scene1"
    tools:context=".ui.YourFragment">

    <View
        android:id="@+id/view_reader"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@drawable/ic_view_finder"
        app:layout_constraintBottom_toBottomOf="@+id/surfaceView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/scannerBar"
        android:layout_width="280dp"
        android:layout_height="2dp"
        android:background="@color/colorAccent"
        app:layout_constraintBottom_toBottomOf="@+id/view_reader"
        app:layout_constraintEnd_toEndOf="@+id/view_reader"
        app:layout_constraintStart_toStartOf="@+id/view_reader"
        app:layout_constraintTop_toTopOf="@+id/view_reader"
        app:layout_constraintVertical_bias="0.0" />

</androidx.constraintlayout.motion.widget.MotionLayout>

Для макета движения требуется параметр app:layoutDescription="@xml/scene1". Здесь загружается файл scene1.xml (расположенный в res/xml/scene1.xml). Когда вы обновляете свой макет, AndroidStudio предложит вам создать файл сцены и сделает это автоматически. Затем вам просто нужно заполнить его.

Как запустить анимацию:

В вашем фрагменте вы можете позвонить

    MotionLayout mMotionLayout = findViewById(R.id.motion_layout);
    mMotionLayout.setTransition(R.id.transition);
    mMotionLayout.transitionToEnd();

Подробнее см. по этой ссылке:
https://developer.android.com/training/constraint-layout/motionlayout

person Tobi    schedule 31.10.2020
comment
Как я должен реализовать это? Не могли бы вы объяснить, куда я должен вставить это? А что такое scene.xml? - person StuartDTO; 01.11.2020