1

I am trying to create a small animation which changes smoothly the background color. My problem is that it only shows the last value (100, that means it directly goes to a red background). I don't know why my created while-loop doesn't actualize every value (so that it would show a smoothly color animation)

New code (which almost works, but Idk how to stop the animation)

imageButton_info.setOnClickListener(new View.OnClickListener(){

        @Override
        public void onClick(View v){


                final Handler handler = new Handler();

                Runnable ChangeBackgroundRunnable = new Runnable() {

                    @Override
                    public void run() {
                        number++;
                        float[] hsvColor = {0, 1, 1};
                        hsvColor[0] = 360f * number / 100;
                        color.setBackgroundColor(Color.HSVToColor(hsvColor));

                        handler.postDelayed(this, 80);
                        if (number >=100)
                            number = 1;

                    }
                };
                number = 0;
                handler.removeCallbacks(ChangeBackgroundRunnable);
                handler.postDelayed(ChangeBackgroundRunnable, 0);

        }
    });

Code:

 public void onClick(View v){

            try {
                while (number<=100) {

                        number=number+1;

                        float[] hsvColor = {0, 1, 1};
                        hsvColor[0] = 360f * number / 100;
                        color.setBackgroundColor(Color.HSVToColor(hsvColor));

                        Thread.sleep(10);
                }
            }catch(Exception e){

                //New exception
                Log.e("Camera Error!",e.getMessage());

            }

Thank you for your answer in advance...

Nick88
  • 15
  • 7

4 Answers4

1

When you change something in the UI, it doesn't happen immediately. Instead, it posts a message to the Looper on the UI thread. When control returns to the looper (when you're done with whatever function the framework called), it will process all the messages on the Looper, until it eventually processes the redraw request. Then it will draw. So if you're looping in onClick, you will not get any updates to the screen. If you want something to happen in 10ms, post a delayed message to a Handler and update the UI in that thread.

Side note: NEVER EVER sleep on the UI thread. The reason is that no input or draw commands can be processed if you're not returning control to the Looper. So your app becomes unresponsive. If you do it long enough, it can even cause the framework to kill your app for being unresponsive.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
1

A better way to do this would be to use an Android animation. I stole the code for this from here

int colorFrom = getResources().getColor(R.color.red);
int colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(250); // milliseconds
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animator) {
        textView.setBackgroundColor((int) animator.getAnimatedValue());
    }

});
colorAnimation.start();
Community
  • 1
  • 1
Jesse Buss
  • 833
  • 6
  • 13
0

Wrapped the answers posted by @gabe-sechan and @jesse-buss

ValueAnimator support from devices SDK above HONEYCOMB. So below that SDK level we'll use @gabe-sechan suggestion. Check the below code.

    private void executeBackgroundChange() {
        // Handler and runnable to run the animation in devices sdk below honeycomb.
        mHandler = new Handler();
        mChangeBackgroundRunnable = new Runnable() {
            @Override
            public void run() {
                number++;

                float[] hsvColor = {0, 1, 1};
                hsvColor[0] = 360f * number / 100;
                mContainer.setBackgroundColor(Color.HSVToColor(hsvColor));

                mHandler.postDelayed(this, 500);
                if (number == 100)
                    number = 0;
            }
        };
        number = 0;
        mHandler.removeCallbacks(mChangeBackgroundRunnable);
        mHandler.postDelayed(mChangeBackgroundRunnable, 0);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void executeBackgroundChangeUsingValueAnimator() {
        colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), getResources().getColor(R.color.red), getResources().getColor(R.color.blue));
        colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(final ValueAnimator animator) {
                mContainer.setBackgroundColor((Integer) animator.getAnimatedValue());
            }
        });
        colorAnimation.setRepeatCount(ValueAnimator.INFINITE);
        colorAnimation.setDuration(10 * 1000);
        colorAnimation.start();
    }

Add the below method and to stop the animation on click of something call the below method.

    private void stopBackgroundChangeAnimation() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            if (colorAnimation != null && colorAnimation.isRunning())
                colorAnimation.end();
        } else {
            if (mHandler != null && mChangeBackgroundRunnable != null)
                mHandler.removeCallbacks(mChangeBackgroundRunnable);
        }
    }

Check the github project for reference.

Mahendran Sakkarai
  • 8,381
  • 6
  • 44
  • 66
  • Thanks for this answer, I have tried Gabe's and your suggestion and it worked almost perfect. The only problem I got now is that I don't know how to stop the animation (I am using a image Button). Do you know how I could stop it on click (I already tried to create a while-loop but animation didn't worked with it)? – Nick88 Feb 15 '17 at 03:31
  • I tried it unfortunately it didn't work but thanks for your support. – Nick88 Feb 15 '17 at 23:50
0

Try to use runOnUiThread

public void onCreate(Bundle savedInstanceState) {
        res = getResources();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.xyz);//**Works**/
        handler.postDelayed(runnable, 10);       
    }

    private Runnable runnable = new Runnable() {
        public void run() {  
            runOnUiThread(new Runnable() { 
                public void run() 
                { 
                    try {
                    while (number<=100) {
                            number=number+1;
                            float[] hsvColor = {0, 1, 1};
                            hsvColor[0] = 360f * number / 100;
                            color.setBackgroundColor(Color.HSVToColor(hsvColor));
                    }
                }catch(Exception e){
                    //New exception
                }
                } 
            }); 
        }
    }
Umer
  • 1,566
  • 2
  • 20
  • 31