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

7 comments:

Anton Alexeev said...

Thanks a lot!

Gaurav Mandlik 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.

Andr.oid Eric said...

hello Gaurav Mandlik,

Please check update version.

Gaurav Mandlik 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....



Andr.oid Eric said...

hello Gaurav Mandlik,

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

Gaurav Mandlik 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.

Andr.oid Eric 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