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:

  1. 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.

    ReplyDelete
  2. 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....



    ReplyDelete
  3. hello Gaurav Mandlik,

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

    ReplyDelete
  4. 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.

    ReplyDelete
  5. ???

    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

    ReplyDelete
  6. THANKS A LOT!!!!
    Fantastic job!
    Very clear and useful code!

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

    ReplyDelete