LoadingDrawable contains a number of cool loading animations that can be used with any View as loading animations or progressbars. The idea for the project comes from this animated link

Note: This project is in the update phase, and new LoadingDrawable animations will be added constantly. Please check out Github for the latest LoadingDrawable updates.

Project profile

LoadingDrawable inherits Drawable and implements the Animatable loading library. This project uses Strategy mode. The constructor must be passed in a subclass of LoadingRenderer. And interacts with the LoadingRenderer via Callback. LoadingRenderer is responsible for measuring and drawing LoadingDrawable.

Drawable

Drawable is lightweight, efficient and reusable. The most common form of Drawable is to read Drawable😄😄😄 from the res/ Drawable file. Unlike a View, Drawable cannot receive events or otherwise interact with the user.

Drawable provides some general methods for controlling drawing. As follows:

  • SetBounds (Rect) determines the position and size of the Drawable, and all Drawable’s should follow this rule. Drawable generally returns the size specified by setBounds(Rect) in a scaled form. In addition, the preferred size is usually set by getIntrinsicHeight () and getIntrinsicWidth ().

  • GetPadding (Rect) determines the inner spacing of the Drawable. This is used when the contents of the Drawable need to be drawn at the specified location, not the starting location.

  • SetState (int[]) determines which client states can be drawn, such as “focused”, “selected”, etc. Some Drawables can be modified based on the selected states. When I define StateListDrawable(defined using the selector element in XML), I often use “selected” to set the state, mainly because not all views have “checked” state.

  • SetLevel (int) allows a client to provide a single continuous controller to modify the Drawable currently being displayed, such as battery level or progress. Some Drawables can change the image they draw based on the current level.

  • Drawable.Callback is commonly used for Callback control of Drawable animations. All Drawable subclasses should support this class, otherwise animations will not work on views that implement this interface to interact with Drawable. In addition, this class is the interface between LoadingDrawable and LoadingRenderer.

Animatable

Animatable is an Android interface designed to support Drawable animations. The well-known AnimationDrawable is written implementing this interface.

Animatable provides only three abstract methods. As follows:

  • IsRunning () indicates whether the animation isRunning.

  • Start () starts Drawable’s animation.

  • Stop () stops the Drawable animation.

LoadingDrawable

LoadingDrawable inherits Drawable and implements an animation loading library written by interface Animatable. LoadingDrawable is a library that covers the basic methods you need to rewrite to customize Drawable and the basic framework for writing animations. LoadingDrawable is like a book that describes the chapters of animation knowledge. LoadingDrawable is also like a library that contains all kinds of cool animations.

What does LoadingDrawable implement?

  • Circular jumping series
    • SwapLoadingRenderer
    • GuardLoadingRenderer
    • DanceLoadingRenderer
    • CollisionLoadingRenderer
  • Circular rolling series

    • GearLoadingRenderer
    • WhorlLoadingRenderer
    • LevelLoadingRenderer
    • MaterialLoadingRenderer
  • Landscape series

    • DayNightLoadingRenderer
    • ElectricFanLoadingRenderer
  • Animal series

    • FishLoadingRenderer
    • GhostsEyeLoadingRenderer
  • Series of articles

    • BalloonLoadingRenderer
    • WaterBottleLoadingRenderer

What is involved in LoadingDrawable?

1. Common usage of Canvas 2. Basic usage of Path 3. Basic usage of PathMeasure 4. Bezier curve formula (just need to know linear formula, quadratic formula, cubic formula)

What is the core code of LoadingDrawable?

public class LoadingDrawable extends Drawable implements Animatable { private LoadingRenderer mLoadingRender; private final Callback mCallback = new Callback() { @Override public void invalidateDrawable(Drawable d) { invalidateSelf(); } @Override public void scheduleDrawable(Drawable d, Runnable what, long when) { scheduleSelf(what, when); } @Override public void unscheduleDrawable(Drawable d, Runnable what) { unscheduleSelf(what); }}; public LoadingDrawable(LoadingRenderer loadingRender) { this.mLoadingRender = loadingRender; this.mLoadingRender.setCallback(mCallback); } @Override public void draw(Canvas canvas) { mLoadingRender.draw(canvas, getBounds()); } @Override public void setAlpha(int alpha) { mLoadingRender.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mLoadingRender.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } @Override public void start() { mLoadingRender.start(); } @Override public void stop() { mLoadingRender.stop(); } @Override public boolean isRunning() { return mLoadingRender.isRunning(); } @Override public int getIntrinsicHeight() { return (int) mLoadingRender.getHeight(); } @Override public int getIntrinsicWidth() { return (int) mLoadingRender.getWidth(); }}Copy the code

The implementation of LoadingDrawable is completely delegated to a LoadingDrawable member variable of type LoadingRenderer. Instead of proxy mode, I simply extract the behavior of LoadingDrawable into the LoadingRenderer. It is convenient for the unified implementation of subclass inheritance. I designed the LoadingDrawable from the analysis of the Android source code Of the MaterialProgressDrawable. At the beginning, I felt that the internal implementation of the MaterialProgressDrawable was quite good, but I felt that the code was very disordered, SO I organized it. This is the prototype of LoadingDrawable. Let’s take a look at the internal implementation of the LoadingRenderer.

public abstract class LoadingRenderer { private static final long ANIMATION_DURATION = 1333; Private static final Float DEFAULT_SIZE = 56.0f; Private static final Float DEFAULT_CENTER_RADIUS = 12.5f; Private static final Float DEFAULT_STROKE_WIDTH = 2.5f; protected float mWidth; protected float mHeight; protected float mStrokeWidth; protected float mCenterRadius; private long mDuration; private Drawable.Callback mCallback; private ValueAnimator mRenderAnimator; public LoadingRenderer(Context context) { setupDefaultParams(context); setupAnimators(); } public abstract void draw(Canvas canvas, Rect bounds); public abstract void computeRender(float renderProgress); public abstract void setAlpha(int alpha); public abstract void setColorFilter(ColorFilter cf); public abstract void reset(); public void start() { reset(); setDuration(mDuration); mRenderAnimator.start(); } public void stop() { mRenderAnimator.cancel(); } public boolean isRunning() { return mRenderAnimator.isRunning(); } public void setCallback(Drawable.Callback callback) { this.mCallback = callback; } protected void invalidateSelf() { mCallback.invalidateDrawable(null); } private void setupDefaultParams(Context context) { final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); final float screenDensity = metrics.density; mWidth = DEFAULT_SIZE * screenDensity; mHeight = DEFAULT_SIZE * screenDensity; mStrokeWidth = DEFAULT_STROKE_WIDTH * screenDensity; mCenterRadius = DEFAULT_CENTER_RADIUS * screenDensity; mDuration = ANIMATION_DURATION; } private void setupAnimators() {renderAnimator = valueAnimator.offloat (0.0f, 1.0f); mRenderAnimator.setRepeatCount(Animation.INFINITE); mRenderAnimator.setRepeatMode(Animation.RESTART); //fuck you! the default interpolator is AccelerateDecelerateInterpolator mRenderAnimator.setInterpolator(new LinearInterpolator()); mRenderAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { computeRender((float) animation.getAnimatedValue()); invalidateSelf(); }}); } protected void addRenderListener(Animator.AnimatorListener animatorListener) { mRenderAnimator.addListener(animatorListener); } public void setCenterRadius(float centerRadius) { mCenterRadius = centerRadius; } public float getCenterRadius() { return mCenterRadius; } public void setStrokeWidth(float strokeWidth) { mStrokeWidth = strokeWidth; } public float getStrokeWidth() { return mStrokeWidth; } public float getWidth() { return mWidth; } public void setWidth(float width) { this.mWidth = width; } public float getHeight() { return mHeight; } public void setHeight(float height) { this.mHeight = height; } public long getDuration() { return mDuration; } public void setDuration(long duration) { this.mDuration = duration; mRenderAnimator.setDuration(mDuration); }}Copy the code

MWidth, mHeight determines the preferred size of the Drawable (which can be stretched, for example when ImageView sets different ScaleTypes or is used as the background of the View). MStrokeWidth and mCenterRadius are used to unify the original Circle Paint and should not be extracted into the base class. These variables will be optimized later. Renderanimator mRenderAnimator is a variable of type ValueAnimator. It is a trigger for LoadingRenderer to render animation. ComputeRender (float) and invalidateSelf() are called in the onAnimationUpdate() method. ComputeRender (float) calculates the location and size of the current content to draw, as well as the color value. InvalidateSelf () triggers a LoadingDrawable to be redrawn by calling invalidateDrawable(NULL) via the mCallback. A redraw of LoadingDrawable calls the Draw (Canvas, Rect) method of the LoadingRenderer, which then subclasses Draw (Canvas, Rect) using data computed by computeRender(float).

LoadingDrawable (drawable)

Circle source parsing Fish source parsing expects you to participate in LoadingDrawable source analysis. Mutual learning, mutual progress!!

LoadingDrawable (drawable)
















How to use LoadingDrawable?

Use with ImageView

ImageView.setImageDrawable(new LoadingDrawable(new ***LoadingRenderer(Context)));Copy the code

Use with View

View.setBackground(new LoadingDrawable(new ***LoadingRenderer(Context)));Copy the code

About me

I like Android, like open source, like to do animation, will open source some useful projects from time to time.

I will share my open source project on Github at the first time on Weibo, welcome to follow my microblog dinus_developer source address: portal