0

I'm struggling trying to figure it out why is not animating from the top of the View1 to the bottom of the View1. When animating it start to animate from the bottom and I don't know why.

This is my layout.

....
    <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" />
...

So I want this scannerBar start animating from the top of the view_reader and start again when it arrives to the bottom of the view_reader.

And I did my animation as follows :

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)

What I'm missing? Is there any other way to animate a view easier than this?

EDIT

Simple question: How to animate with translationY scannerBar (View) from the top of view_reader(View) to bottom of view_reader(View)?

Is it easier with MotionLayout?

StuartDTO
  • 783
  • 7
  • 26
  • 72

1 Answers1

0

Simple animation via translationY:

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

Problem is that you need to know how much translationY you have to use. On different devices, you will get different results.

Better:

Yes, it will be more intuitive with a motionlayout, as you just need to adjust your constraints and don't need to worry about any relative translationY.

<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"/>

With this scene1.xml it will move from the top to the bottom! As it is constraint to the top on start and then constraint to the bottom in the end.

How to set this up:

In your layout file, make a motionLayout the parent of the view you want to animate!

<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>

The motionlayout requires the parameter app:layoutDescription="@xml/scene1". This is where the scene1.xml (located in res/xml/scene1.xml) is loaded. When you update your layout AndroidStudio will tell you to create the scene file and does it automatically. You then just need to fill it.

How to start the animation:

In your fragment you can call

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

See this link for more details:
https://developer.android.com/training/constraint-layout/motionlayout

Tobi
  • 858
  • 7
  • 15
  • How I'm supposed to implement this? Could you explain where I have to paste this? And what is a `scene.xml`? – StuartDTO Nov 01 '20 at 08:40