Friday, June 6, 2014

Change speed of Animation follow touch path

This exercise change the speed of the former example of "Animation follow touch path".


AnimationView.java
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.MotionEvent;
import android.view.View;

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 curX, curY;
  
 float curAngle;  //current angle
 float targetAngle; //target angle
 float stepAngle; //angle each step

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

 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();
  
  pos = new float[2];
  tan = new float[2];
  
  matrix = new Matrix();
  
  touchPath = new Path();
  
  step = 1;  //default
  stepAngle = 1; //default
 }

 @Override
 protected void onDraw(Canvas canvas) {
  if(animPath.isEmpty()){
   return;
  }
  
  canvas.drawPath(animPath, paint);
  
  matrix.reset();
  
  if((targetAngle-curAngle)>stepAngle){
   curAngle += stepAngle;
   matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
   matrix.postTranslate(curX, curY);
   canvas.drawBitmap(bm, matrix, null);
   
   invalidate();
  }else if((curAngle-targetAngle)>stepAngle){
   curAngle -= stepAngle;
   matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
   matrix.postTranslate(curX, curY);
   canvas.drawBitmap(bm, matrix, null);
   
   invalidate();
  }else{
   curAngle=targetAngle;
   if(distance < pathLength){
    pathMeasure.getPosTan(distance, pos, tan);

    targetAngle = (float)(Math.atan2(tan[1], tan[0])*180.0/Math.PI);
    matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
    
    curX = pos[0]-bm_offsetX;
    curY = pos[1]-bm_offsetY;
    matrix.postTranslate(curX, curY);
    
    canvas.drawBitmap(bm, matrix, null);
    
    distance += step;
    
    invalidate();
   }else{
    matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
    matrix.postTranslate(curX, curY);
    canvas.drawBitmap(bm, matrix, null);
   }
  }

 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  
  int action = event.getAction();
  
  switch(action){
  case MotionEvent.ACTION_DOWN:
   touchPath.reset();
   touchPath.moveTo(event.getX(), event.getY());
   break;
  case MotionEvent.ACTION_MOVE:
   touchPath.lineTo(event.getX(), event.getY());
   break;
  case MotionEvent.ACTION_UP:
   touchPath.lineTo(event.getX(), event.getY());
   animPath = new Path(touchPath);
   
   pathMeasure = new PathMeasure(animPath, false);
   pathLength = pathMeasure.getLength();
   
   //step = 1;
   distance = 0;
   curX = 0;
   curY = 0;
   
   //stepAngle = 1; 
   curAngle = 0;
   targetAngle = 0;
   
   invalidate();
   
   break;
    
  }
  
  return true;
 }
 
 public void setSpeed(int sp){
  step = sp;
  stepAngle = sp;
 }

}

/res/layout/activity_main.xml
<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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    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" />

    <SeekBar
        android:id="@+id/speedbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="10"
        android:progress="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
        
        <com.example.androidanimationalongpath.AnimationView
            android:id="@+id/animationview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="10dp"
            android:background="@android:color/darker_gray" />

    </LinearLayout>

</LinearLayout>

MainActivity.java
package com.example.androidanimationalongpath;

import android.support.v7.app.ActionBarActivity;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {
 
 AnimationView animationView;
 SeekBar speedBar;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  animationView = (AnimationView)findViewById(R.id.animationview);
  speedBar = (SeekBar)findViewById(R.id.speedbar);
  speedBar.setOnSeekBarChangeListener(speedBarOnSeekBarChangeListener);
  animationView.setSpeed(speedBar.getProgress()); //set default speed
 }
 
 OnSeekBarChangeListener speedBarOnSeekBarChangeListener = 
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    //offset from SeekBar 0~19 to step 1~10
    animationView.setSpeed(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}};
   

}


download filesDownload the files.

More example of Drawing Path on canvas of custom View.

No comments: