Monday, May 26, 2014

Animation of moving bitmap along path

This example show how to animate a moving bitmap along path.


In order to get the position and angle of the animated bitmap in a distance along a path, we use the code:
  pathMeasure = new PathMeasure(animPath, false);
  pathLength = pathMeasure.getLength();

  ...
  pathMeasure.getPosTan(distance, pos, tan);

where pos, and tan are float[2] passed to retrieve the resulting position and tangent.

MainActivity.java.
package com.example.androidanimationalongpath;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

 }

}

/res/layout/activity_main.xml, simple include our custom view in layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidanimationalongpath.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <com.example.androidanimationalongpath.AnimationView 
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

AnimationView.java, custom view.
package com.example.androidanimationalongpath;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Toast;

public class AnimationView extends View {
 
 Paint paint;
 
 Bitmap bm;
 int bm_offsetX, bm_offsetY;
 
 Path animPath;
 PathMeasure pathMeasure;
 float pathLength;
 
 float step;   //distance each step
 float distance;  //distance moved

 float[] pos;
 float[] tan;
 
 Matrix matrix;

 public AnimationView(Context context) {
  super(context);
  initMyView();
 }

 public AnimationView(Context context, AttributeSet attrs) {
  super(context, attrs);
  initMyView();
 }

 public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  initMyView();
 }
 
 public void initMyView(){
  paint = new Paint();
  paint.setColor(Color.BLUE);
  paint.setStrokeWidth(1);
  paint.setStyle(Paint.Style.STROKE);
    
  bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
  bm_offsetX = bm.getWidth()/2;
  bm_offsetY = bm.getHeight()/2;
  
  animPath = new Path();
  animPath.moveTo(100, 100);
  animPath.lineTo(200, 100);
  animPath.lineTo(300, 50);
  animPath.lineTo(400, 150);
  animPath.lineTo(100, 300);
  animPath.lineTo(600, 300);
  animPath.lineTo(100, 100);
  animPath.close();

  pathMeasure = new PathMeasure(animPath, false);
  pathLength = pathMeasure.getLength();
  
  Toast.makeText(getContext(), "pathLength: " + pathLength, Toast.LENGTH_LONG).show();
  
  step = 1;
  distance = 0;
  pos = new float[2];
  tan = new float[2];
  
  matrix = new Matrix();
 }

 @Override
 protected void onDraw(Canvas canvas) {
  
  canvas.drawPath(animPath, paint);
  
  if(distance < pathLength){
   pathMeasure.getPosTan(distance, pos, tan);
   
   matrix.reset();
   float degrees = (float)(Math.atan2(tan[1], tan[0])*180.0/Math.PI);
   matrix.postRotate(degrees, bm_offsetX, bm_offsetY);
   matrix.postTranslate(pos[0]-bm_offsetX, pos[1]-bm_offsetY);
   
   canvas.drawBitmap(bm, matrix, null);
   
   distance += step;
  }else{
   distance = 0;
  }
  
  invalidate();
 }

}


download filesDownload the files.

Next:
Smooth turning along path

More example of Drawing Path on canvas of custom View.

Updated@2016-08-09:
Custom view to draw bitmap along path, in separate object

8 comments:

Unknown said...

Thanks a lot!

Unknown said...

Hi

Thanks a lot for this code. this is what i am looking for, one question in that i just create a Image move path randomly and it will working fine, but how can i move multiple images on that path can u please help me to solve this issue...?

thanks.

Erik said...

hello Gaurav Mandlik,

Please check update version.

Unknown said...

Hi Android Eric

Thanks a lot for Excellent coding, i try your updated code and my work is almost complete. once again thanks.

i just change in your code as per my requirement, but i want a little help from u,i just send u prepareThings() for what i have changes done in this method.

private void prepareThings() {
Paint paint;
Path animPath;
float step;
Bitmap bm;

paint = new Paint();
paint.setColor(Color.TRANSPARENT);
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.STROKE);

bm = BitmapFactory.decodeResource(getResources(), R.drawable.icon_small);

int width = getWindowManager().getDefaultDisplay().getWidth();
int height = getWindowManager().getDefaultDisplay().getHeight();


for (int k=0; k<50; k++){
animPath = new Path();
for (int j = 0; j < 15; j++) {
Random random = new Random();
int fromX = random.nextInt(width);
int fromY = random.nextInt(height);
if (j == 0) {
int toX = random.nextInt(width);
int toY = random.nextInt(height);
animPath.moveTo(toX, toY);
animPath.lineTo(fromX, fromY);
tempX = fromX;
tempY = fromY;
} else {
animPath.lineTo(tempX, tempY);
animPath.lineTo(fromX, fromY);
tempX = fromX;
tempY = fromY;
}
}
step = 10;
animPath.close();
AnimationThing thing = new AnimationThing(paint, animPath, bm, step);
myAnimationView.insertThing(thing);
}
}


as u can see in above code, i just create path randomly and move image is it OK? but when i increase a size of bitmap more then 50 then the move animation is getting slow, can u please tell me why this is happening..?

Once again thanks a lot....



Erik said...

hello Gaurav Mandlik,

It seem that the code canvas.drawPath(thing.animPath, thing.paint) inside onDraw() run slow, remove it if not need.

Unknown said...

Hi Andr.oid Eric

as per your suggestion i just comment the line which is u notify me, but the result is there is no any image and path not draw and move on canvas.

just more brief explanation, i want to create something like that http://emojisandearthporn.com, is it possible in android if it is then how, please guide me..

Thanks.

Erik said...

???

Only comment the code:
canvas.drawPath(thing.animPath, thing.paint);

as shown here:
http://android-er.blogspot.com/2016/08/custom-view-to-draw-bitmap-along-path_10.html

Unknown said...

THANKS A LOT!!!!
Fantastic job!
Very clear and useful code!

This is exactly what beginners like me -:) must understood in onDraw()