0

I am working on a android project where the user can scan a RFID tag. The tag expires after a certain amount of seconds to clear up the system before another tag comes in, basically to avoid processing the same tag twice by mistake. To visualise this timeout I want the background of the button where the tags ID is displayed to be animated. Basically I want the entire button to be filled with color when the tag has just been scanned and slowly scale down to the middle as time processes.

Diagram of what I am looking for

What I have found so far: I found this answer where they talk about the properties api. I could see this working with a gradient but unfortunately the documentation on gradients is sparce and it looks like it wouldnt be that easy to do that with.

I also thought that maybe you could achieve this by somehow layering another view of the same size below the button and scaling that. But honestly I think this would be quite difficult to do consistently, especially with resizing the view while the timer processes and configuration changes. Then again, I am not really that experienced with android and use linear and grid layouts for almost everything since they are the easiest to understand.

All I would really need is some way to essentially "scale" the background by a value (the ratio between total time and time left) towards the middle like I have demonstrated here. Or a way to essentially have a hard color gradient where the white portions of the gradient move towards the middle as the time processes.

Last solution I thought could maybe work is to have a animated vector drawable and manipulate the objectanimator associated with it to force it to play at the right speed. However, this solution is probably pretty messy, thought I haven't tried it (yet)

Does anyone have a clean solution to this problem?

Note: i am using java for this project. I did not include code snippets because I didn't think they were needed. If you need some snippets please simply ask and I will provide. My minSdkVersion is 25 since the target device for the job has android 7.1 and cannot be updated to a newer version.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
MoustacheSpy
  • 743
  • 1
  • 6
  • 27
  • I would just use a horizontal progress bar instead and a timer that updates its progress from 100 to 0 percent as time runs out. If you want to have the progress reset in the middle, use two progress bars side by side – Nikos Hidalgo Feb 14 '20 at 15:46
  • @NikosHidalgo Great idea. I will attempt this and report back. However, I am confused as to how it should work with 2 progress bars. I cannot span the text over 2 view elements :/ – MoustacheSpy Feb 14 '20 at 15:56
  • The "button" can be **any** clickable View. An ImageView could be the trick. Or even a LinearLayout with an ImageView which shrinks down. – Phantômaxx Feb 14 '20 at 16:06

1 Answers1

0

Here’s a sample layout with two progress bars and a textview over them:

    <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:progressBackgroundTint="@color/transparent"
        android:rotation="180"
        android:scaleY="4"
        app:layout_constraintBottom_toBottomOf="@id/textView2"
        app:layout_constraintEnd_toStartOf="@+id/progressBar2"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/textView2"
        tools:progress="100" />

    <ProgressBar
        android:id="@+id/progressBar2"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:progressBackgroundTint="@color/transparent"
        android:scaleY="4"
        app:layout_constraintBottom_toBottomOf="@id/textView2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/progressBar"
        app:layout_constraintTop_toTopOf="@id/textView2"
        tools:progress="100" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="24dp"
        android:text="TextView"
        android:textAlignment="center"
        android:textColor="@color/black"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

These are the results you get by setting the progress to 100, 50 and 1:

100:

enter image description here

50:

enter image description here

1:

enter image description here

If you add a custom drawable as your background you can make the progress bar fill the space accordingly and also make its colour red.

Note that the grey lines in the photos are from my design tab in Android Studio and aren't visible other than when debugging.

UPDATE: Here's the animation code that makes the progress bars reset from 100% to 0% in 5 seconds.

ProgressBar pb = findViewById(R.id.progressBar); ProgressBar pb2 = findViewById(R.id.progressBar2);

    ObjectAnimator animation = ObjectAnimator.ofInt(pb, "progress", 0, 100);
    animation.setDuration(5000);
    animation.setInterpolator(new DecelerateInterpolator());
    animation.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) { }

        @Override
        public void onAnimationEnd(Animator animator) {
            //do something when the countdown is complete
        }

        @Override
        public void onAnimationCancel(Animator animator) { }

        @Override
        public void onAnimationRepeat(Animator animator) { }
    });
    animation.start();

    AnimatorSet set = new AnimatorSet();
    set.playTogether(ObjectAnimator.ofInt(pb, "progress", 100, 0),
            ObjectAnimator.ofInt(pb2, "progress", 100, 0));
    set.setDuration(5000);
    set.start();
Nikos Hidalgo
  • 3,666
  • 9
  • 25
  • 39