Animation and Its Subclasses

Animation extends from Object and some known direct subclasses are as follows which have been described shortly.
  • AlphaAnimation: An animation that controls the alpha level of an object. Useful for fading things in and out.
  • AnimationSet: Represents a group of Animations that should be played together. The transformation of each individual animation are composed together into a single transform.
  • RotateAnimation: An animation that controls the rotation of an object. This rotation takes place in the X-Y plane. You can specify the point to use for the center of the rotation, where (0,0) is the top left point. If not specified, (0,0) is the default rotation point.
  • ScaleAnimation: An animation that controls the scale of an object. You can specify the point to use for the center of scaling.
  • TranslateAnimation: An animation that controls the position of an object.

One big disadvantage of Animation and its sub-classes is that you can animate only basic properties like rotation, scale, alpha and position (e.g., not a background color) and these tools are restricted to View's sub-classes only. One more issue you face if you use Animation is that it animates a View's pixel only, not a View itself, e.g., you apply TransitionAnimation to your object, but it stays clickable in the previous location, if not to specify different behavior.
Usage:
We should create an instance of Animation class and override applyTransformation() function of it appropriately.

anim2 = new Animation(){

       @Override
      protected void applyTransformation(float interpolatedTime, Transformation transformation){

          //update property value
          //set the new value to targetView
          //invalidate the view
      }
    };

Then we can set some parameters of the Animation instance and finally run the animation by syntax

targetView.startAnimation(anim2)

The following examples devote to discuss Animation class itself and providing some examples of it. The first example shows how we can create one instance of Animation and use it to make a simple animation on a EditText.

Example 1: Follow the below steps:
Step 1- Create a new Android Studio project and select an Empty Activity template.
Step 2- In activity_main.xml file add an EditText and a Button like below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:animateLayoutChanges="true"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.msh_n.myp.customview1.MainActivity">
<EditText
android:id="@+id/edtTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="108dp"
android:text="Hello World!"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Click"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edtTxt" />
</android.support.constraint.ConstraintLayout>

Step 3- Edit the MainActivity.java file as below.

package com.msh_n.myp.customview1;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
Button button;
Animation anim2;
float oldSize;
float newSize;
EditText edtTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button1);
edtTxt = (EditText) findViewById(R.id.edtTxt);
oldSize = 0f;
newSize = 1f;
anim2 = new Animation(){
@Override
protected void applyTransformation(float interpolatedTime, Transformation transformation){
float size = oldSize + ((newSize - oldSize) * interpolatedTime);
edtTxt.setAlpha(size);
edtTxt.invalidate();
}
};
anim2.setDuration(2000);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
edtTxt.startAnimation(anim2);
}
});
}
}

Here a new instance of Animation has been instantiated and the function applyTransformation() has been override to produce suitable functionality for making the EditText animating.
Now just run the app on an emulator a real device.


Example 2: Here we animate a circle inside the PieView created in the topic Custom View in Android. We want to draw a circle with an animation that draws the circle by angle (refer to end of the example to see the animation).

Step 1- Create a new Android Studio project and select an Empty Activity template.
Step 2- Follow the steps in Custom View in Android to provide a new custom view called PieView like below. Consider that here we added a circle with violet color to convert the circle to a ring, just for having more pretty view. Also suitable getter and setter methods for angle variable have been involved. The PieView.java file is like this:

package com.msh_n.myp.customview1;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.Image;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v7.widget.AppCompatButton;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.widget.Button;
public class PieView extends View {
int radius;
float angle;
Paint paintBackground;
Paint paintV;
Paint paintShadow;
Rect rect;
int backColor;
int viewColor;
int height =500;
int width=250;
int ori;
int actionBarHeight;
RectF rectCircle;
RectF rectOval;
public PieView(Context context){
//this(context, null, 0);
super(context);
}
public PieView(Context context, AttributeSet attrs){
//this(context, attrs, 0);
super(context, attrs);
init(context, attrs);
}
public PieView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public PieView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes){
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
public String getTitleText(){
return titleText;
}
public void setTitleText(String str){
titleText = str;
}
public int getRadius(){
return radius;
}
public float getAngle() {
return angle;
}
public void setAngle(float ang) {
this.angle = ang;
}
protected void init(Context context, @Nullable AttributeSet attrs){
angle = 5;
rect = new Rect();
// finding height of the action bar
TypedValue tv = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
actionBarHeight = getResources().getDimensionPixelSize(tv.resourceId);
paintBackground = new Paint(Paint.ANTI_ALIAS_FLAG);
paintV = new Paint();
paintShadow = new Paint();
//height = getLayoutParams().height;
//width = getLayoutParams().width;
//width = getMeasuredWidth();
//height = getMeasuredHeight();
ori = ((Activity) context).getResources().getConfiguration().orientation;
if(attrs == null){
backColor = getResources().getColor(android.R.color.holo_purple);
viewColor = getResources().getColor(android.R.color.holo_green_light);
paintBackground.setColor(backColor);
paintV.setColor(viewColor);
paintShadow.setColor(getResources().getColor(android.R.color.holo_purple));
return;
}
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.PieView, 0, 0);
try {
titleText = a.getString(R.styleable.PieView_titleText);
backColor = a.getColor(R.styleable.PieView_backgroundColor,
getResources().getColor(android.R.color.holo_blue_light));
viewColor = a.getColor(R.styleable.PieView_viewColor,
getResources().getColor(android.R.color.holo_orange_dark));
} finally {
a.recycle();
}
paintBackground.setColor(backColor);
paintV.setColor(viewColor);
paintShadow.setColor(getResources().getColor(android.R.color.holo_purple));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
//height = h + actionBarHeight;
height = h;
//rectCircle = new RectF(width/2, 0, (3/4)*width, height/3);
rectCircle = new RectF(width/4, 0, 3*width/4, height/3);
rectOval = new
RectF(width/4, 0,width/2+width/3, height/3);
boolean isWidthLarger = width > height/3;
if(isWidthLarger){
radius = height/6;
}else{
radius = width/2;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int desiredWidth = 1000;
int desiredHeight = 1500;
int width;
int height;
//width
if(widthMode == MeasureSpec.EXACTLY){
//Must be this size
width = widthSize;
}else if(widthMode == MeasureSpec.AT_MOST){
//Can't be bigger than...
width = Math.min(widthSize, desiredWidth);
}else{
//Be whatever you want
width = desiredWidth;
}
//height
if(heightMode == MeasureSpec.EXACTLY){
//Must be this size
height = heightSize;
}else if(heightMode == MeasureSpec.AT_MOST){
//Can't be bigger than...
height = Math.min(heightSize, desiredHeight);
}else{
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rect.left = 0;
rect.top = 0;
if(ori == Configuration.ORIENTATION_PORTRAIT) {
rect.bottom = height / 3;
rect.right = width;
RectF rect2 = new RectF();
rect2.left = 0;
rect2.right = width;
rect2.bottom = height;
rect2.top = 0;
/*boolean isWidthLarger = width > height/3;
int r;
if(isWidthLarger){
r = height/6;
}else{
r = width/2;
}*/
//canvas.drawRect(rect2, paintBackground);
canvas.drawRect(rect, paintBackground);
//canvas.drawOval(rectOval, paintShadow);
canvas.drawRect(rectCircle, paintShadow);
canvas.drawArc(rectCircle, 0, angle, true, paintV);
canvas.drawCircle(width/2, height/6, radius/1.2f, paintShadow);
}else if(ori == Configuration.ORIENTATION_LANDSCAPE){
}
}
}
view raw PieView.java hosted with ❤ by GitHub

Step 3- Now we create a new java class called CircleAnimation which extends Animation class and overrides applyTransformation() function like below:

package com.msh_n.myp.customview1;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* Created by MSh on 6/15/2019.
*/
public class CircleAnimation extends Animation {
private PieView pieView;
private float oldAngle;
private float newAngle;
public CircleAnimation(PieView pieView, float newAngle){
this.newAngle = newAngle;
this.pieView = pieView;
this.oldAngle = pieView.getAngle();
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation transformation){
float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
pieView.setAngle(angle);
pieView.requestLayout();
}
}

Step 4- In the current step, we can instantiate an instance of CircleAnimation in MainActivity.java and start the animation.

package com.msh_n.myp.customview1;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button button;
CircleAnimation cirAnim;
PieView pieView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button1);
pieView = (PieView) findViewById(R.id.pieView2);
cirAnim = new CircleAnimation(pieView, 360);
cirAnim.setDuration(3000);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pieView.startAnimation(cirAnim);
}
});
}
}

Now all things are ready to run the animation.

Comments