I am using an ObjectAnimator to make a long text on a TextView to be scrolled inside a HorizontalScrollView. The scroll animation is working nicely, the text is being scrolled correctly, but I am having trouble to make the animation stop for a few moments before it restarts.
I am using the following classes to make such animations:
class ObjectScroller {
ObjectAnimator animator;
TextView scrollText;
long duration = 7500;
long delay = 2500;
public ObjectScroller(TextView scroll, int itemWidth, int viewWidth) {
this.scrollText = scroll;
animator = ObjectAnimator.ofFloat(scrollText, "translationX", viewWidth-(itemWidth + 50));
animator.setStartDelay(delay);
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(duration);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
}
public void startObjectScroll() {
animator.addListener(new DelayAnimation(delay));
animator.start();
}
}
class DelayAnimation implements Animator.AnimatorListener {
private long delayMillis;
public DelayAnimation(long delayMillis) {
this.delayMillis = delayMillis;
}
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
animation.pause();
new Handler().postDelayed(animation::resume, delayMillis);
}
}
Those classes are utilized in a RecyclerView.Adapter
(cause those scrolling texts are located inside the items of a RecyclerView) and are utilized as follows:
@Override
public void onBindViewHolder(@NonNull ViewHolderInterface.MainListViewHolder holder, int position) {
\------------
\omitting code that does not relate to animations
\------------
this.beforeDraw(holder.textInfoOne, () -> {
Paint textPaint = holder.textInfoOne.getPaint();
String text = holder.textInfoOne.getText().toString();
int itemWidth = Math.round(textPaint.measureText(text));
int viewWidth = holder.scrollText.getWidth();
if (itemWidth > viewWidth) {
holder.obScroller = new ObjectScroller(holder.textInfoOne, itemWidth,viewWidth);
holder.obScroller.startObjectScroll();
}
});
}
public void beforeDraw(View view, Runnable runnable) {
ViewTreeObserver.OnPreDrawListener preDraw = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
runnable.run();
return true;
}
};
view.getViewTreeObserver().addOnPreDrawListener(preDraw);
}
where beforeDraw
is just a method created to allow me to find the views’ proper size on the screen to decide if the text should be scrolled or not.
Anyway, the problem I am facing is the fact that, when utilizing the onAnimationRepeat(Animator animation)
, the animation restarts, and just then it pauses for the time determined as delay to restart scrolling. This delay before resuming the animation is part of what I envisioned, but it isn’t everything that I want to achieve, since what I wanted is that the animation also paused after its completion but before its restart.
To be more clear, my desired outcome would be as follows:
Delay -> Start Animation -> Complete Scroll Animation -> Pause at the End -> Restart Animation with Delay -> ...
However, what I am getting so far would be like this:
Delay -> Start Animation -> Complete Scroll Animation -> **No Pause** -> Restart Animation with Delay -> ...
Is it possible to achieve such thing with ObjectAnimator? I changed from Animation to ObjectAnimator precisely because I wanted to pause the animation before restarting it.
Also, I would prefer to have a solution that uses the setRepeatCount(ValueAnimator.INFINITE)
option since I want to make sure it will never stop scrolling even if the user does forget his phone unlocked.
Thanks in advance for all the help!
2
Answers
I must thank both Rajan Kali and 5f3bde39-70a2-4df1-afa2-47f61b answers to being able to find a solution. It might not be the most elegant one and I am willing to look for even better ones, but this one worked for me:
You could use
AnimationUpdateListener
and control when to pause the animation at the end before repeating using