Wednesday, August 10, 2016

Custom view to draw bitmap along path, calculate in background thread

Last post show a example of "Custom view to draw bitmap along path", with calculation run inside onDraw(). It's modified version to pre-calculate in back thread.


(remark: in last post, canvas.drawPath() is called inside onDraw(). It seem run very slow, removed in this example.)

Modify AnimationView.java
package com.blogspot.android_er.androidmovingbitmapalongpath;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class AnimationView extends View {

    List<AnimationThing> animationThingsList;
    public AnimationView(Context context) {
        super(context);
        initAnimationView();
    }

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

    public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAnimationView();
    }

    private void initAnimationView(){
        animationThingsList = new ArrayList<>();
    }

    public void insertThing(AnimationThing thing){
        animationThingsList.add(thing);
    }

    //prepare calculation in background thread
    public void preDraw(){
        for (AnimationThing thing : animationThingsList){
            if(thing.distance < thing.pathLength){
                thing.pathMeasure.getPosTan(thing.distance, thing.pos, thing.tan);

                thing.matrix.reset();
                float degrees = (float)(Math.atan2(thing.tan[1], 
                        thing.tan[0])*180.0/Math.PI);
                thing.matrix.postRotate(degrees, thing.bm_offsetX, thing.bm_offsetY);
                thing.matrix.postTranslate(thing.pos[0]-thing.bm_offsetX, 
                        thing.pos[1]-thing.bm_offsetY);

                thing.distance += thing.step;
            }else{
                thing.distance = 0;
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (AnimationThing thing : animationThingsList){
            canvas.drawBitmap(thing.bm, thing.matrix, null);
        }

        invalidate();
    }

    /*
    @Override
    protected void onDraw(Canvas canvas) {
        for (AnimationThing thing : animationThingsList){

            //This code run slow!!!
            //canvas.drawPath(thing.animPath, thing.paint);

            if(thing.distance < thing.pathLength){
                thing.pathMeasure.getPosTan(thing.distance, thing.pos, thing.tan);

                thing.matrix.reset();
                float degrees = (float)(Math.atan2(thing.tan[1], 
                    thing.tan[0])*180.0/Math.PI);
                thing.matrix.postRotate(degrees, thing.bm_offsetX, thing.bm_offsetY);
                thing.matrix.postTranslate(thing.pos[0]-thing.bm_offsetX, 
                    thing.pos[1]-thing.bm_offsetY);

                canvas.drawBitmap(thing.bm, thing.matrix, null);

                thing.distance += thing.step;
            }else{
                thing.distance = 0;
            }
        }

        invalidate();
    }
    */


}


MainActivity.java
package com.blogspot.android_er.androidmovingbitmapalongpath;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Path;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    AnimationView myAnimationView;
    AniThread myAniThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myAnimationView = (AnimationView)findViewById(R.id.MyAnimationView);

        prepareThings();
        myAniThread = new AniThread(myAnimationView);
        myAniThread.start();
    }

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

        bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        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();

        step = 1;

        AnimationThing thing = new AnimationThing(animPath, bm, step);
        myAnimationView.insertThing(thing);

        //The second thing
        bm = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_menu_add);

        animPath.reset();
        animPath.addCircle(400, 400, 300, Path.Direction.CW);
        step = 3;
        thing = new AnimationThing(animPath, bm, step);
        myAnimationView.insertThing(thing);
    }

    class AniThread extends Thread{

        AnimationView targetView;

        public AniThread(AnimationView target) {
            super();
            targetView = target;
        }

        @Override
        public void run() {
            while (true){
                targetView.preDraw();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

}


The other files, AnimationThing.java and activity_main.xml, refer last post.


download filesDownload the files .

No comments: