Solution to Animation Challenge

This is the code for the challenge solution I summaried and selected from previous posts

SunsetFragment.java

import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;

public class SunsetFragment extends Fragment {

private boolean mSunset;
private View mSceneView;
private View mSunView;
private View mSkyView;
private View mReflectionView;
private int  mBlueSkyColor;
private int  mSunsetSkyColor;
private int  mNightSkyColor;
private int mHotSunColor;
private int mColdSunColor;
private int   mSunsetSkyColorCurrent;
private int   mNightSkyColorCurrent;
private float mSunYCurrent;
private float mReflectionYCurrent;
private AnimatorSet mSunriseAnimatorSet;
private AnimatorSet mSunsetAnimatorSet;
private String TAG ="Sunset";

public static final int DURATION = 3000;


public static SunsetFragment newInstance(){
    return  new SunsetFragment();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
    View view =inflater.inflate(R.layout.fragment_sunset,container,false);

    mSceneView = view;
    mSunView   = view.findViewById(R.id.sun);
    mReflectionView = view.findViewById(R.id.reflection);
    mSkyView   = view.findViewById(R.id.sky);
    Resources resources = getResources();
    mBlueSkyColor  = resources.getColor(R.color.blue_sky  );
    mSunsetSkyColor= resources.getColor(R.color.sunset_sky);
    mNightSkyColor = resources.getColor(R.color.night_sky );
    mHotSunColor = ContextCompat.getColor(getActivity(), R.color.heat_sun);
    mColdSunColor = ContextCompat.getColor(getActivity(), R.color.cold_sun);
    mSunsetSkyColorCurrent = mBlueSkyColor;
    mNightSkyColorCurrent  = mSunsetSkyColor;

    mSunset = true;


    mSceneView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

          if (mSunset) {
          startSunsetAnimation();
              if (mSunriseAnimatorSet != null) {
                  mSunriseAnimatorSet.end();
                  mSunriseAnimatorSet = null;
              }
          } else {
          startSunriseAnimation();
              if (mSunsetAnimatorSet != null) {
                  mSunsetAnimatorSet.end();
                  mSunsetAnimatorSet = null;
              }
          }

          mSunset = !mSunset;
          startSunHeatAnimation();
          }
    });

    ViewTreeObserver observer = view.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mSunYCurrent           = mSunView.getTop();
            mReflectionYCurrent        = mReflectionView.getTop();
        }
    });

    return  view;
}

private void startSunsetAnimation(){

    long duration = (long) (DURATION / (mSkyView.getHeight() - mSunView.getTop()) * (mSkyView.getHeight() - mSunYCurrent));

    ObjectAnimator sunHeightAnimator = ObjectAnimator.ofFloat(mSunView, "y",  mSunYCurrent, mSkyView.getHeight())
            .setDuration(duration);

    sunHeightAnimator.setInterpolator(new AccelerateInterpolator());

    sunHeightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mSunYCurrent = (float) animation.getAnimatedValue();

        }
    });


    ObjectAnimator reflectionHeightAnimator = ObjectAnimator.ofFloat(mReflectionView, "y", mReflectionYCurrent, -mReflectionView.getHeight())
            .setDuration(duration);
    reflectionHeightAnimator.setInterpolator(new AccelerateInterpolator());
    reflectionHeightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mReflectionYCurrent = (float) animation.getAnimatedValue();
        }
    });


    ObjectAnimator sunsetSkyAnimator = ObjectAnimator.ofObject(mSkyView, "backgroundColor",  new ArgbEvaluator(), mSunsetSkyColorCurrent, mSunsetSkyColor)
            .setDuration(duration);
    sunsetSkyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mSunsetSkyColorCurrent = (int) animation.getAnimatedValue();

        }
    });


    ObjectAnimator nightSkyAnimator = ObjectAnimator.ofObject(mSkyView, "backgroundColor",
            new ArgbEvaluator(), mNightSkyColorCurrent, mNightSkyColor)
            .setDuration(DURATION);

    nightSkyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mNightSkyColorCurrent = (int) animation.getAnimatedValue();
        }
    });

    mSunsetAnimatorSet = new AnimatorSet();
    mSunsetAnimatorSet
            .play(sunHeightAnimator)
            .with(reflectionHeightAnimator)
            .with(sunsetSkyAnimator)
            .before(nightSkyAnimator);

    mSunsetAnimatorSet.start();

}

private void startSunHeatAnimation() {
    ObjectAnimator sunRayAnimator = ObjectAnimator.ofFloat(mSunView, "rotation",0,23)
                  .setDuration(500);
    sunRayAnimator.setRepeatMode(ObjectAnimator.REVERSE);
    sunRayAnimator.setRepeatCount(ObjectAnimator.INFINITE);


    ObjectAnimator sunHeatAnimator = ObjectAnimator.ofInt(mSunView,"tint",mHotSunColor, mColdSunColor )
                  .setDuration(500);
    sunHeatAnimator.setEvaluator(new ArgbEvaluator());
    sunHeatAnimator.setRepeatMode(ObjectAnimator.REVERSE);
    sunHeatAnimator.setRepeatCount(ObjectAnimator.INFINITE);
    AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.play(sunRayAnimator).with(sunHeatAnimator);
    animatorSet.start();
    }

private void startSunriseAnimation(){

    long duration = (long) (DURATION / (mSkyView.getHeight() - mSunView.getTop()) * (mSunYCurrent- mSunView.getTop()));
    long nightDuration = (long)(DURATION*((double)(mSunsetSkyColor-mNightSkyColorCurrent)/(double)(mSunsetSkyColor-mNightSkyColor)));

    ObjectAnimator sunHeightAnimator = ObjectAnimator.ofFloat(mSunView, "y",  mSunYCurrent, mSunView.getTop())
            .setDuration(duration);

    sunHeightAnimator.setInterpolator(new DecelerateInterpolator());

    sunHeightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mSunYCurrent = (float) animation.getAnimatedValue();
        }
    });


    ObjectAnimator reflectionHeightAnimator = ObjectAnimator.ofFloat(mReflectionView, "y", mReflectionYCurrent, mReflectionView.getTop())
            .setDuration(duration);
    reflectionHeightAnimator.setInterpolator(new DecelerateInterpolator());
    reflectionHeightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mReflectionYCurrent = (float) animation.getAnimatedValue();
        }
    });


    ObjectAnimator daySkyAnimator = ObjectAnimator.ofObject(mSkyView, "backgroundColor",  new ArgbEvaluator(), mSunsetSkyColorCurrent, mBlueSkyColor)
            .setDuration(duration);
    daySkyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mSunsetSkyColorCurrent = (int) animation.getAnimatedValue();
        }
    });


    ObjectAnimator nightSkyAnimator = ObjectAnimator.ofObject(mSkyView, "backgroundColor", new ArgbEvaluator(), mNightSkyColorCurrent, mSunsetSkyColor)
            .setDuration(nightDuration);

    nightSkyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mNightSkyColorCurrent = (int) animation.getAnimatedValue();
        }
    });

    mSunriseAnimatorSet = new AnimatorSet();
    mSunriseAnimatorSet
            .play(sunHeightAnimator)
            .with(reflectionHeightAnimator)
            .with(daySkyAnimator)
            .after(nightSkyAnimator);

    mSunriseAnimatorSet.start();
}
}

fragment_sunset.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/sky"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.61"
        android:background="@color/blue_sky">

        <ImageView
            android:id="@+id/sun"
            android:layout_width="180dp"
            android:layout_height="180dp"
            android:layout_gravity="center"
            android:src="@drawable/ic_wb_sunny"/>
    </FrameLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.39"
        android:background="@color/sea">

    <ImageView
        android:id="@+id/reflection"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:src="@drawable/sun"/>


    </FrameLayout>
</LinearLayout>

ic_wb_sunny.xml

<vector
    android:height="180dp"
    android:tint="#fcfcb7"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0"
    android:width="180dp"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FF000000"
        android:pathData="M6.76,4.84l-1.8,-1.79 -1.41,1.41 1.79,1.79 1.42,-1.41zM4,10.5L1,10.5v2h3v-2zM13,0.55h-2L11,3.5h2L13,0.55zM20.45,4.46l-1.41,-1.41 -1.79,1.79 1.41,1.41 1.79,-1.79zM17.24,18.16l1.79,1.8 1.41,-1.41 -1.8,-1.79 -1.4,1.4zM20,10.5v2h3v-2h-3zM12,5.5c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6zM11,22.45h2L13,19.5h-2v2.95zM3.55,18.54l1.41,1.41 1.79,-1.8 -1.41,-1.41 -1.79,1.8z"/>

</vector>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <color name="bright_sun"> #fcfcb7 </color>
    <color name="blue_sky"  > #1e7ac7 </color>
    <color name="sunset_sky"> #ec8100 </color>
    <color name="night_sky" > #05192e </color>
    <color name="sea"       > #224869 </color>

    <color name="heat_sun">#FFfcfcb7</color>
    <color name="cold_sun">#FFff0000</color>

</resources>

sun.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android = "http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@color/bright_sun"/>
</shape>

Everything else worked fine expect I counldn’t find the way to altering the color of the sun and since I introduced ic_wb_sunny the method will be different than the one give by the book (if there is a method at all).I appreciate if anyone can help me with that.

1 Like

Hello @shadow_wxh,

Thanks for the post.

How did you come up with the vector for the ic_wb_sunny.xml?