Follow the former post "
Animation follow touch path". The example show how to draw animation follow user touch path. Always one step in each onDraw(), without concern the device dpi, screen size... In some case, for example small screen with high dpi, or large screen with low dpi, the touch path will have different length, so it have different visual animation speed.
This example show how to retrieve screen dpi by with DisplayMetrics. May be you have to adjust speed (step and stepAngle in the code) at run-time accordingly, depends on your application.
We always have to concern the performance (processing time) of our code. This example also show the processing time in onDraw, time between call of onDraw, and Frame Per Second (it approximate 60 fps). Remember you have to make sure your code cannot run longer than 1/60 second.
run on Nexus One
run on HTC One X
run on Nexus 7 (1st generation)
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, paintText;
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;
long lastTime;
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);
paintText = new Paint();
paintText.setColor(Color.RED);
paintText.setStrokeWidth(1);
paintText.setStyle(Paint.Style.FILL);
paintText.setTextSize(26);
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();
lastTime = System.currentTimeMillis();
}
@Override
protected void onDraw(Canvas canvas) {
if(animPath.isEmpty()){
return;
}
long startNanos = System.nanoTime();
long startMillis = System.currentTimeMillis();
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);
}
}
long endNanos = System.nanoTime();
long betweenFrame = startMillis - lastTime;
int fps = (int) (1000/betweenFrame);
String strProcessingTime = "Processing Time (ns=0.000001ms) = " + (endNanos - startNanos);
String strBetweenFrame = "Between Frame (ms) = " + betweenFrame;
String strFPS = "Frame Per Second (approximate) = " + fps;
lastTime = startMillis;
canvas.drawText(strProcessingTime, 10, 30, paintText);
canvas.drawText(strBetweenFrame, 10, 60, paintText);
canvas.drawText(strFPS, 10, 90, paintText);
canvas.drawText(String.valueOf(pathLength), 10, 120, paintText);
}
@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;
}
}
package com.example.androidanimationalongpath;
import android.support.v7.app.ActionBarActivity;
import android.util.DisplayMetrics;
import android.widget.TextView;
import android.os.Bundle;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textDispInfo = (TextView)findViewById(R.id.dispinfo);
//get display dpi
DisplayMetrics metrics = getResources().getDisplayMetrics();
textDispInfo.setText(
"xdpi = " + metrics.xdpi + "\n" +
"ydpi = " + metrics.ydpi);
}
}
/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" />
<TextView
android:id="@+id/dispinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<com.example.androidanimationalongpath.AnimationView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@android:color/darker_gray" />
</LinearLayout>
</LinearLayout>
Download the files.
APK is prepared for testing on your device.
Next:
-
Change speed of Animation follow touch path
More example of Drawing Path on canvas of custom View.