2

I was trying to find easy way to animate sprite image on my android project. Found some complicated solutions and usage of them was not so easy on RecyclerViewAdapter. Why it can not be doing easy and with custom view.

Here is an example sprite image to be shown as animation. https://cdn.codeandweb.com/blog/2016/05/10/how-to-create-a-sprite-sheet/spritestrip.png

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
OMArikan
  • 306
  • 1
  • 3
  • 9

1 Answers1

3

This custom view works really good for sprite emoji image.

If someone need sprite image animation on Android can use this custom ImageView.

public class AnimatedImageView extends AppCompatImageView {

    private static final String KEY_ACTIVITY = "activity";
    private static final String KEY_FRAME_COUNT = "frameCount";
    private static final String KEY_FRAME_SPEED = "frameSpeed";
    private static final String KEY_LOOP_ENABLE = "loopEnable";
    private static final String KEY_SOURCE_URL = "sourceUrl";

    private AppCompatActivity activity;

    private Bitmap sourceBitmap;
    private Bitmap croppedBitmap;

    private int xPos;

    private int frameCount;
    private int frameSpeed;
    private int frameWidth, frameHeight;

    private int sourceWidth;

    private boolean loopEnable;

    private Timer timer;

    public AnimatedImageView(Context context) {
        super(context);
    }

    public AnimatedImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public AnimatedImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void start(Map <String,Object> map) {
        this.activity = (AppCompatActivity) map.get(KEY_ACTIVITY);
        this.frameCount = (int) map.get(KEY_FRAME_COUNT);
        this.frameSpeed = (int) map.get(KEY_FRAME_SPEED);
        this.loopEnable = (boolean) map.get(KEY_LOOP_ENABLE);
        new DownloadImage().execute(String.valueOf(map.get(KEY_SOURCE_URL)));
    }

    private void animateBitmap() {
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                prepareBitmap();
            }
        }, 0, frameSpeed);
    }

    private void prepareBitmap() {
        croppedBitmap = Bitmap.createBitmap(sourceBitmap, xPos, 0, frameWidth, frameHeight);
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                setImageBitmap(croppedBitmap);

                if (xPos + frameWidth >= sourceWidth) {
                    if (loopEnable) {
                        xPos = 0;
                    } else {
                        xPos = 0;
                        timer.cancel();
                        return;
                    }
                }

                xPos = xPos + frameWidth;
            }
        });
    }

    private void buildView(Bitmap bitmap) {
        sourceBitmap = bitmap;
        frameWidth = sourceBitmap.getWidth() / frameCount;
        frameHeight = sourceBitmap.getHeight();
        sourceWidth = sourceBitmap.getWidth();

        measure(frameWidth, frameHeight);

        animateBitmap();
    }

    public int getFrameCount() {
        return frameCount;
    }

    public void setFrameCount(int frameCount) {
        this.frameCount = frameCount;
    }

    public int getFrameSpeed() {
        return frameSpeed;
    }

    public void setFrameSpeed(int frameSpeed) {
        this.frameSpeed = frameSpeed;
    }

    public boolean isLoopEnable() {
        return loopEnable;
    }

    public void setLoopEnable(boolean loopEnable) {
        this.loopEnable = loopEnable;
    }

    private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
        @Override
        protected Bitmap doInBackground(String... url) {
            String imageURL = url[0];
            Bitmap bitmap = null;

            try {
                InputStream input = new URL(imageURL).openStream();
                bitmap = BitmapFactory.decodeStream(input);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            buildView(bitmap);
        }
    }

    public static class AnimationBuilder {

        private final int DEFAULT_FRAME_COUNT = 20;
        private final int DEFAULT_FRAME_SPEED = 40;

        private AppCompatActivity activity;
        private int frameCount = DEFAULT_FRAME_COUNT;
        private int frameSpeed = DEFAULT_FRAME_SPEED;
        private boolean loopEnable;
        private String sourceUrl = "";

        private AppCompatActivity getAppCompatActivity() {
            return activity;
        }

        public AnimationBuilder from(AppCompatActivity activity) {
            this.activity = activity;
            return this;
        }

        private int getFrameCount() {
            return frameCount;
        }

        public AnimationBuilder frameCount(int frameCount) {
            this.frameCount = frameCount;
            return this;
        }

        private int getFrameSpeed() {
            return frameSpeed;
        }

        public AnimationBuilder frameSpeed(int frameSpeed) {
            this.frameSpeed = frameSpeed;
            return this;
        }

        private boolean isLoopEnable() {
            return loopEnable;
        }

        public AnimationBuilder loopEnable(boolean loopEnable) {
            this.loopEnable = loopEnable;
            return this;
        }

        private String getSourceUrl() {
            return sourceUrl;
        }

        public AnimationBuilder load(String sourceUrl) {
            this.sourceUrl = sourceUrl;
            return this;
        }

        public Map<String, Object> build() {
            Map<String, Object> builtMap = new HashMap<>();
            builtMap.put(KEY_ACTIVITY, getAppCompatActivity());
            builtMap.put(KEY_FRAME_COUNT, getFrameCount());
            builtMap.put(KEY_FRAME_SPEED, getFrameSpeed());
            builtMap.put(KEY_LOOP_ENABLE, isLoopEnable());
            builtMap.put(KEY_SOURCE_URL, getSourceUrl());
            return builtMap;
        }
    }
}

Usage :

To use this custom ImageView you need to know frameCount.

Only works with image url.

for image on question frame count is 6

yourAnimatedImageView.start(new AnimatedImageView.AnimationBuilder()
            .from(activity)
            .frameCount(6)
            .frameSpeed(50)
            .load("https://cdn.codeandweb.com/blog/2016/05/10/how-to-create-a-sprite-sheet/spritestrip.png")
            .loopEnable(false).build());

Hope it is gonna help who is looking solution to animate sprite image on Android.

OMArikan
  • 306
  • 1
  • 3
  • 9