<repo_name>sohel274/AnimatedSpriteProgressBar<file_sep>/animatedspriteprogressbar/src/main/java/com/darkminstrel/aspb/TrapezeSpriteAdapter.java
package com.darkminstrel.aspb;

/**
 * Created by Dark on 19.01.2016.
 */
public final class TrapezeSpriteAdapter implements SpriteAdapter {
    @Override
    public int getSpriteIndex(float interpolatedTime, int totalSpritesCount) {
        int totalFrames = 6*totalSpritesCount;
        int frame = (int) (totalFrames*interpolatedTime);

        int ix;
        if(frame<totalSpritesCount) ix=0;
        else if(frame<2*totalSpritesCount) ix=frame-totalSpritesCount;
        else if(frame<4*totalSpritesCount) ix=totalSpritesCount-1;
        else if(frame<5*totalSpritesCount) ix=totalSpritesCount-1-(frame-4*totalSpritesCount);
        else ix=0;

        return ix;
    }
}
<file_sep>/README.md
# AnimatedSpriteProgressBar
This Android library allows you to create custom indeterminate ProgressBars from your own sprites.

![example](https://cloud.githubusercontent.com/assets/12033349/12432479/241102aa-bf04-11e5-9609-7d2b00c4d867.gif)

### Download

Gradle:

```groovy
compile 'com.darkminstrel.aspb:animatedspriteprogressbar:1.0.0'
```

Maven:
```xml
<dependency>
  <groupId>com.darkminstrel.aspb</groupId>
  <artifactId>animatedspriteprogressbar</artifactId>
  <version>1.0.0</version>
  <type>aar</type>
</dependency>
```

### Usage

* put your sprites into one of the "drawable" folders:
![Example](https://cloud.githubusercontent.com/assets/12033349/12432011/65dd16b8-bf01-11e5-89ed-550f2e457637.png)

* define the array in values/arrays.xml:
```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <array name="progress_array">
        <item>@drawable/progress0</item>
        <item>@drawable/progress1</item>
        <item>@drawable/progress2</item>
        <item>@drawable/progress3</item>
        <item>@drawable/progress4</item>
        <item>@drawable/progress5</item>
        <item>@drawable/progress6</item>
        <item>@drawable/progress7</item>
        <item>@drawable/progress8</item>
        <item>@drawable/progress9</item>
    </array>

</resources>
```

* add AnimatedSpriteProgressBar view to your layout:
```xml
<com.darkminstrel.aspb.AnimatedSpriteProgressBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:sprites="@array/progress_array"
    />
```

* use custom attributes if needed:
```
  app:duration="3000"
  app:rotations="4"
  app:adapter="trapeze|triangle|square" 
  app:interpolator="accelerate_decelerate|linear"
```

### Requirements

Tested on Android 4.1+ (minSdkVersion 16)

### Licence
> Copyright 2016 <NAME>
>
> Licensed under the Apache License, Version 2.0 (the "License");
> you may not use this work except in compliance with the License.
> You may obtain a copy of the License in the LICENSE file, or at:
>
>  [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
>
> Unless required by applicable law or agreed to in writing, software
> distributed under the License is distributed on an "AS IS" BASIS,
> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> See the License for the specific language governing permissions and
> limitations under the License.
<file_sep>/animatedspriteprogressbar/src/main/java/com/darkminstrel/aspb/AnimatedSpriteProgressBar.java
package com.darkminstrel.aspb;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.Transformation;
import android.widget.ImageView;

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

/**
 * Created by Dark on 15.01.2016.
 */
public class AnimatedSpriteProgressBar extends ImageView {

    public AnimatedSpriteProgressBar(Context context) {
        super(context);
        throw new IllegalArgumentException("Constructor with defined AttributeSet must be used");
    }

    public AnimatedSpriteProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public AnimatedSpriteProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private int mDuration, mRotations;
    private List<Drawable> mFramesList;
    private SpriteAdapter mSpriteAdapter;
    private Animation mRotateAnimation;
    private Interpolator mInterpolator;

    private void init(Context context, AttributeSet attrs){
        if(isInEditMode()) return;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.aspb, 0, 0);
        try {
            mDuration = ta.getInteger(R.styleable.aspb_duration, 3000);

            mRotations = ta.getInteger(R.styleable.aspb_rotations, 4);

            mFramesList = new ArrayList<>();
            final int spritesArrayId = ta.getResourceId(R.styleable.aspb_sprites, 0);
            if (spritesArrayId != 0) {
                TypedArray sprites = context.getResources().obtainTypedArray(spritesArrayId);
                int spritesLen = sprites.length();
                for (int i = 0; i < spritesLen; i++) mFramesList.add(getResources().getDrawable(sprites.getResourceId(i, 0)));
                sprites.recycle();
            }
            if(mFramesList.isEmpty()) throw new IllegalArgumentException("No sprites provided");

            int adapter = ta.getInt(R.styleable.aspb_adapter, 0);
            if(adapter == 0) mSpriteAdapter = new TrapezeSpriteAdapter();
            else if(adapter == 1) mSpriteAdapter = new TriangleSpriteAdapter();
            else if(adapter == 2) mSpriteAdapter = new SquareSpriteAdapter();
            else throw new IllegalArgumentException("Unknown sprite adapter");

            int interpolator = ta.getInt(R.styleable.aspb_interpolator, 0);
            if(interpolator == 0) mInterpolator = new AccelerateDecelerateInterpolator();
            else if(interpolator == 1) mInterpolator = new LinearInterpolator();
            else throw new IllegalArgumentException("Unknown interpolator");
        } finally {
            ta.recycle();
        }

        final AnimationDrawable mAnimationDrawable = new AnimationDrawable();
        for(Drawable d : mFramesList) mAnimationDrawable.addFrame(d, 0);
        mRotateAnimation = new RotateAnimation(0, 360*mRotations, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f){
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                int ix = mSpriteAdapter.getSpriteIndex(interpolatedTime, mFramesList.size());
                mAnimationDrawable.selectDrawable(ix);
                super.applyTransformation(interpolatedTime, t);
            }
        };
        mRotateAnimation.setDuration(mDuration);
        mRotateAnimation.setRepeatCount(Animation.INFINITE);
        mRotateAnimation.setInterpolator(mInterpolator);
        setImageDrawable(mAnimationDrawable);
    }

    @Override
    public void setVisibility(int v) {
        if (getVisibility() != v) {
            super.setVisibility(v);
            if (v == GONE || v == INVISIBLE) {
                stopAnimation();
            } else {
                startAnimation();
            }
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startAnimation();
    }

    @Override
    protected void onDetachedFromWindow() {
        stopAnimation();
        super.onDetachedFromWindow();
    }

    void startAnimation() {
        if (getVisibility() != VISIBLE) return;
        startAnimation(mRotateAnimation);
        postInvalidate();
    }

    void stopAnimation() {
        clearAnimation();
        postInvalidate();
    }
}
