Monday, October 26, 2015

android - How to create a gradient background animation

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity"
    >
    <ToggleButton
        android:id="@+id/toggle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:textOn="Stop"
        android:textOff="Play"
        android:background="#19fff4f4"
        />
</RelativeLayout>
MainActivity.java

package com.cfsuman.me.androidsnippets;

import android.graphics.Point;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.TransitionDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import android.os.Handler;
import android.widget.ToggleButton;


public class MainActivity extends AppCompatActivity {
    private Context mContext;
    private RelativeLayout mRL;

    private Handler mHandler;
    private Runnable mRunnable;
    private int mInterval = 5000;
    private Point mScreenSize;

    private TransitionDrawable drawable;;
    private GradientGenerator mGradientGenerator;
    private GradientDrawable mStartGradient;
    private GradientDrawable mEndGradient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Request for window action bar feature
        requestWindowFeature(Window.FEATURE_ACTION_BAR);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Hide the action bar
        getSupportActionBar().hide();

        // Get the application context
        mContext = getApplicationContext();

        // Get the widgets reference from XML layout
        mRL = (RelativeLayout) findViewById(R.id.rl);
        ToggleButton toggle = (ToggleButton) findViewById(R.id.toggle);

        // Get the screen size in pixels
        mScreenSize = getScreenSize();

        /*
            Handler
                A Handler allows you to send and process Message and Runnable objects associated with
                a thread's MessageQueue. Each Handler instance is associated with a single thread
                and that thread's message queue. When you create a new Handler, it is bound to the
                thread / message queue of the thread that is creating it -- from that point on,
                it will deliver messages and runnables to that message queue and execute them
                as they come out of the message queue.
        */
        /*
            public Handler ()
                Default constructor associates this handler with the Looper for the current thread.
                If this thread does not have a looper, this handler won't be able to receive
                messages so an exception is thrown.
        */
        // Initialize a new Handler
        mHandler = new Handler();

        // Initialize a new instance of GradientGenerator class
        mGradientGenerator = new GradientGenerator(mContext,mScreenSize);

        // Generate a random GradientDrawable
        mStartGradient = mGradientGenerator.getRandomGradientDrawable();

        // Set the RelativeLayout background
        mRL.setBackground(mStartGradient);

        // Set click listener for ToggleButton
        toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                if (b) {
                    /*
                        Runnable
                            Represents a command that can be executed. Often used to run code in a
                            different Thread.

                        Thread
                            A Thread is a concurrent unit of execution. It has its own call stack for
                            methods being invoked, their arguments and local variables. Each application
                            has at least one thread running when it is started, the main thread, in the
                            main ThreadGroup. The runtime keeps its own threads in the system thread group.

                            There are two ways to execute code in a new thread. You can either subclass
                            Thread and overriding its run() method, or construct a new Thread and pass a
                            Runnable to the constructor. In either case, the start() method must be
                            called to actually execute the new Thread.
                    */
                    // Initialize a new Runnable
                    mRunnable = new Runnable() {
                        /*
                            public abstract void run ()
                                Starts executing the active part of the class' code. This method is
                                called when a thread is started that has been created with a class which
                                implements Runnable.
                        */
                        @Override
                        public void run() {
                            // Do a task after an interval
                            doTask();
                        }
                    };
                    // Play animation immediately after button click
                    mHandler.postDelayed(mRunnable, 100);
                } else {
                    /*
                        public final void removeCallbacks (Runnable r)
                            Remove any pending posts of Runnable r that are in the message queue.
                    */
                    // Stop the animation
                    mHandler.removeCallbacks(mRunnable);
                }
            }
        });
    }

    // Custom method to do a task
    protected void doTask(){
        // If the animation already running
        if(mEndGradient != null){
            /*
                To make a continuous animation we get the last animation ending GradientDrawable
                and set it as next animation starting GradientDrawable
            */
            mStartGradient = mEndGradient;
        }

        /*
            An extension of LayerDrawables that is intended to cross-fade between the first
            and second layer. So, TransitionDrawable support only two layers.
        */
        // Generate an array of GradientDrawable objects
        GradientDrawable[] mGradientDrawableArray = new GradientDrawable[]{
                mStartGradient,
                mGradientGenerator.getRandomGradientDrawable()
        };

        // Get and store the last element from GradientDrawable array
        mEndGradient = mGradientDrawableArray[mGradientDrawableArray.length-1];

        // Initialize a new TransitionDrawable using ColorDrawable array
        drawable = new TransitionDrawable(mGradientDrawableArray);

        // Set the animation duration
        drawable.startTransition(mInterval);

        // Set the TransitionDrawable as RelativeLayout background drawable
        mRL.setBackground(drawable);

        /*
            public final boolean postDelayed (Runnable r, long delayMillis)
                Causes the Runnable r to be added to the message queue, to be run after the specified
                amount of time elapses. The runnable will be run on the thread to which this handler
                is attached. The time-base is uptimeMillis(). Time spent in deep sleep will add an
                additional delay to execution.
        */
        // Schedule the next animation
        mHandler.postDelayed(mRunnable,mInterval);
    }

    // Custom method to get screen size in pixels
    protected Point getScreenSize(){
        DisplayMetrics dm = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) mContext.getSystemService(mContext.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(dm);
        Point size = new Point(dm.widthPixels,dm.heightPixels);
        return size;
    }
}
GradientGenerator.java

package com.cfsuman.me.androidsnippets;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.GradientDrawable;

import java.util.Random;

public class GradientGenerator {
    private Random mRandom = new Random();
    private Context mContext;
    private Point mGradientSize;

    GradientGenerator(Context context, Point gradientSize){
        // Set the context of application
        this.mContext = context;
        // Set the gradient size (width and height)
        this.mGradientSize = gradientSize;
    }

    // Custom method to generate random GradientDrawable array
    protected GradientDrawable[] getRandomGradientDrawableArray(int length){
        GradientDrawable[] gradients = new GradientDrawable[length];
        for (int i=0;i<length;i++){
            gradients[i] = getRandomGradientDrawable();
        }
        return gradients;
    }

    // Custom method to generate random GradientDrawable
    protected GradientDrawable getRandomGradientDrawable(){
        GradientDrawable gradient = new GradientDrawable();

        /*
            public void setOrientation (GradientDrawable.Orientation orientation)
                Changes the orientation of the gradient defined in this drawable.

                Note: changing orientation will affect all instances of a drawable loaded from a
                    resource. It is recommended to invoke mutate() before changing the orientation.

                Parameters
                    orientation : The desired orientation (angle) of the gradient
        */
        // Set the gradient orientation
        gradient.setOrientation(getRandomOrientation());

        /*
            public void setColors (int[] colors)
                Sets the colors used to draw the gradient.
                Each color is specified as an ARGB integer and the array must contain at least 2 colors.

                Parameters
                    colors : an array containing 2 or more ARGB colors
        */
        // Set the gradient colors
        gradient.setColors(getRandomColorArray());

        // The type of the gradient: LINEAR_GRADIENT, RADIAL_GRADIENT or SWEEP_GRADIENT
        gradient = setRandomGradientType(gradient);

        /*
            public void setSize (int width, int height)
                Sets the size of the shape drawn by this drawable.

                Parameters
                width : The width of the shape used by this drawable
                height : The height of the shape used by this drawable
        */
        // Set the gradient size (width and height)
        gradient.setSize(mGradientSize.x, mGradientSize.y);

        // Return the GradientDrawable
        return gradient;
    }

    // Custom method to get a random GradientDrawable GradientType
    protected GradientDrawable setRandomGradientType(GradientDrawable gradient){
        /*
            public void setGradientType (int gradient)
                Sets the type of gradient used by this drawable.

                Parameters
                    gradient : The type of the gradient: LINEAR_GRADIENT, RADIAL_GRADIENT or SWEEP_GRADIENT
        */
        /*
            Get a random number from 0,1, and 2
            We Uses the random numbers as this way
            0 = LINEAR_GRADIENT
            1 = RADIAL_GRADIENT
            2 = SWEEP_GRADIENT
         */
        int randomNumber = mRandom.nextInt(3);
        if(randomNumber == 0){
            gradient.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        }else if(randomNumber==1)
        {
            gradient.setGradientType(GradientDrawable.RADIAL_GRADIENT);
        }else {
            gradient.setGradientType(GradientDrawable.SWEEP_GRADIENT);
        }

        // Set the gradient center for GradientDrawable
        if(randomNumber !=0){
            /*
                Sets the center location of the gradient. The radius is honored only when the
                gradient type is set to RADIAL_GRADIENT or SWEEP_GRADIENT.

                Gradient center honored a float value between 0 to 1
             */
            //Random.nextFloat() * (x - y) + x
            gradient.setGradientCenter(
                    mRandom.nextFloat() * (1 - 0) + 0,
                    mRandom.nextFloat() * (1 - 0) + 0)
            ;
        }

        // Sets the radius of the gradient.
        if(randomNumber == 1){
            /*
                public void setGradientRadius (float gradientRadius)
                    Sets the radius of the gradient. The radius is honored only when the gradient type is set to RADIAL_GRADIENT.

                    Parameters
                        gradientRadius : The radius of the gradient in pixels
            */
            gradient.setGradientRadius(mRandom.nextInt(mGradientSize.x));
        }

        // Return the GradientDrawable where gradient type assigned
        return gradient;
    }

    // Custom method to generate a color array of random colors
    protected int[] getRandomColorArray(){
        // Get random number between minimum (inclusive) to maximum (exclusive)
        int numberOfColors = mRandom.nextInt(16-3)+3;
        int[] colors = new int[numberOfColors];
        for (int i=0;i<numberOfColors;i++){
            colors[i] = getRandomColor();
        }
        // Return the color array, number of elements between 3 to 15
        return colors;
    }

    // Get a random gradient orientation
    protected GradientDrawable.Orientation getRandomOrientation(){
        // Initialize a new array of GradientDrawable Orientation
        GradientDrawable.Orientation[] orientations = new GradientDrawable.Orientation[]{
                // BL_TR : draw the gradient from the bottom-left to the top-right
                GradientDrawable.Orientation.BL_TR,
                // BOTTOM_TOP : draw the gradient from the bottom to the top
                GradientDrawable.Orientation.BOTTOM_TOP,
                // BR_TL : draw the gradient from the bottom-right to the top-left
                GradientDrawable.Orientation.BR_TL,
                // LEFT_RIGHT : draw the gradient from the left to the right
                GradientDrawable.Orientation.LEFT_RIGHT,
                // RIGHT_LEFT : draw the gradient from the right to the left
                GradientDrawable.Orientation.RIGHT_LEFT,
                // TL_BR : draw the gradient from the top-left to the bottom-right
                GradientDrawable.Orientation.TL_BR,
                // TOP_BOTTOM : draw the gradient from the top to the bottom
                GradientDrawable.Orientation.TOP_BOTTOM,
                // TR_BL : draw the gradient from the top-right to the bottom-left
                GradientDrawable.Orientation.TR_BL
        };
        // Return a random Orientation
        GradientDrawable.Orientation orientation = orientations[mRandom.nextInt(orientations.length)];
        return orientation;
    }

    // Custom method to generate a random color
    protected int getRandomColor(){
        // 256 is excluded, so random number is between 0 to 255
        int red = mRandom.nextInt(256);
        int green = mRandom.nextInt(256);
        int blue = mRandom.nextInt(256);
        int color = Color.argb(255, red, green, blue);
        // Return the random argb color
        return color;
    }
}
More android examples