Animate seekbar progress

2019-04-20 10:29发布

问题:

I have a screen with 4 seek bars ( As shown in the image below) . If the user moves B,C or D I calculate the average of the three and setProgress of A to the average. That was the easy part . What I would like to do is animate the progress bar A such that it does not jump in one shot (for eg from 25-75 ).

What are the recommended ways to animate A? I got a simple animation up but I am calling a TimerTask every 50ms to increment or decrement A by a unit value till I reach the required position. But its not very efficient.

Note: I have a custom Seekbar object using which I have created seekBar's A,B,C & D. Sorry I cant really share the code but will be happy to clarify anything.

回答1:

I guess its too late. But I found a way to achieve this using ValueAnimator.

ValueAnimator anim = ValueAnimator.ofInt(0, seekBar.getMax());
anim.setDuration(1000);
anim.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
    int animProgress = (Integer) animation.getAnimatedValue();
    seekBar.setProgress(animProgress);
    }
});
anim.start();


回答2:

This works on any Android version, without using any animations.

private void animateSeek(final SeekBar mSeek, final int toVal) {
    new Thread(new Runnable() {
        @Override
        public void run() {

            while (true) {
                if (mSeek.getProgress() == toVal) {
                    break;
                }
                int mProgress = mSeek.getProgress();
                if (mProgress < toVal) {
                    mProgress++;

                } else if (mProgress > toVal) {
                    mProgress--;
                }

                mSeek.setProgress(mProgress);

                try {
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }).start();
}


回答3:

I have done it using ObjectAnimator.

private void animateProgression(int progress) {
    final ObjectAnimator animation = ObjectAnimator.ofInt(mySeekBar, "progress", 0, progress);
    animation.setDuration(3000);
    animation.setInterpolator(new DecelerateInterpolator());
    animation.start();
    mySeekBar.clearAnimation();
}


回答4:

If you are using Honeycomb then you can use ViewPropertyAnimator http://android-developers.blogspot.com/2011/05/introducing-viewpropertyanimator.html

The animation before 3.0 is quite limited but as an alternative to your method you could use an animation listener:

anim.setAnimationListener(new AnimationListener() {
  public void onAnimationStart(Animation anim) {
     //moveseekbar
  }
  public void onAnimationRepeat(Animation anim) {}
  public void onAnimationEnd(Animation anim) {
     //call animation again if movement not complete
  }
});   

Don't forget to call setFillAfter(boolean fillAfter) because the animation <3.0 doesn't actually move the view. It just gives the illusion that the view has moved. Important distinction if you still want the seekbar to continue to receive touches.



回答5:

I reduced the number of iterations by iterating the timer task over an exponential function instead of unit increments. Still hoping for better answers :-)



回答6:

I needed code that was just like what @sidhanshu_udawat had done. That was a great base to start from. Big win because it runs on its own thread. Thanks for that example.

However, when I took that code and tried it there was an issue that it would increment up and then stop.

I altered the code (pasted below) and now if you send in your seekbar with code like the following you will see that the seekbar animates up and down the scale.

isRunning - Control From Your Activity

Also, I needed to stop the animation when someone clicked a button so I added the boolean isRunning as a member on my Activity. Now when they click the button, I set isRunnig to false and the SeekBar stops.

Set up your SeekBar like the following and then call the method:

animSeekBar.incrementProgressBy(1);
  animSeekBar.setMax(100);
  animateSeek(animSeekBar,100);

private void animateSeek(final SeekBar mSeek, final int toVal) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                boolean isIncrementing = true;
                int mProgress = 0;
                isRunning = true;

                while (isRunning) {
                    if (isIncrementing){
                        mProgress++;
                    }
                    else{
                        mProgress--;
                    }
                    mSeek.setProgress(mProgress);
                    if (mProgress >= toVal) {
                        isIncrementing = false;

                    } else if (mProgress <= 0) {
                        isIncrementing = true;
                    }
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }