diff --git a/.gitignore b/.gitignore index a881469..e479603 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .DS_Store /build /captures +*.iml \ No newline at end of file diff --git a/LoadingDrawable.iml b/LoadingDrawable.iml deleted file mode 100644 index eb791b2..0000000 --- a/LoadingDrawable.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Preview/CircleJumpDrawable.gif b/Preview/CircleJumpDrawable.gif index 5345ad6..58af668 100644 Binary files a/Preview/CircleJumpDrawable.gif and b/Preview/CircleJumpDrawable.gif differ diff --git a/README-ZH.md b/README-ZH.md deleted file mode 100644 index 26cd368..0000000 --- a/README-ZH.md +++ /dev/null @@ -1,94 +0,0 @@ - -## LoadingDrawable -[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-LoadingDrawable-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/3450) - - 一些酷炫的加载动画, 可以与任何View配合使用,作为加载动画或者Progressbar, 此外很适合与[RecyclerRefreshLayout](https://github.com/dinuscxj/RecyclerRefreshLayout) - 配合使用作为刷新的loading 动画
- - 这个项目的思路源于这个动画链接 [link] (http://mp.weixin.qq.com/s?__biz=MjM5MDMxOTE5NA==&mid=402703079&idx=2&sn=2fcc6746a866dcc003c68ead9b68e595&scene=2&srcid=0302A7p723KK8E5gSzLKb2ZL&from=timeline&isappinstalled=0#wechat_redirect).
- 或许你更喜欢使用Gif实现 : [GifLoadingView] (https://github.com/Rogero0o/GifLoadingView).
- -![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/ShapeChangeDrawable.gif) -![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/GoodsDrawable.gif) -![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/AnimalDrawable.gif) -![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/SceneryDrawable.gif) -![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/CircleJumpDrawable.gif) -![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/CircleRotateDrawable.gif) - -## 功能 - -#### 形变系列 - * CircleBroodLoadingRenderer - * CoolWaitLoadingRenderer - -#### 物品系列 - * BalloonLoadingRenderer - * WaterBottleLoadingRenderer - -#### 动物系列 - * FishLoadingRenderer - * GhostsEyeLoadingRenderer - -#### 风景系列 - * DayNightLoadingRenderer - * ElectricFanLoadingRenderer - -#### 圆形滚动系列 - * GearLoadingRenderer - * WhorlLoadingRenderer - * LevelLoadingRenderer - * MaterialLoadingRenderer - -#### 圆形跳动系列 - * SwapLoadingRenderer - * GuardLoadingRenderer - * DanceLoadingRenderer - * CollisionLoadingRenderer - -## 待办事项 -当我感觉bug比较少的时候,我会添加一个gradle依赖。 所以在推上去之前希望大家多提提建议和bug. - -## 用法 -#### Gradle - ``` - compile project(':library') - ``` -#### 在代码里 - - ```java - LoadingView.setLoadingRenderer(LoadingRenderer); - ``` - -#### 在xml中 - ```xml - - ``` - -如果LoadingView不能满足你的需求,或许你需要参考LoadingView进行自定义View - -## 杂谈 -如果你喜欢LoadingDrawable或者在使用它, 你可以 - - * star这个项目 - * 提一些建议, 谢谢。 - -## License - Copyright 2015-2019 dinus - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - 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. diff --git a/README.md b/README.md index 528b43c..b3a0868 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,24 @@ ## LoadingDrawable: Android cool animation collection -[中文版文档](https://github.com/dinuscxj/LoadingDrawable/blob/master/README-ZH.md)    [前言](http://www.jianshu.com/p/6e0ac5af4e8b)    -[Circle系列源码解析](http://www.jianshu.com/p/1c3c6fc1b7ff)    +[CircleRotate源码解析](http://www.jianshu.com/p/1c3c6fc1b7ff)    [Fish源码解析](http://blog.csdn.net/XSF50717/article/details/51494266)
[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-LoadingDrawable-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/3450) - Some android loading drawable, can be combined with any View as the loading View and Progressbar, - - This project idea is from the [link] (http://mp.weixin.qq.com/s?__biz=MjM5MDMxOTE5NA==&mid=402703079&idx=2&sn=2fcc6746a866dcc003c68ead9b68e595&scene=2&srcid=0302A7p723KK8E5gSzLKb2ZL&from=timeline&isappinstalled=0#wechat_redirect).
- Perhaps you prefer to use gif way to achieve : [GifLoadingView] (https://github.com/Rogero0o/GifLoadingView).
+ LoadingDrawable is some android animations implement of drawable: a library can be used in the pull-down to refresh, the placeholders of image loading and the time-consuming tasks. This project idea is from the [link](http://mp.weixin.qq.com/s?__biz=MjM5MDMxOTE5NA==&mid=402703079&idx=2&sn=2fcc6746a866dcc003c68ead9b68e595&scene=2&srcid=0302A7p723KK8E5gSzLKb2ZL&from=timeline&isappinstalled=0#wechat_redirect).
+ +The following content show a brief overview of LoadingDrawable + +* It extends `Drawable` and implement the interface `Animatable` +* it uses strategy mode +* It can be used as the background of View or content of `ImageView` +* It's constructor must be passed a `LoadingRenderer` +* It interact with `LoadingRenderer` by the callback `Callback` +* `LoadingRenderer` is used for measuring and drawing the `LoadingDrawable`. note: +`LoadingRenderer` is the core +* `LoadingRenderer` only can be created by their `Builder`. + +Learn more about LoadingDrawable on the [Wiki Home](https://github.com/dinuscxj/LoadingDrawable/wiki). ![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/ShapeChangeDrawable.gif) ![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/GoodsDrawable.gif) @@ -18,7 +27,7 @@ ![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/CircleJumpDrawable.gif) ![](https://raw.githubusercontent.com/dinuscxj/LoadingDrawable/master/Preview/CircleRotateDrawable.gif) -## Features +## LoadingRenderer Style #### ShapeChange * CircleBroodLoadingRenderer @@ -33,37 +42,23 @@ * GhostsEyeLoadingEyeRenderer #### Scenery - * DayNightLoadingRenderer * ElectricFanLoadingRenderer - -#### Circle Rotate - * GearLoadingRenderer - * WhorlLoadingRenderer - * LevelLoadingRenderer - * MaterialLoadingRenderer + * DayNightLoadingRenderer #### Circle Jump + * CollisionLoadingRenderer * SwapLoadingRenderer * GuardLoadingRenderer * DanceLoadingRenderer - * CollisionLoadingRenderer -## TODO - When I feel less bugs enough, I will add a gradle dependency. So I hope you will make more Suggestions or Issues. +#### Circle Rotate + * WhorlLoadingRenderer + * MaterialLoadingRenderer + * GearLoadingRenderer + * LevelLoadingRenderer ## Usage -#### Gradle - ``` - compile project(':library') - ``` -#### In java - - ```java - LoadingView.setLoadingRenderer(LoadingRenderer); - ``` - -#### In xml - + Define the `LoadingView` in XML and specify the `LoadingRenderer` style: ```xml ``` - -If the LoadingView can't meet your requirements, you might need to refer to the LoadingView customize the View you need + Or specify the `LoadingRenderer` style in Java + ```java + ***LoadingRenderer.Builder builder = new ***LoadingRenderer.Builder(context); + LoadingView.setLoadingRenderer(builder.build()); + ``` + +## TODO + When I feel less bugs enough, I will add a gradle dependency. So I hope you will make more Suggestions or Issues. ## Misc If you like LoadingDrawable or use it, could you please: * star this repo * send me some feedback. Thanks! + + ***QQ Group:*** **342748245** ## License Copyright 2015-2019 dinus diff --git a/app/app.iml b/app/app.iml deleted file mode 100644 index c8d9349..0000000 --- a/app/app.iml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/app/dinus/com/example/AnimalActivity.java b/app/src/main/java/app/dinus/com/example/AnimalActivity.java index fde72d1..45c1bee 100644 --- a/app/src/main/java/app/dinus/com/example/AnimalActivity.java +++ b/app/src/main/java/app/dinus/com/example/AnimalActivity.java @@ -4,11 +4,6 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; - -import app.dinus.com.loadingdrawable.LoadingDrawable; -import app.dinus.com.loadingdrawable.render.animal.FishLoadingRenderer; -import app.dinus.com.loadingdrawable.render.animal.GhostsEyeLoadingRenderer; public class AnimalActivity extends AppCompatActivity { public static void startActivity(Context context) { diff --git a/app/src/main/java/app/dinus/com/example/CircleJumpActivity.java b/app/src/main/java/app/dinus/com/example/CircleJumpActivity.java index 313c0a2..bf95c98 100644 --- a/app/src/main/java/app/dinus/com/example/CircleJumpActivity.java +++ b/app/src/main/java/app/dinus/com/example/CircleJumpActivity.java @@ -4,13 +4,6 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; - -import app.dinus.com.loadingdrawable.LoadingDrawable; -import app.dinus.com.loadingdrawable.render.circle.jump.CollisionLoadingRenderer; -import app.dinus.com.loadingdrawable.render.circle.jump.DanceLoadingRenderer; -import app.dinus.com.loadingdrawable.render.circle.jump.GuardLoadingRenderer; -import app.dinus.com.loadingdrawable.render.circle.jump.SwapLoadingRenderer; public class CircleJumpActivity extends AppCompatActivity { public static void startActivity(Context context) { diff --git a/app/src/main/java/app/dinus/com/example/CircleRotateActivity.java b/app/src/main/java/app/dinus/com/example/CircleRotateActivity.java index a4fdf8e..ffd562e 100644 --- a/app/src/main/java/app/dinus/com/example/CircleRotateActivity.java +++ b/app/src/main/java/app/dinus/com/example/CircleRotateActivity.java @@ -2,11 +2,13 @@ import android.content.Context; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; -import app.dinus.com.loadingdrawable.LoadingDrawable; +import app.dinus.com.loadingdrawable.DensityUtil; +import app.dinus.com.loadingdrawable.LoadingView; +import app.dinus.com.loadingdrawable.render.LoadingRenderer; import app.dinus.com.loadingdrawable.render.circle.rotate.GearLoadingRenderer; import app.dinus.com.loadingdrawable.render.circle.rotate.LevelLoadingRenderer; import app.dinus.com.loadingdrawable.render.circle.rotate.MaterialLoadingRenderer; diff --git a/app/src/main/java/app/dinus/com/example/GoodsActivity.java b/app/src/main/java/app/dinus/com/example/GoodsActivity.java index 1bfe40e..552b59f 100644 --- a/app/src/main/java/app/dinus/com/example/GoodsActivity.java +++ b/app/src/main/java/app/dinus/com/example/GoodsActivity.java @@ -4,12 +4,6 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; - -import app.dinus.com.loadingdrawable.LoadingDrawable; -import app.dinus.com.loadingdrawable.render.animal.GhostsEyeLoadingRenderer; -import app.dinus.com.loadingdrawable.render.goods.BalloonLoadingRenderer; -import app.dinus.com.loadingdrawable.render.goods.WaterBottleLoadingRenderer; public class GoodsActivity extends AppCompatActivity { diff --git a/app/src/main/java/app/dinus/com/example/SceneryActivity.java b/app/src/main/java/app/dinus/com/example/SceneryActivity.java index 545c39f..b6756aa 100644 --- a/app/src/main/java/app/dinus/com/example/SceneryActivity.java +++ b/app/src/main/java/app/dinus/com/example/SceneryActivity.java @@ -4,11 +4,6 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; - -import app.dinus.com.loadingdrawable.LoadingDrawable; -import app.dinus.com.loadingdrawable.render.scenery.DayNightLoadingRenderer; -import app.dinus.com.loadingdrawable.render.scenery.ElectricFanLoadingRenderer; public class SceneryActivity extends AppCompatActivity { diff --git a/app/src/main/java/app/dinus/com/example/ShapeChangeActivity.java b/app/src/main/java/app/dinus/com/example/ShapeChangeActivity.java index a278d35..5cc5d83 100644 --- a/app/src/main/java/app/dinus/com/example/ShapeChangeActivity.java +++ b/app/src/main/java/app/dinus/com/example/ShapeChangeActivity.java @@ -4,11 +4,6 @@ import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; - -import app.dinus.com.loadingdrawable.LoadingDrawable; -import app.dinus.com.loadingdrawable.render.shapechange.CircleBroodLoadingRenderer; -import app.dinus.com.loadingdrawable.render.shapechange.CoolWaitLoadingRenderer; public class ShapeChangeActivity extends AppCompatActivity { diff --git a/library/library.iml b/library/library.iml deleted file mode 100644 index ed83241..0000000 --- a/library/library.iml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/LoadingView.java b/library/src/main/java/app/dinus/com/loadingdrawable/LoadingView.java index d919880..ba77e64 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/LoadingView.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/LoadingView.java @@ -6,6 +6,7 @@ import android.view.View; import android.widget.ImageView; +import app.dinus.com.loadingdrawable.render.LoadingDrawable; import app.dinus.com.loadingdrawable.render.LoadingRenderer; import app.dinus.com.loadingdrawable.render.LoadingRendererFactory; @@ -53,7 +54,9 @@ protected void onDetachedFromWindow() { @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); - if (visibility == View.VISIBLE) { + + final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE; + if (visible) { startAnimation(); } else { stopAnimation(); diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/LoadingDrawable.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingDrawable.java similarity index 68% rename from library/src/main/java/app/dinus/com/loadingdrawable/LoadingDrawable.java rename to library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingDrawable.java index e021df3..0c30ed6 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/LoadingDrawable.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingDrawable.java @@ -1,15 +1,16 @@ -package app.dinus.com.loadingdrawable; +package app.dinus.com.loadingdrawable.render; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; +import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import app.dinus.com.loadingdrawable.render.LoadingRenderer; public class LoadingDrawable extends Drawable implements Animatable { - private LoadingRenderer mLoadingRender; + private final LoadingRenderer mLoadingRender; private final Callback mCallback = new Callback() { @Override @@ -33,19 +34,27 @@ public LoadingDrawable(LoadingRenderer loadingRender) { this.mLoadingRender.setCallback(mCallback); } + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + this.mLoadingRender.setBounds(bounds); + } + @Override public void draw(Canvas canvas) { - mLoadingRender.draw(canvas, getBounds()); + if (!getBounds().isEmpty()) { + this.mLoadingRender.draw(canvas); + } } @Override public void setAlpha(int alpha) { - mLoadingRender.setAlpha(alpha); + this.mLoadingRender.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { - mLoadingRender.setColorFilter(cf); + this.mLoadingRender.setColorFilter(cf); } @Override @@ -55,26 +64,26 @@ public int getOpacity() { @Override public void start() { - mLoadingRender.start(); + this.mLoadingRender.start(); } @Override public void stop() { - mLoadingRender.stop(); + this.mLoadingRender.stop(); } @Override public boolean isRunning() { - return mLoadingRender.isRunning(); + return this.mLoadingRender.isRunning(); } @Override public int getIntrinsicHeight() { - return (int) mLoadingRender.getHeight(); + return (int) this.mLoadingRender.mHeight; } @Override public int getIntrinsicWidth() { - return (int) mLoadingRender.getWidth(); + return (int) this.mLoadingRender.mWidth; } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRenderer.java index d74efe4..fe0282b 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRenderer.java @@ -6,10 +6,12 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.util.DisplayMetrics; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; import android.view.animation.Animation; -import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import app.dinus.com.loadingdrawable.DensityUtil; @@ -18,51 +20,87 @@ public abstract class LoadingRenderer { private static final long ANIMATION_DURATION = 1333; private static final float DEFAULT_SIZE = 56.0f; - protected float mWidth; - protected float mHeight; + private final ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener + = new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + computeRender((float) animation.getAnimatedValue()); + invalidateSelf(); + } + }; + + /** + * Whenever {@link LoadingDrawable} boundary changes mBounds will be updated. + * More details you can see {@link LoadingDrawable#onBoundsChange(Rect)} + */ + protected final Rect mBounds = new Rect(); - private long mDuration; private Drawable.Callback mCallback; private ValueAnimator mRenderAnimator; + protected long mDuration; + + protected float mWidth; + protected float mHeight; + public LoadingRenderer(Context context) { - setupDefaultParams(context); + initParams(context); setupAnimators(); } - public abstract void draw(Canvas canvas, Rect bounds); + @Deprecated + protected void draw(Canvas canvas, Rect bounds) { + } + + protected void draw(Canvas canvas) { + draw(canvas, mBounds); + } - public abstract void computeRender(float renderProgress); + protected abstract void computeRender(float renderProgress); - public abstract void setAlpha(int alpha); + protected abstract void setAlpha(int alpha); - public abstract void setColorFilter(ColorFilter cf); + protected abstract void setColorFilter(ColorFilter cf); - public abstract void reset(); + protected abstract void reset(); - public void start() { + protected void addRenderListener(Animator.AnimatorListener animatorListener) { + mRenderAnimator.addListener(animatorListener); + } + + void start() { reset(); - setDuration(mDuration); + mRenderAnimator.addUpdateListener(mAnimatorUpdateListener); + + mRenderAnimator.setRepeatCount(ValueAnimator.INFINITE); + mRenderAnimator.setDuration(mDuration); mRenderAnimator.start(); } - public void stop() { - mRenderAnimator.cancel(); + void stop() { + // if I just call mRenderAnimator.end(), + // it will always call the method onAnimationUpdate(ValueAnimator animation) + // why ? if you know why please send email to me (dinus_developer@163.com) + mRenderAnimator.removeUpdateListener(mAnimatorUpdateListener); + + mRenderAnimator.setRepeatCount(0); + mRenderAnimator.setDuration(0); + mRenderAnimator.end(); } - public boolean isRunning() { + boolean isRunning() { return mRenderAnimator.isRunning(); } - public void setCallback(Drawable.Callback callback) { + void setCallback(Drawable.Callback callback) { this.mCallback = callback; } - protected void invalidateSelf() { - mCallback.invalidateDrawable(null); + void setBounds(Rect bounds) { + mBounds.set(bounds); } - private void setupDefaultParams(Context context) { + private void initParams(Context context) { mWidth = DensityUtil.dip2px(context, DEFAULT_SIZE); mHeight = DensityUtil.dip2px(context, DEFAULT_SIZE); @@ -73,44 +111,14 @@ private void setupAnimators() { mRenderAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); mRenderAnimator.setRepeatCount(Animation.INFINITE); mRenderAnimator.setRepeatMode(Animation.RESTART); + mRenderAnimator.setDuration(mDuration); //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(); - } - }); - + mRenderAnimator.addUpdateListener(mAnimatorUpdateListener); } - protected void addRenderListener(Animator.AnimatorListener animatorListener) { - mRenderAnimator.addListener(animatorListener); - } - - 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; + private void invalidateSelf() { + mCallback.invalidateDrawable(null); } - public void setDuration(long duration) { - this.mDuration = duration; - mRenderAnimator.setDuration(mDuration); - } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRendererFactory.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRendererFactory.java index 45227db..59040b0 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRendererFactory.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/LoadingRendererFactory.java @@ -61,6 +61,7 @@ public static LoadingRenderer createLoadingRenderer(Context context, int loading if (parameterTypes != null && parameterTypes.length == 1 && parameterTypes[0].equals(Context.class)) { + constructor.setAccessible(true); return (LoadingRenderer) constructor.newInstance(context); } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/FishLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/FishLoadingRenderer.java index 7c6f63d..2c63d48 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/FishLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/FishLoadingRenderer.java @@ -70,7 +70,7 @@ public class FishLoadingRenderer extends LoadingRenderer { private int mColor; - public FishLoadingRenderer(Context context) { + private FishLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -91,7 +91,7 @@ private void init(Context context) { mColor = DEFAULT_COLOR; - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -103,7 +103,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mTempBounds; arcBounds.set(bounds); @@ -153,7 +153,7 @@ private float calculateRotateDegrees(float fishProgress) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (mRiverPath == null) { return; } @@ -169,17 +169,17 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { } @Override - public void reset() { + protected void reset() { } private Path createFishEyePath(float fishEyeCenterX, float fishEyeCenterY) { @@ -246,4 +246,17 @@ public float getInterpolation(float input) { return FISH_MOVE_POINTS[index]; } } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public FishLoadingRenderer build() { + FishLoadingRenderer loadingRenderer = new FishLoadingRenderer(mContext); + return loadingRenderer; + } + } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/GhostsEyeLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/GhostsEyeLoadingRenderer.java index dfd9a52..b13b2a8 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/GhostsEyeLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/animal/GhostsEyeLoadingRenderer.java @@ -65,7 +65,7 @@ public class GhostsEyeLoadingRenderer extends LoadingRenderer { private int mColor; - public GhostsEyeLoadingRenderer(Context context) { + private GhostsEyeLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -87,7 +87,7 @@ private void init(Context context) { mColor = DEFAULT_COLOR; - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -99,7 +99,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mTempBounds; arcBounds.set(bounds); @@ -120,7 +120,7 @@ public void draw(Canvas canvas, Rect bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (renderProgress <= LEFT_EYE_BALL_END_JUMP_OFFSET && renderProgress >= LEFT_EYE_CIRCLE$BALL_START_JUMP_UP_OFFSET) { float eyeCircle$BallJumpUpProgress = (renderProgress - LEFT_EYE_CIRCLE$BALL_START_JUMP_UP_OFFSET) / (LEFT_EYE_BALL_END_JUMP_OFFSET - LEFT_EYE_CIRCLE$BALL_START_JUMP_UP_OFFSET); mLeftEyeBallOffsetY = -mMaxEyeJumptDistance * EYE_BALL_INTERPOLATOR.getInterpolation(eyeCircle$BallJumpUpProgress); @@ -143,17 +143,17 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { } @Override - public void reset() { + protected void reset() { mLeftEyeBallOffsetY = 0.0f; mRightEyeBallOffsetY = 0.0f; mLeftEyeCircleOffsetY = 0.0f; @@ -245,4 +245,17 @@ public float getInterpolation(float input) { } } } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public GhostsEyeLoadingRenderer build() { + GhostsEyeLoadingRenderer loadingRenderer = new GhostsEyeLoadingRenderer(mContext); + return loadingRenderer; + } + } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/CollisionLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/CollisionLoadingRenderer.java index fc070d3..fef4662 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/CollisionLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/CollisionLoadingRenderer.java @@ -6,12 +6,9 @@ import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Paint; -import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; -import android.support.annotation.NonNull; -import android.util.DisplayMetrics; -import android.util.TypedValue; +import android.support.annotation.Size; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -23,175 +20,284 @@ public class CollisionLoadingRenderer extends LoadingRenderer { private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator(); private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); - private static final int CIRCLE_COUNT = 7; + private static final int MAX_ALPHA = 255; + private static final int OVAL_ALPHA = 64; - //the 2 * 2 is the left and right side offset - private static final float DEFAULT_WIDTH = 15.0f * (CIRCLE_COUNT + 2 * 2); - //the 2 * 2 is the top and bottom side offset - private static final float DEFAULT_HEIGHT = 15.0f * (1 + 2 * 2); + private static final int DEFAULT_BALL_COUNT = 7; + + private static final float DEFAULT_OVAL_HEIGHT = 1.5f; + private static final float DEFAULT_BALL_RADIUS = 7.5f; + private static final float DEFAULT_WIDTH = 15.0f * 11; + private static final float DEFAULT_HEIGHT = 15.0f * 4; - private static final float DURATION_OFFSET = 0.25f; private static final float START_LEFT_DURATION_OFFSET = 0.25f; private static final float START_RIGHT_DURATION_OFFSET = 0.5f; private static final float END_RIGHT_DURATION_OFFSET = 0.75f; private static final float END_LEFT_DURATION_OFFSET = 1.0f; - private static final float DEFAULT_STROKE_WIDTH = 2.5f; - private static final int[] DEFAULT_COLORS = new int[]{ - Color.RED, Color.GREEN + Color.parseColor("#FF28435D"), Color.parseColor("#FFC32720") }; private static final float[] DEFAULT_POSITIONS = new float[]{ 0.0f, 1.0f }; - private final Paint mPaint = new Paint(); - private final RectF mTempBounds = new RectF(); + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final RectF mOvalRect = new RectF(); + @Size(2) private int[] mColors; private float[] mPositions; - private float mEndXOffsetProgress; - private float mStartXOffsetProgress; + private float mOvalVerticalRadius; + + private float mBallRadius; + private float mBallCenterY; + private float mBallSideOffsets; + private float mBallMoveXOffsets; + private float mBallQuadCoefficient; + + private float mLeftBallMoveXOffsets; + private float mLeftBallMoveYOffsets; + private float mRightBallMoveXOffsets; + private float mRightBallMoveYOffsets; + + private float mLeftOvalShapeRate; + private float mRightOvalShapeRate; - private float mStrokeWidth; + private int mBallCount; - public CollisionLoadingRenderer(Context context) { + private CollisionLoadingRenderer(Context context) { super(context); init(context); + adjustParams(); setupPaint(); } private void init(Context context) { + mBallRadius = DensityUtil.dip2px(context, DEFAULT_BALL_RADIUS); mWidth = DensityUtil.dip2px(context, DEFAULT_WIDTH); mHeight = DensityUtil.dip2px(context, DEFAULT_HEIGHT); - mStrokeWidth = DensityUtil.dip2px(context, DEFAULT_STROKE_WIDTH); - } + mOvalVerticalRadius = DensityUtil.dip2px(context, DEFAULT_OVAL_HEIGHT); - private void setupPaint() { mColors = DEFAULT_COLORS; mPositions = DEFAULT_POSITIONS; - mPaint.setStrokeWidth(mStrokeWidth); - mPaint.setAntiAlias(true); + mBallCount = DEFAULT_BALL_COUNT; + + //mBallMoveYOffsets = mBallQuadCoefficient * mBallMoveXOffsets ^ 2 + // ==> if mBallMoveYOffsets == mBallMoveXOffsets + // ==> mBallQuadCoefficient = 1.0f / mBallMoveXOffsets; + mBallMoveXOffsets = 1.5f * (2 * mBallRadius); + mBallQuadCoefficient = 1.0f / mBallMoveXOffsets; + } + + private void adjustParams() { + mBallCenterY = mHeight / 2.0f; + mBallSideOffsets = (mWidth - mBallRadius * 2.0f * (mBallCount - 2)) / 2; + } + + private void setupPaint() { mPaint.setStyle(Paint.Style.FILL); + mPaint.setShader(new LinearGradient(mBallSideOffsets, 0, mWidth - mBallSideOffsets, 0, + mColors, mPositions, Shader.TileMode.CLAMP)); } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas) { int saveCount = canvas.save(); - RectF arcBounds = mTempBounds; - arcBounds.set(bounds); - - float cy = mHeight / 2; - float circleRadius = computeCircleRadius(arcBounds); - - float sideOffset = 2.0f * (2 * circleRadius); - float maxMoveOffset = 1.5f * (2 * circleRadius); - - LinearGradient gradient = new LinearGradient(arcBounds.left + sideOffset, 0, arcBounds.right - sideOffset, 0, - mColors, mPositions, Shader.TileMode.CLAMP); - mPaint.setShader(gradient); - - for (int i = 0; i < CIRCLE_COUNT; i++) { - if (i == 0 && mStartXOffsetProgress != 0) { - float xMoveOffset = maxMoveOffset * mStartXOffsetProgress; - // y = ax^2 --> if x = sideOffset, y = sideOffset ==> a = 1 / sideOffset - float yMoveOffset = (float) (Math.pow(xMoveOffset, 2) / maxMoveOffset); - canvas.drawCircle(circleRadius + sideOffset - xMoveOffset, cy - yMoveOffset, circleRadius, mPaint); - continue; - } + for (int i = 1; i < mBallCount - 1; i++) { + mPaint.setAlpha(MAX_ALPHA); + canvas.drawCircle(mBallRadius * (i * 2 - 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint); - if (i == CIRCLE_COUNT - 1 && mEndXOffsetProgress != 0) { - float xMoveOffset = maxMoveOffset * mEndXOffsetProgress; - // y = ax^2 --> if x = sideOffset, y = sideOffset / 2 ==> a = 1 / sideOffset - float yMoveOffset = (float) (Math.pow(xMoveOffset, 2) / maxMoveOffset); - canvas.drawCircle(circleRadius * (CIRCLE_COUNT * 2 - 1) + sideOffset + xMoveOffset, cy - yMoveOffset, circleRadius, mPaint); - continue; - } - - canvas.drawCircle(circleRadius * (i * 2 + 1) + sideOffset, cy, circleRadius, mPaint); + mOvalRect.set(mBallRadius * (i * 2 - 2) + mBallSideOffsets, mHeight - mOvalVerticalRadius * 2, + mBallRadius * (i * 2) + mBallSideOffsets, mHeight); + mPaint.setAlpha(OVAL_ALPHA); + canvas.drawOval(mOvalRect, mPaint); } - canvas.restoreToCount(saveCount); - } - - private float computeCircleRadius(RectF rectBounds) { - float width = rectBounds.width(); - float height = rectBounds.height(); + //draw the first ball + mPaint.setAlpha(MAX_ALPHA); + canvas.drawCircle(mBallSideOffsets - mBallRadius - mLeftBallMoveXOffsets, + mBallCenterY - mLeftBallMoveYOffsets, mBallRadius, mPaint); + + mOvalRect.set(mBallSideOffsets - mBallRadius - mBallRadius * mLeftOvalShapeRate - mLeftBallMoveXOffsets, + mHeight - mOvalVerticalRadius - mOvalVerticalRadius * mLeftOvalShapeRate, + mBallSideOffsets - mBallRadius + mBallRadius * mLeftOvalShapeRate - mLeftBallMoveXOffsets, + mHeight - mOvalVerticalRadius + mOvalVerticalRadius * mLeftOvalShapeRate); + mPaint.setAlpha(OVAL_ALPHA); + canvas.drawOval(mOvalRect, mPaint); + + //draw the last ball + mPaint.setAlpha(MAX_ALPHA); + canvas.drawCircle(mBallRadius * (mBallCount * 2 - 3) + mBallSideOffsets + mRightBallMoveXOffsets, + mBallCenterY - mRightBallMoveYOffsets, mBallRadius, mPaint); + + mOvalRect.set(mBallRadius * (mBallCount * 2 - 3) - mBallRadius * mRightOvalShapeRate + mBallSideOffsets + mRightBallMoveXOffsets, + mHeight - mOvalVerticalRadius - mOvalVerticalRadius * mRightOvalShapeRate, + mBallRadius * (mBallCount * 2 - 3) + mBallRadius * mRightOvalShapeRate + mBallSideOffsets + mRightBallMoveXOffsets, + mHeight - mOvalVerticalRadius + mOvalVerticalRadius * mRightOvalShapeRate); + mPaint.setAlpha(OVAL_ALPHA); + canvas.drawOval(mOvalRect, mPaint); - //CIRCLE_COUNT + 4 is the sliding distance of both sides - float radius = Math.min(width / (CIRCLE_COUNT + 4) / 2, height / 2); - return radius; + canvas.restoreToCount(saveCount); } @Override - public void computeRender(float renderProgress) { - - // Moving the start offset to left only occurs in the first 25% of a - // single ring animation + protected void computeRender(float renderProgress) { + // Moving the left ball to the left sides only occurs in the first 25% of a jump animation if (renderProgress <= START_LEFT_DURATION_OFFSET) { - float startLeftOffsetProgress = renderProgress / DURATION_OFFSET; - mStartXOffsetProgress = DECELERATE_INTERPOLATOR.getInterpolation(startLeftOffsetProgress); - - invalidateSelf(); + float startLeftOffsetProgress = renderProgress / START_LEFT_DURATION_OFFSET; + computeLeftBallMoveOffsets(DECELERATE_INTERPOLATOR.getInterpolation(startLeftOffsetProgress)); return; } - // Moving the start offset to left only occurs between 25% and 50% of a - // single ring animation + // Moving the left ball to the origin location only occurs between 25% and 50% of a jump ring animation if (renderProgress <= START_RIGHT_DURATION_OFFSET) { - float startRightOffsetProgress = (renderProgress - START_LEFT_DURATION_OFFSET) / DURATION_OFFSET; - mStartXOffsetProgress = ACCELERATE_INTERPOLATOR.getInterpolation(1.0f - startRightOffsetProgress); - - invalidateSelf(); + float startRightOffsetProgress = (renderProgress - START_LEFT_DURATION_OFFSET) / (START_RIGHT_DURATION_OFFSET - START_LEFT_DURATION_OFFSET); + computeLeftBallMoveOffsets(ACCELERATE_INTERPOLATOR.getInterpolation(1.0f - startRightOffsetProgress)); return; } - // Moving the end offset to right starts between 50% and 75% a single ring - // animation completes + // Moving the right ball to the right sides only occurs between 50% and 75% of a jump animation if (renderProgress <= END_RIGHT_DURATION_OFFSET) { - float endRightOffsetProgress = (renderProgress - START_RIGHT_DURATION_OFFSET) / DURATION_OFFSET; - mEndXOffsetProgress = DECELERATE_INTERPOLATOR.getInterpolation(endRightOffsetProgress); - - invalidateSelf(); + float endRightOffsetProgress = (renderProgress - START_RIGHT_DURATION_OFFSET) / (END_RIGHT_DURATION_OFFSET - START_RIGHT_DURATION_OFFSET); + computeRightBallMoveOffsets(DECELERATE_INTERPOLATOR.getInterpolation(endRightOffsetProgress)); return; } - // Moving the end offset to left starts after 75% of a single ring - // animation completes + // Moving the right ball to the origin location only occurs after 75% of a jump animation if (renderProgress <= END_LEFT_DURATION_OFFSET) { - float endRightOffsetProgress = (renderProgress - END_RIGHT_DURATION_OFFSET) / DURATION_OFFSET; - mEndXOffsetProgress = ACCELERATE_INTERPOLATOR.getInterpolation(1 - endRightOffsetProgress); - - invalidateSelf(); + float endRightOffsetProgress = (renderProgress - END_RIGHT_DURATION_OFFSET) / (END_LEFT_DURATION_OFFSET - END_RIGHT_DURATION_OFFSET); + computeRightBallMoveOffsets(ACCELERATE_INTERPOLATOR.getInterpolation(1 - endRightOffsetProgress)); return; } + + } + + private void computeLeftBallMoveOffsets(float progress) { + mRightBallMoveXOffsets = 0.0f; + mRightBallMoveYOffsets = 0.0f; + + mLeftOvalShapeRate = 1.0f - progress; + mLeftBallMoveXOffsets = mBallMoveXOffsets * progress; + mLeftBallMoveYOffsets = (float) (Math.pow(mLeftBallMoveXOffsets, 2) * mBallQuadCoefficient); + } + + private void computeRightBallMoveOffsets(float progress) { + mLeftBallMoveXOffsets = 0.0f; + mLeftBallMoveYOffsets = 0.0f; + + mRightOvalShapeRate = 1.0f - progress; + mRightBallMoveXOffsets = mBallMoveXOffsets * progress; + mRightBallMoveYOffsets = (float) (Math.pow(mRightBallMoveXOffsets, 2) * mBallQuadCoefficient); } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); } @Override - public void reset() { + protected void reset() { } - public void setColors(@NonNull int[] colors) { - mColors = colors; + private void apply(Builder builder) { + this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; + this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; + + this.mOvalVerticalRadius = builder.mOvalVerticalRadius > 0 ? builder.mOvalVerticalRadius : this.mOvalVerticalRadius; + this.mBallRadius = builder.mBallRadius > 0 ? builder.mBallRadius : this.mBallRadius; + this.mBallMoveXOffsets = builder.mBallMoveXOffsets > 0 ? builder.mBallMoveXOffsets : this.mBallMoveXOffsets; + this.mBallQuadCoefficient = builder.mBallQuadCoefficient > 0 ? builder.mBallQuadCoefficient : this.mBallQuadCoefficient; + this.mBallCount = builder.mBallCount > 0 ? builder.mBallCount : this.mBallCount; + + this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; + + this.mColors = builder.mColors != null ? builder.mColors : this.mColors; + + adjustParams(); + setupPaint(); } - public void setPositions(@NonNull float[] positions) { - mPositions = positions; + public static class Builder { + private Context mContext; + + private int mWidth; + private int mHeight; + + private float mOvalVerticalRadius; + + private int mBallCount; + private float mBallRadius; + private float mBallMoveXOffsets; + private float mBallQuadCoefficient; + + private int mDuration; + + @Size(2) + private int[] mColors; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public Builder setWidth(int width) { + this.mWidth = width; + return this; + } + + public Builder setHeight(int height) { + this.mHeight = height; + return this; + } + + public Builder setOvalVerticalRadius(int ovalVerticalRadius) { + this.mOvalVerticalRadius = ovalVerticalRadius; + return this; + } + + public Builder setBallRadius(int ballRadius) { + this.mBallRadius = ballRadius; + return this; + } + + public Builder setBallMoveXOffsets(int ballMoveXOffsets) { + this.mBallMoveXOffsets = ballMoveXOffsets; + return this; + } + + public Builder setBallQuadCoefficient(int ballQuadCoefficient) { + this.mBallQuadCoefficient = ballQuadCoefficient; + return this; + } + + public Builder setBallCount(int ballCount) { + this.mBallCount = ballCount; + return this; + } + + public Builder setColors(@Size(2) int[] colors) { + this.mColors = colors; + return this; + } + + public Builder setDuration(int duration) { + this.mDuration = duration; + return this; + } + + public CollisionLoadingRenderer build() { + CollisionLoadingRenderer loadingRenderer = new CollisionLoadingRenderer(mContext); + loadingRenderer.apply(this); + return loadingRenderer; + } } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/DanceLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/DanceLoadingRenderer.java index cef6131..9d72c9a 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/DanceLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/DanceLoadingRenderer.java @@ -83,7 +83,7 @@ public class DanceLoadingRenderer extends LoadingRenderer { private int mColor; private int mArcColor; - public DanceLoadingRenderer(Context context) { + private DanceLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -95,8 +95,8 @@ private void init(Context context) { mDanceBallRadius = DensityUtil.dip2px(context, DEFAULT_DANCE_BALL_RADIUS); setColor(DEFAULT_COLOR); - setInsets((int) getWidth(), (int) getHeight()); - setDuration(ANIMATION_DURATION); + setInsets((int) mWidth, (int) mHeight); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -106,7 +106,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); mTempBounds.set(bounds); @@ -149,7 +149,7 @@ public void draw(Canvas canvas, Rect bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { float radius = Math.min(mCurrentBounds.height(), mCurrentBounds.width()) / 2.0f; //the origin coordinate is the centerLeft of the field mCurrentBounds float originCoordinateX = mCurrentBounds.left; @@ -259,47 +259,47 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { mScale = 1.0f; mRotation = 0; } - public void setColor(int color) { + private void setColor(int color) { mColor = color; mArcColor = halfAlphaColor(mColor); } - public void setRotation(float rotation) { + private void setRotation(float rotation) { mRotation = rotation; - invalidateSelf(); + } - public void setDanceBallRadius(float danceBallRadius) { + private void setDanceBallRadius(float danceBallRadius) { this.mDanceBallRadius = danceBallRadius; - invalidateSelf(); + } - public float getDanceBallRadius() { + private float getDanceBallRadius() { return mDanceBallRadius; } - public float getRotation() { + private float getRotation() { return mRotation; } - public void setInsets(int width, int height) { + private void setInsets(int width, int height) { final float minEdge = (float) Math.min(width, height); float insets; if (mCenterRadius <= 0 || minEdge < 0) { @@ -321,4 +321,17 @@ private int halfAlphaColor(int colorValue) { | (startG << 8) | startB; } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public DanceLoadingRenderer build() { + DanceLoadingRenderer loadingRenderer = new DanceLoadingRenderer(mContext); + return loadingRenderer; + } + } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/GuardLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/GuardLoadingRenderer.java index 3ce439a..7a1c971 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/GuardLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/GuardLoadingRenderer.java @@ -65,10 +65,10 @@ public class GuardLoadingRenderer extends LoadingRenderer { private PathMeasure mPathMeasure; - public GuardLoadingRenderer(Context context) { + private GuardLoadingRenderer(Context context) { super(context); - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; init(context); setupPaint(); } @@ -88,11 +88,11 @@ private void setupPaint() { mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); - setInsets((int) getWidth(), (int) getHeight()); + setInsets((int) mWidth, (int) mHeight); } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { RectF arcBounds = mTempBounds; arcBounds.set(bounds); arcBounds.inset(mStrokeInset, mStrokeInset); @@ -129,7 +129,7 @@ public void draw(Canvas canvas, Rect bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (renderProgress <= START_TRIM_DURATION_OFFSET) { final float startTrimProgress = (renderProgress) / START_TRIM_DURATION_OFFSET; mEndTrim = -MATERIAL_INTERPOLATOR.getInterpolation(startTrimProgress); @@ -180,19 +180,19 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { mScale = 1.0f; mEndTrim = 0.0f; mRotation = 0.0f; @@ -200,10 +200,6 @@ public void reset() { mWaveProgress = 1.0f; } - public void setColor(int color) { - mColor = color; - } - private Path createSkipBallPath() { float radius = Math.min(mCurrentBounds.width(), mCurrentBounds.height()) / 2.0f; float radiusPow2 = (float) Math.pow(radius, 2.0f); @@ -237,46 +233,7 @@ private Path createSkipBallPath() { return path; } - public void setStartTrim(float startTrim) { - mStartTrim = startTrim; - invalidateSelf(); - } - - public float getStartTrim() { - return mStartTrim; - } - - public void setEndTrim(float endTrim) { - mEndTrim = endTrim; - invalidateSelf(); - } - - public float getEndTrim() { - return mEndTrim; - } - - public void setRotation(float rotation) { - mRotation = rotation; - invalidateSelf(); - } - - public void setScale(float scale) { - this.mScale = scale; - } - - public float getScale() { - return mScale; - } - - public void setSkipBallSize(float skipBallSize) { - this.mSkipBallSize = skipBallSize; - } - - public float getSkipBallSize() { - return mSkipBallSize; - } - - public void setInsets(int width, int height) { + private void setInsets(int width, int height) { final float minEdge = (float) Math.min(width, height); float insets; if (mCenterRadius <= 0 || minEdge < 0) { @@ -286,4 +243,17 @@ public void setInsets(int width, int height) { } mStrokeInset = insets; } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public GuardLoadingRenderer build() { + GuardLoadingRenderer loadingRenderer = new GuardLoadingRenderer(mContext); + return loadingRenderer; + } + } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/SwapLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/SwapLoadingRenderer.java index 423df50..c759723 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/SwapLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/jump/SwapLoadingRenderer.java @@ -5,155 +5,223 @@ import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.RectF; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.util.DisplayMetrics; -import android.util.TypedValue; +import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import app.dinus.com.loadingdrawable.DensityUtil; import app.dinus.com.loadingdrawable.render.LoadingRenderer; public class SwapLoadingRenderer extends LoadingRenderer { - private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator(); + private static final Interpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator(); private static final long ANIMATION_DURATION = 2500; - private static final int CIRCLE_COUNT = 5; + private static final int DEFAULT_CIRCLE_COUNT = 5; - //(CIRCLE_COUNT - 1) / 2 is the Circle interval width; the 2 * 2 is the both side inset - private static final float DEFAULT_WIDTH = 15.0f * (CIRCLE_COUNT + (CIRCLE_COUNT - 1) / 2 + 2 * 2); - //the 2 * 2 is the both side inset - private static final float DEFAULT_HEIGHT = 15.0f * (1 + 2 * 2); + private static final float DEFAULT_BALL_RADIUS = 7.5f; + private static final float DEFAULT_WIDTH = 15.0f * 11; + private static final float DEFAULT_HEIGHT = 15.0f * 5; private static final float DEFAULT_STROKE_WIDTH = 1.5f; private static final int DEFAULT_COLOR = Color.WHITE; - private final Paint mPaint = new Paint(); - private final RectF mTempBounds = new RectF(); + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private int mColor; private int mSwapIndex; + private int mBallCount; - private float mSwapThreshold; - private float mSwapXOffsetProgress; + private float mBallSideOffsets; + private float mBallCenterY; + private float mBallRadius; + private float mBallInterval; + private float mSwapBallOffsetX; + private float mSwapBallOffsetY; + private float mASwapThreshold; private float mStrokeWidth; - public SwapLoadingRenderer(Context context) { + private SwapLoadingRenderer(Context context) { super(context); - setDuration(ANIMATION_DURATION); init(context); + adjustParams(); setupPaint(); } private void init(Context context) { mWidth = DensityUtil.dip2px(context, DEFAULT_WIDTH); mHeight = DensityUtil.dip2px(context, DEFAULT_HEIGHT); + mBallRadius = DensityUtil.dip2px(context, DEFAULT_BALL_RADIUS); mStrokeWidth = DensityUtil.dip2px(context, DEFAULT_STROKE_WIDTH); - mSwapThreshold = 1.0f / CIRCLE_COUNT; + mColor = DEFAULT_COLOR; + mDuration = ANIMATION_DURATION; + mBallCount = DEFAULT_CIRCLE_COUNT; + + mBallInterval = mBallRadius; } - private void setupPaint() { - mColor = DEFAULT_COLOR; + private void adjustParams() { + mBallCenterY = mHeight / 2.0f; + mBallSideOffsets = (mWidth - mBallRadius * 2 * mBallCount - mBallInterval * (mBallCount - 1)) / 2.0f; - mPaint.setAntiAlias(true); - mPaint.setStrokeWidth(mStrokeWidth); - mPaint.setStyle(Paint.Style.FILL); + mASwapThreshold = 1.0f / mBallCount; } - @Override - public void draw(Canvas canvas, Rect bounds) { + private void setupPaint() { mPaint.setColor(mColor); + mPaint.setStrokeWidth(mStrokeWidth); + } + @Override + protected void draw(Canvas canvas) { int saveCount = canvas.save(); - RectF arcBounds = mTempBounds; - arcBounds.set(bounds); - - float cy = mHeight / 2; - float circleRadius = computeCircleRadius(arcBounds); - - float sideOffset = 2.0f * (2 * circleRadius); - float intervalWidth = circleRadius; - - float circleDiameter = mSwapIndex == CIRCLE_COUNT - 1 - ? circleRadius * (CIRCLE_COUNT - 1) * 3 - : circleRadius * 3; - - //x^2 + y^2 = (3 * circleRadius / 2) ^ 2 - float xMoveOffset = mSwapIndex == CIRCLE_COUNT - 1 - ? -mSwapXOffsetProgress * circleDiameter - : mSwapXOffsetProgress * circleDiameter; - //the y axial symmetry - float xCoordinate = mSwapIndex == CIRCLE_COUNT - 1 - ? xMoveOffset + circleDiameter / 2 - : xMoveOffset - circleDiameter / 2; - float yMoveOffset = (float) (mSwapIndex % 2 == 0 && mSwapIndex != CIRCLE_COUNT - 1 - ? Math.sqrt(Math.pow(circleDiameter / 2, 2.0f) - Math.pow(xCoordinate, 2.0f)) - : -Math.sqrt(Math.pow(circleDiameter / 2, 2.0f) - Math.pow(xCoordinate, 2.0f))); - - for (int i = 0; i < CIRCLE_COUNT; i++) { + for (int i = 0; i < mBallCount; i++) { if (i == mSwapIndex) { mPaint.setStyle(Paint.Style.FILL); - canvas.drawCircle(circleRadius * (i * 2 + 1) + sideOffset + i * intervalWidth + xMoveOffset - , cy - yMoveOffset, circleRadius - mStrokeWidth / 2, mPaint); - } else if (i == (mSwapIndex + 1) % CIRCLE_COUNT) { + canvas.drawCircle(mBallSideOffsets + mBallRadius * (i * 2 + 1) + i * mBallInterval + mSwapBallOffsetX + , mBallCenterY - mSwapBallOffsetY, mBallRadius, mPaint); + } else if (i == (mSwapIndex + 1) % mBallCount) { mPaint.setStyle(Paint.Style.STROKE); - - canvas.drawCircle(circleRadius * (i * 2 + 1) + sideOffset + i * intervalWidth - xMoveOffset - , cy + yMoveOffset, circleRadius - mStrokeWidth / 2, mPaint); + canvas.drawCircle(mBallSideOffsets + mBallRadius * (i * 2 + 1) + i * mBallInterval - mSwapBallOffsetX + , mBallCenterY + mSwapBallOffsetY, mBallRadius - mStrokeWidth / 2, mPaint); } else { mPaint.setStyle(Paint.Style.STROKE); - - canvas.drawCircle(circleRadius * (i * 2 + 1) + sideOffset + i * intervalWidth, cy, - circleRadius - mStrokeWidth / 2, mPaint); + canvas.drawCircle(mBallSideOffsets + mBallRadius * (i * 2 + 1) + i * mBallInterval, mBallCenterY + , mBallRadius - mStrokeWidth / 2, mPaint); } - } canvas.restoreToCount(saveCount); } - private float computeCircleRadius(RectF rectBounds) { - float width = rectBounds.width(); - float height = rectBounds.height(); + @Override + protected void computeRender(float renderProgress) { + mSwapIndex = (int) (renderProgress / mASwapThreshold); - //CIRCLE_COUNT + 4 is the sliding distance of both sides - float radius = Math.min(width / (CIRCLE_COUNT + (CIRCLE_COUNT - 1) / 2 + 2 * 2) / 2, height / 2); - return radius; - } + // Swap trace : x^2 + y^2 = r ^ 2 + float swapTraceProgress = ACCELERATE_DECELERATE_INTERPOLATOR.getInterpolation( + (renderProgress - mSwapIndex * mASwapThreshold) / mASwapThreshold); - @Override - public void computeRender(float renderProgress) { - mSwapIndex = (int) (renderProgress / mSwapThreshold); - mSwapXOffsetProgress = MATERIAL_INTERPOLATOR.getInterpolation( - (renderProgress - mSwapIndex * mSwapThreshold) / mSwapThreshold); + float swapTraceRadius = mSwapIndex == mBallCount - 1 + ? (mBallRadius * 2 * (mBallCount - 1) + mBallInterval * (mBallCount - 1)) / 2 + : (mBallRadius * 2 + mBallInterval) / 2; + + // Calculate the X offset of the swap ball + mSwapBallOffsetX = mSwapIndex == mBallCount - 1 + ? -swapTraceProgress * swapTraceRadius * 2 + : swapTraceProgress * swapTraceRadius * 2; + + // if mSwapIndex == mBallCount - 1 then (swapTraceRadius, swapTraceRadius) as the origin of coordinates + // else (-swapTraceRadius, -swapTraceRadius) as the origin of coordinates + float xCoordinate = mSwapIndex == mBallCount - 1 + ? mSwapBallOffsetX + swapTraceRadius + : mSwapBallOffsetX - swapTraceRadius; + + // Calculate the Y offset of the swap ball + mSwapBallOffsetY = (float) (mSwapIndex % 2 == 0 && mSwapIndex != mBallCount - 1 + ? Math.sqrt(Math.pow(swapTraceRadius, 2.0f) - Math.pow(xCoordinate, 2.0f)) + : -Math.sqrt(Math.pow(swapTraceRadius, 2.0f) - Math.pow(xCoordinate, 2.0f))); - invalidateSelf(); } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); } @Override - public void reset() { + protected void reset() { } - public void setColor(int color) { - mColor = color; + private void apply(Builder builder) { + this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; + this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; + this.mStrokeWidth = builder.mStrokeWidth > 0 ? builder.mStrokeWidth : this.mStrokeWidth; + + this.mBallRadius = builder.mBallRadius > 0 ? builder.mBallRadius : this.mBallRadius; + this.mBallInterval = builder.mBallInterval > 0 ? builder.mBallInterval : this.mBallInterval; + this.mBallCount = builder.mBallCount > 0 ? builder.mBallCount : this.mBallCount; + + this.mColor = builder.mColor != 0 ? builder.mColor : this.mColor; + + this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; + + adjustParams(); + setupPaint(); + } + + public static class Builder { + private Context mContext; + + private int mWidth; + private int mHeight; + private int mStrokeWidth; + + private int mBallCount; + private int mBallRadius; + private int mBallInterval; + + private int mDuration; + + private int mColor; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public Builder setWidth(int width) { + this.mWidth = width; + return this; + } + + public Builder setHeight(int height) { + this.mHeight = height; + return this; + } + + public Builder setStrokeWidth(int strokeWidth) { + this.mStrokeWidth = strokeWidth; + return this; + } + + public Builder setBallRadius(int ballRadius) { + this.mBallRadius = ballRadius; + return this; + } + + public Builder setBallInterval(int ballInterval) { + this.mBallInterval = ballInterval; + return this; + } + + public Builder setBallCount(int ballCount) { + this.mBallCount = ballCount; + return this; + } + + public Builder setColor(int color) { + this.mColor = color; + return this; + } + + public Builder setDuration(int duration) { + this.mDuration = duration; + return this; + } + + public SwapLoadingRenderer build() { + SwapLoadingRenderer loadingRenderer = new SwapLoadingRenderer(mContext); + loadingRenderer.apply(this); + return loadingRenderer; + } } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/GearLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/GearLoadingRenderer.java index ac5182d..b1f4c00 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/GearLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/GearLoadingRenderer.java @@ -7,19 +7,16 @@ import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; -import android.graphics.Rect; import android.graphics.RectF; -import android.util.DisplayMetrics; +import android.support.annotation.IntRange; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; import app.dinus.com.loadingdrawable.DensityUtil; import app.dinus.com.loadingdrawable.render.LoadingRenderer; public class GearLoadingRenderer extends LoadingRenderer { - private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator(); private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); @@ -28,10 +25,9 @@ public class GearLoadingRenderer extends LoadingRenderer { private static final int MAX_ALPHA = 255; private static final int DEGREE_360 = 360; - private static final float MIN_SWIPE_DEGREE = 0.1f; - private static final float MAX_SWIPE_DEGREES = 0.17f * DEGREE_360; + private static final int DEFAULT_GEAR_SWIPE_DEGREES = 60; + private static final float FULL_GROUP_ROTATION = 3.0f * DEGREE_360; - private static final float MAX_ROTATION_INCREMENT = 0.25f * DEGREE_360; private static final float START_SCALE_DURATION_OFFSET = 0.3f; private static final float START_TRIM_DURATION_OFFSET = 0.5f; @@ -63,7 +59,10 @@ public void onAnimationStart(Animator animation) { } }; - private int mCurrentColor; + private int mColor; + + private int mGearCount; + private int mGearSwipeDegrees; private float mStrokeInset; @@ -74,15 +73,13 @@ public void onAnimationStart(Animator animation) { private float mEndDegrees; private float mStartDegrees; private float mSwipeDegrees; - private float mRotationIncrement; private float mOriginEndDegrees; private float mOriginStartDegrees; - private float mOriginRotationIncrement; private float mStrokeWidth; private float mCenterRadius; - public GearLoadingRenderer(Context context) { + private GearLoadingRenderer(Context context) { super(context); init(context); @@ -94,7 +91,10 @@ private void init(Context context) { mStrokeWidth = DensityUtil.dip2px(context, DEFAULT_STROKE_WIDTH); mCenterRadius = DensityUtil.dip2px(context, DEFAULT_CENTER_RADIUS); - mCurrentColor = DEFAULT_COLOR; + mColor = DEFAULT_COLOR; + + mGearCount = GEAR_COUNT; + mGearSwipeDegrees = DEFAULT_GEAR_SWIPE_DEGREES; } private void setupPaint() { @@ -103,118 +103,185 @@ private void setupPaint() { mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); - setInsets((int) getWidth(), (int) getHeight()); + initStrokeInset(mWidth, mHeight); } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas) { int saveCount = canvas.save(); - canvas.rotate(mGroupRotation, bounds.exactCenterX(), bounds.exactCenterY()); - RectF arcBounds = mTempBounds; - arcBounds.set(bounds); - arcBounds.inset(mStrokeInset, mStrokeInset); + mTempBounds.set(mBounds); + mTempBounds.inset(mStrokeInset, mStrokeInset); + mTempBounds.inset(mTempBounds.width() * (1.0f - mScale) / 2.0f, mTempBounds.width() * (1.0f - mScale) / 2.0f); - arcBounds.inset(arcBounds.width() * (1.0f - mScale) / 2.0f, arcBounds.width() * (1.0f - mScale) / 2.0f); + canvas.rotate(mGroupRotation, mTempBounds.centerX(), mTempBounds.centerY()); - mPaint.setColor(mCurrentColor); + mPaint.setColor(mColor); mPaint.setAlpha((int) (MAX_ALPHA * mScale)); mPaint.setStrokeWidth(mStrokeWidth * mScale); - for (int i = 0; i < GEAR_COUNT; i++) { - canvas.drawArc(arcBounds, mStartDegrees + DEGREE_360 / GEAR_COUNT * i, mSwipeDegrees, false, mPaint); + + if (mSwipeDegrees != 0) { + for (int i = 0; i < mGearCount; i++) { + canvas.drawArc(mTempBounds, mStartDegrees + DEGREE_360 / mGearCount * i, mSwipeDegrees, false, mPaint); + } } canvas.restoreToCount(saveCount); } @Override - public void computeRender(float renderProgress) { - // Scaling up the start size only occurs in the first 20% of a - // single ring animation + protected void computeRender(float renderProgress) { + // Scaling up the start size only occurs in the first 20% of a single ring animation if (renderProgress <= START_SCALE_DURATION_OFFSET) { float startScaleProgress = (renderProgress) / START_SCALE_DURATION_OFFSET; mScale = DECELERATE_INTERPOLATOR.getInterpolation(startScaleProgress); } - // Moving the start trim only occurs between 20% to 50% of a - // single ring animation + // Moving the start trim only occurs between 20% to 50% of a single ring animation if (renderProgress <= START_TRIM_DURATION_OFFSET && renderProgress > START_SCALE_DURATION_OFFSET) { float startTrimProgress = (renderProgress - START_SCALE_DURATION_OFFSET) / (START_TRIM_DURATION_OFFSET - START_SCALE_DURATION_OFFSET); - mStartDegrees = mOriginStartDegrees + MAX_SWIPE_DEGREES * LINEAR_INTERPOLATOR.getInterpolation(startTrimProgress); + mStartDegrees = mOriginStartDegrees + mGearSwipeDegrees * startTrimProgress; } - // Moving the end trim starts between 50% to 80% of a single ring - // animation completes + // Moving the end trim starts between 50% to 80% of a single ring animation if (renderProgress <= END_TRIM_DURATION_OFFSET && renderProgress > START_TRIM_DURATION_OFFSET) { float endTrimProgress = (renderProgress - START_TRIM_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_TRIM_DURATION_OFFSET); - mEndDegrees = mOriginEndDegrees + MAX_SWIPE_DEGREES * LINEAR_INTERPOLATOR.getInterpolation(endTrimProgress); + mEndDegrees = mOriginEndDegrees + mGearSwipeDegrees * endTrimProgress; } - // Scaling down the end size starts after 80% of a single ring - // animation completes + // Scaling down the end size starts after 80% of a single ring animation if (renderProgress > END_TRIM_DURATION_OFFSET) { float endScaleProgress = (renderProgress - END_TRIM_DURATION_OFFSET) / (END_SCALE_DURATION_OFFSET - END_TRIM_DURATION_OFFSET); mScale = 1.0f - ACCELERATE_INTERPOLATOR.getInterpolation(endScaleProgress); } - if (Math.abs(mEndDegrees - mStartDegrees) > MIN_SWIPE_DEGREE) { - mSwipeDegrees = mEndDegrees - mStartDegrees; - } - if (renderProgress <= END_TRIM_DURATION_OFFSET && renderProgress > START_SCALE_DURATION_OFFSET) { float rotateProgress = (renderProgress - START_SCALE_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_SCALE_DURATION_OFFSET); mGroupRotation = ((FULL_GROUP_ROTATION / NUM_POINTS) * rotateProgress) + (FULL_GROUP_ROTATION * (mRotationCount / NUM_POINTS)); - mRotationIncrement = mOriginRotationIncrement + (MAX_ROTATION_INCREMENT * rotateProgress); + } + + if (Math.abs(mEndDegrees - mStartDegrees) > 0) { + mSwipeDegrees = mEndDegrees - mStartDegrees; } } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); } @Override - public void reset() { + protected void reset() { resetOriginals(); } - public void setColor(int color) { - mCurrentColor = color; - } - - private void setInsets(int width, int height) { - final float minEdge = (float) Math.min(width, height); - float insets; - if (mCenterRadius <= 0 || minEdge < 0) { - insets = (float) Math.ceil(mStrokeWidth / 2.0f); - } else { - insets = minEdge / 2.0f - mCenterRadius; - } - mStrokeInset = insets; + private void initStrokeInset(float width, float height) { + float minSize = Math.min(width, height); + float strokeInset = minSize / 2.0f - mCenterRadius; + float minStrokeInset = (float) Math.ceil(mStrokeWidth / 2.0f); + mStrokeInset = strokeInset < minStrokeInset ? minStrokeInset : strokeInset; } private void storeOriginals() { mOriginEndDegrees = mEndDegrees; - mOriginStartDegrees = mStartDegrees; - mOriginRotationIncrement = mRotationIncrement; + mOriginStartDegrees = mEndDegrees; } private void resetOriginals() { mOriginEndDegrees = 0; mOriginStartDegrees = 0; - mOriginRotationIncrement = 0; mEndDegrees = 0; mStartDegrees = 0; - mRotationIncrement = 0; - mSwipeDegrees = MIN_SWIPE_DEGREE; + mSwipeDegrees = 1; + } + + private void apply(Builder builder) { + this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; + this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; + this.mStrokeWidth = builder.mStrokeWidth > 0 ? builder.mStrokeWidth : this.mStrokeWidth; + this.mCenterRadius = builder.mCenterRadius > 0 ? builder.mCenterRadius : this.mCenterRadius; + + this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; + + this.mColor = builder.mColor != 0 ? builder.mColor : this.mColor; + + this.mGearCount = builder.mGearCount > 0 ? builder.mGearCount : this.mGearCount; + this.mGearSwipeDegrees = builder.mGearSwipeDegrees > 0 ? builder.mGearSwipeDegrees : this.mGearSwipeDegrees; + + setupPaint(); + initStrokeInset(this.mWidth, this.mHeight); + } + + public static class Builder { + private Context mContext; + + private int mWidth; + private int mHeight; + private int mStrokeWidth; + private int mCenterRadius; + + private int mDuration; + + private int mColor; + + private int mGearCount; + private int mGearSwipeDegrees; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public Builder setWidth(int width) { + this.mWidth = width; + return this; + } + + public Builder setHeight(int height) { + this.mHeight = height; + return this; + } + + public Builder setStrokeWidth(int strokeWidth) { + this.mStrokeWidth = strokeWidth; + return this; + } + + public Builder setCenterRadius(int centerRadius) { + this.mCenterRadius = centerRadius; + return this; + } + + public Builder setDuration(int duration) { + this.mDuration = duration; + return this; + } + + public Builder setColor(int color) { + this.mColor = color; + return this; + } + + public Builder setGearCount(int gearCount) { + this.mGearCount = gearCount; + return this; + } + + public Builder setGearSwipeDegrees(@IntRange(from = 0, to = 360) int gearSwipeDegrees) { + this.mGearSwipeDegrees = gearSwipeDegrees; + return this; + } + + public GearLoadingRenderer build() { + GearLoadingRenderer loadingRenderer = new GearLoadingRenderer(mContext); + loadingRenderer.apply(this); + return loadingRenderer; + } } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/LevelLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/LevelLoadingRenderer.java index a38534e..208699f 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/LevelLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/LevelLoadingRenderer.java @@ -9,8 +9,8 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.support.annotation.Size; import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.util.DisplayMetrics; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -28,13 +28,10 @@ public class LevelLoadingRenderer extends LoadingRenderer { private static final int NUM_POINTS = 5; private static final int DEGREE_360 = 360; - private static final float MIN_SWIPE_DEGREE = 0.1f; private static final float MAX_SWIPE_DEGREES = 0.8f * DEGREE_360; private static final float FULL_GROUP_ROTATION = 3.0f * DEGREE_360; - private static final float MAX_ROTATION_INCREMENT = 0.25f * DEGREE_360; - private static final float LEVEL2_SWEEP_ANGLE_OFFSET = 7.0f / 8.0f; - private static final float LEVEL3_SWEEP_ANGLE_OFFSET = 5.0f / 8.0f; + private static final float[] LEVEL_SWEEP_ANGLE_OFFSETS = new float[]{1.0f, 7.0f / 8.0f, 5.0f / 8.0f}; private static final float START_TRIM_DURATION_OFFSET = 0.5f; private static final float END_TRIM_DURATION_OFFSET = 1.0f; @@ -42,7 +39,8 @@ public class LevelLoadingRenderer extends LoadingRenderer { private static final float DEFAULT_CENTER_RADIUS = 12.5f; private static final float DEFAULT_STROKE_WIDTH = 2.5f; - private static final int DEFAULT_COLOR = Color.WHITE; + private static final int[] DEFAULT_LEVEL_COLORS = new int[]{Color.parseColor("#55ffffff"), + Color.parseColor("#b1ffffff"), Color.parseColor("#ffffffff")}; private final Paint mPaint = new Paint(); private final RectF mTempBounds = new RectF(); @@ -64,9 +62,10 @@ public void onAnimationStart(Animator animation) { } }; - private int mLevel1Color; - private int mLevel2Color; - private int mLevel3Color; + @Size(3) + private int[] mLevelColors; + @Size(3) + private float[] mLevelSwipeDegrees; private float mStrokeInset; @@ -75,189 +74,226 @@ public void onAnimationStart(Animator animation) { private float mEndDegrees; private float mStartDegrees; - private float mLevel1SwipeDegrees; - private float mLevel2SwipeDegrees; - private float mLevel3SwipeDegrees; - private float mRotationIncrement; private float mOriginEndDegrees; private float mOriginStartDegrees; - private float mOriginRotationIncrement; private float mStrokeWidth; private float mCenterRadius; - public LevelLoadingRenderer(Context context) { + private LevelLoadingRenderer(Context context) { super(context); init(context); setupPaint(); addRenderListener(mAnimatorListener); } - + private void init(Context context) { mStrokeWidth = DensityUtil.dip2px(context, DEFAULT_STROKE_WIDTH); mCenterRadius = DensityUtil.dip2px(context, DEFAULT_CENTER_RADIUS); + + mLevelSwipeDegrees = new float[3]; + mLevelColors = DEFAULT_LEVEL_COLORS; } - + private void setupPaint() { - mLevel1Color = oneThirdAlphaColor(DEFAULT_COLOR); - mLevel2Color = twoThirdAlphaColor(DEFAULT_COLOR); - mLevel3Color = DEFAULT_COLOR; mPaint.setAntiAlias(true); mPaint.setStrokeWidth(mStrokeWidth); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); - setInsets((int) getWidth(), (int) getHeight()); + initStrokeInset((int) mWidth, (int) mHeight); } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas) { int saveCount = canvas.save(); - canvas.rotate(mGroupRotation, bounds.exactCenterX(), bounds.exactCenterY()); - RectF arcBounds = mTempBounds; - arcBounds.set(bounds); - arcBounds.inset(mStrokeInset, mStrokeInset); + mTempBounds.set(mBounds); + mTempBounds.inset(mStrokeInset, mStrokeInset); + canvas.rotate(mGroupRotation, mTempBounds.centerX(), mTempBounds.centerY()); - mPaint.setColor(mLevel1Color); - canvas.drawArc(arcBounds, mEndDegrees, mLevel1SwipeDegrees, false, mPaint); - mPaint.setColor(mLevel2Color); - canvas.drawArc(arcBounds, mEndDegrees, mLevel2SwipeDegrees, false, mPaint); - mPaint.setColor(mLevel3Color); - canvas.drawArc(arcBounds, mEndDegrees, mLevel3SwipeDegrees, false, mPaint); + for (int i = 0; i < 3; i++) { + if (mLevelSwipeDegrees[i] != 0) { + mPaint.setColor(mLevelColors[i]); + canvas.drawArc(mTempBounds, mEndDegrees, mLevelSwipeDegrees[i], false, mPaint); + } + } canvas.restoreToCount(saveCount); } @Override - public void computeRender(float renderProgress) { - // Moving the start trim only occurs in the first 50% of a - // single ring animation + protected void computeRender(float renderProgress) { + // Moving the start trim only occurs in the first 50% of a single ring animation if (renderProgress <= START_TRIM_DURATION_OFFSET) { float startTrimProgress = (renderProgress) / START_TRIM_DURATION_OFFSET; mStartDegrees = mOriginStartDegrees + MAX_SWIPE_DEGREES * MATERIAL_INTERPOLATOR.getInterpolation(startTrimProgress); - float mSwipeDegrees = MIN_SWIPE_DEGREE; - if (Math.abs(mEndDegrees - mStartDegrees) > MIN_SWIPE_DEGREE) { - mSwipeDegrees = mEndDegrees - mStartDegrees; - } + float mSwipeDegrees = mEndDegrees - mStartDegrees; float levelSwipeDegreesProgress = Math.abs(mSwipeDegrees) / MAX_SWIPE_DEGREES; float level1Increment = DECELERATE_INTERPOLATOR.getInterpolation(levelSwipeDegreesProgress) - LINEAR_INTERPOLATOR.getInterpolation(levelSwipeDegreesProgress); float level3Increment = ACCELERATE_INTERPOLATOR.getInterpolation(levelSwipeDegreesProgress) - LINEAR_INTERPOLATOR.getInterpolation(levelSwipeDegreesProgress); - mLevel1SwipeDegrees = -mSwipeDegrees * (1 + level1Increment); - mLevel2SwipeDegrees = -mSwipeDegrees * LEVEL2_SWEEP_ANGLE_OFFSET; - mLevel3SwipeDegrees = -mSwipeDegrees * LEVEL3_SWEEP_ANGLE_OFFSET * (1 + level3Increment); + mLevelSwipeDegrees[0] = -mSwipeDegrees * LEVEL_SWEEP_ANGLE_OFFSETS[0] * (1.0f + level1Increment); + mLevelSwipeDegrees[1] = -mSwipeDegrees * LEVEL_SWEEP_ANGLE_OFFSETS[1] * 1.0f; + mLevelSwipeDegrees[2] = -mSwipeDegrees * LEVEL_SWEEP_ANGLE_OFFSETS[2] * (1.0f + level3Increment); } - // Moving the end trim starts after 50% of a single ring - // animation completes + // Moving the end trim starts after 50% of a single ring animation if (renderProgress > START_TRIM_DURATION_OFFSET) { float endTrimProgress = (renderProgress - START_TRIM_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_TRIM_DURATION_OFFSET); mEndDegrees = mOriginEndDegrees + MAX_SWIPE_DEGREES * MATERIAL_INTERPOLATOR.getInterpolation(endTrimProgress); - float mSwipeDegrees = MIN_SWIPE_DEGREE; - if (Math.abs(mEndDegrees - mStartDegrees) > MIN_SWIPE_DEGREE) { - mSwipeDegrees = mEndDegrees - mStartDegrees; - } + float mSwipeDegrees = mEndDegrees - mStartDegrees; float levelSwipeDegreesProgress = Math.abs(mSwipeDegrees) / MAX_SWIPE_DEGREES; - if (levelSwipeDegreesProgress > LEVEL2_SWEEP_ANGLE_OFFSET) { - mLevel1SwipeDegrees = -mSwipeDegrees; - mLevel2SwipeDegrees = MAX_SWIPE_DEGREES * LEVEL2_SWEEP_ANGLE_OFFSET; - mLevel3SwipeDegrees = MAX_SWIPE_DEGREES * LEVEL3_SWEEP_ANGLE_OFFSET; - } else if (levelSwipeDegreesProgress > LEVEL3_SWEEP_ANGLE_OFFSET) { - mLevel1SwipeDegrees = MIN_SWIPE_DEGREE; - mLevel2SwipeDegrees = -mSwipeDegrees; - mLevel3SwipeDegrees = MAX_SWIPE_DEGREES * LEVEL3_SWEEP_ANGLE_OFFSET; + if (levelSwipeDegreesProgress > LEVEL_SWEEP_ANGLE_OFFSETS[1]) { + mLevelSwipeDegrees[0] = -mSwipeDegrees; + mLevelSwipeDegrees[1] = MAX_SWIPE_DEGREES * LEVEL_SWEEP_ANGLE_OFFSETS[1]; + mLevelSwipeDegrees[2] = MAX_SWIPE_DEGREES * LEVEL_SWEEP_ANGLE_OFFSETS[2]; + } else if (levelSwipeDegreesProgress > LEVEL_SWEEP_ANGLE_OFFSETS[2]) { + mLevelSwipeDegrees[0] = 0; + mLevelSwipeDegrees[1] = -mSwipeDegrees; + mLevelSwipeDegrees[2] = MAX_SWIPE_DEGREES * LEVEL_SWEEP_ANGLE_OFFSETS[2]; } else { - mLevel1SwipeDegrees = MIN_SWIPE_DEGREE; - mLevel2SwipeDegrees = MIN_SWIPE_DEGREE; - mLevel3SwipeDegrees = -mSwipeDegrees; + mLevelSwipeDegrees[0] = 0; + mLevelSwipeDegrees[1] = 0; + mLevelSwipeDegrees[2] = -mSwipeDegrees; } } mGroupRotation = ((FULL_GROUP_ROTATION / NUM_POINTS) * renderProgress) + (FULL_GROUP_ROTATION * (mRotationCount / NUM_POINTS)); - mRotationIncrement = mOriginRotationIncrement + (MAX_ROTATION_INCREMENT * renderProgress); } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); } @Override - public void reset() { + protected void reset() { resetOriginals(); } - public void setColor(int color) { - mLevel1Color = oneThirdAlphaColor(color); - mLevel2Color = twoThirdAlphaColor(color); - mLevel3Color = color; - } - - public void setInsets(int width, int height) { - final float minEdge = (float) Math.min(width, height); - float insets; - if (mCenterRadius <= 0 || minEdge < 0) { - insets = (float) Math.ceil(mStrokeWidth / 2.0f); - } else { - insets = minEdge / 2.0f - mCenterRadius; - } - mStrokeInset = insets; + private void initStrokeInset(float width, float height) { + float minSize = Math.min(width, height); + float strokeInset = minSize / 2.0f - mCenterRadius; + float minStrokeInset = (float) Math.ceil(mStrokeWidth / 2.0f); + mStrokeInset = strokeInset < minStrokeInset ? minStrokeInset : strokeInset; } private void storeOriginals() { mOriginEndDegrees = mEndDegrees; - mOriginStartDegrees = mStartDegrees; - mOriginRotationIncrement = mRotationIncrement; + mOriginStartDegrees = mEndDegrees; } private void resetOriginals() { mOriginEndDegrees = 0; mOriginStartDegrees = 0; - mOriginRotationIncrement = 0; mEndDegrees = 0; mStartDegrees = 0; - mRotationIncrement = 0; - mLevel1SwipeDegrees = MIN_SWIPE_DEGREE; - mLevel2SwipeDegrees = MIN_SWIPE_DEGREE; - mLevel3SwipeDegrees = MIN_SWIPE_DEGREE; + mLevelSwipeDegrees[0] = 0; + mLevelSwipeDegrees[1] = 0; + mLevelSwipeDegrees[2] = 0; } - private int oneThirdAlphaColor(int colorValue) { - int startA = (colorValue >> 24) & 0xff; - int startR = (colorValue >> 16) & 0xff; - int startG = (colorValue >> 8) & 0xff; - int startB = colorValue & 0xff; + private void apply(Builder builder) { + this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; + this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; + this.mStrokeWidth = builder.mStrokeWidth > 0 ? builder.mStrokeWidth : this.mStrokeWidth; + this.mCenterRadius = builder.mCenterRadius > 0 ? builder.mCenterRadius : this.mCenterRadius; - return (startA / 3 << 24) - | (startR << 16) - | (startG << 8) - | startB; + this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; + + this.mLevelColors = builder.mLevelColors != null ? builder.mLevelColors : this.mLevelColors; + + setupPaint(); + initStrokeInset(this.mWidth, this.mHeight); } - private int twoThirdAlphaColor(int colorValue) { - int startA = (colorValue >> 24) & 0xff; - int startR = (colorValue >> 16) & 0xff; - int startG = (colorValue >> 8) & 0xff; - int startB = colorValue & 0xff; + public static class Builder { + private Context mContext; + + private int mWidth; + private int mHeight; + private int mStrokeWidth; + private int mCenterRadius; + + private int mDuration; + + @Size(3) + private int[] mLevelColors; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public Builder setWidth(int width) { + this.mWidth = width; + return this; + } + + public Builder setHeight(int height) { + this.mHeight = height; + return this; + } + + public Builder setStrokeWidth(int strokeWidth) { + this.mStrokeWidth = strokeWidth; + return this; + } + + public Builder setCenterRadius(int centerRadius) { + this.mCenterRadius = centerRadius; + return this; + } + + public Builder setDuration(int duration) { + this.mDuration = duration; + return this; + } + + public Builder setLevelColors(@Size(3) int[] colors) { + this.mLevelColors = colors; + return this; + } + + public Builder setLevelColor(int color) { + return setLevelColors(new int[]{oneThirdAlphaColor(color), twoThirdAlphaColor(color), color}); + } + + public LevelLoadingRenderer build() { + LevelLoadingRenderer loadingRenderer = new LevelLoadingRenderer(mContext); + loadingRenderer.apply(this); + return loadingRenderer; + } + + private int oneThirdAlphaColor(int colorValue) { + int startA = (colorValue >> 24) & 0xff; + int startR = (colorValue >> 16) & 0xff; + int startG = (colorValue >> 8) & 0xff; + int startB = colorValue & 0xff; - return (startA * 2 / 3 << 24) - | (startR << 16) - | (startG << 8) - | startB; + return (startA / 3 << 24) | (startR << 16) | (startG << 8) | startB; + } + + private int twoThirdAlphaColor(int colorValue) { + int startA = (colorValue >> 24) & 0xff; + int startR = (colorValue >> 16) & 0xff; + int startG = (colorValue >> 8) & 0xff; + int startB = colorValue & 0xff; + + return (startA * 2 / 3 << 24) | (startR << 16) | (startG << 8) | startB; + } } + } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/MaterialLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/MaterialLoadingRenderer.java index f4ebc8f..5f87f9d 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/MaterialLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/MaterialLoadingRenderer.java @@ -7,11 +7,8 @@ import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; -import android.graphics.Rect; import android.graphics.RectF; -import android.support.annotation.NonNull; import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.util.DisplayMetrics; import android.view.animation.Interpolator; import app.dinus.com.loadingdrawable.DensityUtil; @@ -23,15 +20,13 @@ public class MaterialLoadingRenderer extends LoadingRenderer { private static final int DEGREE_360 = 360; private static final int NUM_POINTS = 5; - private static final float MIN_SWIPE_DEGREE = 0.1f; private static final float MAX_SWIPE_DEGREES = 0.8f * DEGREE_360; private static final float FULL_GROUP_ROTATION = 3.0f * DEGREE_360; - private static final float MAX_ROTATION_INCREMENT = 0.25f * DEGREE_360; private static final float COLOR_START_DELAY_OFFSET = 0.8f; private static final float END_TRIM_DURATION_OFFSET = 1.0f; private static final float START_TRIM_DURATION_OFFSET = 0.5f; - + private static final float DEFAULT_CENTER_RADIUS = 12.5f; private static final float DEFAULT_STROKE_WIDTH = 2.5f; @@ -72,15 +67,13 @@ public void onAnimationStart(Animator animation) { private float mEndDegrees; private float mStartDegrees; private float mSwipeDegrees; - private float mRotationIncrement; private float mOriginEndDegrees; private float mOriginStartDegrees; - private float mOriginRotationIncrement; private float mStrokeWidth; private float mCenterRadius; - public MaterialLoadingRenderer(Context context) { + private MaterialLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -94,7 +87,7 @@ private void init(Context context) { mColors = DEFAULT_COLORS; setColorIndex(0); - setInsets((int) getWidth(), (int) getHeight()); + initStrokeInset(mWidth, mHeight); } private void setupPaint() { @@ -105,70 +98,65 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas) { int saveCount = canvas.save(); - canvas.rotate(mGroupRotation, bounds.exactCenterX(), bounds.exactCenterY()); + mTempBounds.set(mBounds); + mTempBounds.inset(mStrokeInset, mStrokeInset); - RectF arcBounds = mTempBounds; - arcBounds.set(bounds); - arcBounds.inset(mStrokeInset, mStrokeInset); + canvas.rotate(mGroupRotation, mTempBounds.centerX(), mTempBounds.centerY()); - mPaint.setColor(mCurrentColor); - canvas.drawArc(arcBounds, mStartDegrees, mSwipeDegrees, false, mPaint); + if (mSwipeDegrees != 0) { + mPaint.setColor(mCurrentColor); + canvas.drawArc(mTempBounds, mStartDegrees, mSwipeDegrees, false, mPaint); + } canvas.restoreToCount(saveCount); } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { updateRingColor(renderProgress); - // Moving the start trim only occurs in the first 50% of a - // single ring animation + // Moving the start trim only occurs in the first 50% of a single ring animation if (renderProgress <= START_TRIM_DURATION_OFFSET) { float startTrimProgress = renderProgress / START_TRIM_DURATION_OFFSET; - mStartDegrees = mOriginStartDegrees + MAX_SWIPE_DEGREES * MATERIAL_INTERPOLATOR.getInterpolation(startTrimProgress); + mStartDegrees = mOriginStartDegrees + MAX_SWIPE_DEGREES + * MATERIAL_INTERPOLATOR.getInterpolation(startTrimProgress); } - // Moving the end trim starts after 50% of a single ring - // animation completes + // Moving the end trim starts after 50% of a single ring animation completes if (renderProgress > START_TRIM_DURATION_OFFSET) { - float endTrimProgress = (renderProgress - START_TRIM_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_TRIM_DURATION_OFFSET); - mEndDegrees = mOriginEndDegrees + MAX_SWIPE_DEGREES * MATERIAL_INTERPOLATOR.getInterpolation(endTrimProgress); + float endTrimProgress = (renderProgress - START_TRIM_DURATION_OFFSET) + / (END_TRIM_DURATION_OFFSET - START_TRIM_DURATION_OFFSET); + mEndDegrees = mOriginEndDegrees + MAX_SWIPE_DEGREES + * MATERIAL_INTERPOLATOR.getInterpolation(endTrimProgress); } - if (Math.abs(mEndDegrees - mStartDegrees) > MIN_SWIPE_DEGREE) { + if (Math.abs(mEndDegrees - mStartDegrees) > 0) { mSwipeDegrees = mEndDegrees - mStartDegrees; } - mGroupRotation = ((FULL_GROUP_ROTATION / NUM_POINTS) * renderProgress) + (FULL_GROUP_ROTATION * (mRotationCount / NUM_POINTS)); - mRotationIncrement = mOriginRotationIncrement + (MAX_ROTATION_INCREMENT * renderProgress); + mGroupRotation = ((FULL_GROUP_ROTATION / NUM_POINTS) * renderProgress) + + (FULL_GROUP_ROTATION * (mRotationCount / NUM_POINTS)); } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); } @Override - public void reset() { + protected void reset() { resetOriginals(); } - public void setColors(@NonNull int[] colors) { - mColors = colors; - setColorIndex(0); - } - - public void setColorIndex(int index) { + private void setColorIndex(int index) { mColorIndex = index; mCurrentColor = mColors[mColorIndex]; } @@ -185,33 +173,24 @@ private void goToNextColor() { setColorIndex(getNextColorIndex()); } - private void setInsets(int width, int height) { - final float minEdge = (float) Math.min(width, height); - float insets; - if (mCenterRadius <= 0 || minEdge < 0) { - insets = (float) Math.ceil(mStrokeWidth / 2.0f); - } else { - insets = minEdge / 2.0f - mCenterRadius; - } - mStrokeInset = insets; + private void initStrokeInset(float width, float height) { + float minSize = Math.min(width, height); + float strokeInset = minSize / 2.0f - mCenterRadius; + float minStrokeInset = (float) Math.ceil(mStrokeWidth / 2.0f); + mStrokeInset = strokeInset < minStrokeInset ? minStrokeInset : strokeInset; } private void storeOriginals() { mOriginEndDegrees = mEndDegrees; - mOriginStartDegrees = mStartDegrees; - mOriginRotationIncrement = mRotationIncrement; + mOriginStartDegrees = mEndDegrees; } private void resetOriginals() { mOriginEndDegrees = 0; mOriginStartDegrees = 0; - mOriginRotationIncrement = 0; mEndDegrees = 0; mStartDegrees = 0; - mRotationIncrement = 0; - - mSwipeDegrees = MIN_SWIPE_DEGREE; } private int getStartingColor() { @@ -242,8 +221,71 @@ private int evaluateColorChange(float fraction, int startValue, int endValue) { | ((startB + (int) (fraction * (endB - startB)))); } + private void apply(Builder builder) { + this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; + this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; + this.mStrokeWidth = builder.mStrokeWidth > 0 ? builder.mStrokeWidth : this.mStrokeWidth; + this.mCenterRadius = builder.mCenterRadius > 0 ? builder.mCenterRadius : this.mCenterRadius; + + this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; + + this.mColors = builder.mColors != null && builder.mColors.length > 0 ? builder.mColors : this.mColors; + + setColorIndex(0); + setupPaint(); + initStrokeInset(this.mWidth, this.mHeight); + } + public static class Builder { + private Context mContext; + + private int mWidth; + private int mHeight; + private int mStrokeWidth; + private int mCenterRadius; + + private int mDuration; + private int[] mColors; + public Builder(Context mContext) { + this.mContext = mContext; + } + + public Builder setWidth(int width) { + this.mWidth = width; + return this; + } + + public Builder setHeight(int height) { + this.mHeight = height; + return this; + } + + public Builder setStrokeWidth(int strokeWidth) { + this.mStrokeWidth = strokeWidth; + return this; + } + + public Builder setCenterRadius(int centerRadius) { + this.mCenterRadius = centerRadius; + return this; + } + + public Builder setDuration(int duration) { + this.mDuration = duration; + return this; + } + + public Builder setColors(int[] colors) { + this.mColors = colors; + return this; + } + + public MaterialLoadingRenderer build() { + MaterialLoadingRenderer loadingRenderer = new MaterialLoadingRenderer(mContext); + loadingRenderer.apply(this); + return loadingRenderer; + } } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/WhorlLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/WhorlLoadingRenderer.java index eecb02c..827ce2b 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/WhorlLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/circle/rotate/WhorlLoadingRenderer.java @@ -23,10 +23,8 @@ public class WhorlLoadingRenderer extends LoadingRenderer { private static final int DEGREE_360 = 360; private static final int NUM_POINTS = 5; - private static final float MIN_SWIPE_DEGREE = 0.1f; private static final float MAX_SWIPE_DEGREES = 0.6f * DEGREE_360; private static final float FULL_GROUP_ROTATION = 3.0f * DEGREE_360; - private static final float MAX_ROTATION_INCREMENT = 0.25f * DEGREE_360; private static final float START_TRIM_DURATION_OFFSET = 0.5f; private static final float END_TRIM_DURATION_OFFSET = 1.0f; @@ -40,6 +38,7 @@ public class WhorlLoadingRenderer extends LoadingRenderer { private final Paint mPaint = new Paint(); private final RectF mTempBounds = new RectF(); + private final RectF mTempArcBounds = new RectF(); private final Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() { @Override @@ -68,15 +67,13 @@ public void onAnimationStart(Animator animation) { private float mEndDegrees; private float mStartDegrees; private float mSwipeDegrees; - private float mRotationIncrement; private float mOriginEndDegrees; private float mOriginStartDegrees; - private float mOriginRotationIncrement; - + private float mStrokeWidth; private float mCenterRadius; - public WhorlLoadingRenderer(Context context) { + private WhorlLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -87,7 +84,8 @@ private void init(Context context) { mColors = DEFAULT_COLORS; mStrokeWidth = DensityUtil.dip2px(context, DEFAULT_STROKE_WIDTH); mCenterRadius = DensityUtil.dip2px(context, DEFAULT_CENTER_RADIUS); - setInsets((int) getWidth(), (int) getHeight()); + + initStrokeInset(mWidth, mHeight); } private void setupPaint() { @@ -98,26 +96,27 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas) { int saveCount = canvas.save(); - canvas.rotate(mGroupRotation, bounds.exactCenterX(), bounds.exactCenterY()); - RectF arcBounds = mTempBounds; - arcBounds.set(bounds); - arcBounds.inset(mStrokeInset, mStrokeInset); + mTempBounds.set(mBounds); + mTempBounds.inset(mStrokeInset, mStrokeInset); + + canvas.rotate(mGroupRotation, mTempBounds.centerX(), mTempBounds.centerY()); - for (int i = 0; i < mColors.length; i++) { - mPaint.setStrokeWidth(mStrokeWidth / (i + 1)); - mPaint.setColor(mColors[i]); - canvas.drawArc(createArcBounds(arcBounds, i), mStartDegrees + DEGREE_180 * (i % 2), - mSwipeDegrees, false, mPaint); + if (mSwipeDegrees != 0) { + for (int i = 0; i < mColors.length; i++) { + mPaint.setStrokeWidth(mStrokeWidth / (i + 1)); + mPaint.setColor(mColors[i]); + canvas.drawArc(createArcBounds(mTempBounds, i), mStartDegrees + DEGREE_180 * (i % 2), + mSwipeDegrees, false, mPaint); + } } canvas.restoreToCount(saveCount); } private RectF createArcBounds(RectF sourceArcBounds, int index) { - RectF arcBounds = new RectF(); int intervalWidth = 0; for (int i = 0; i < index; i++) { @@ -128,82 +127,135 @@ private RectF createArcBounds(RectF sourceArcBounds, int index) { int arcBoundsTop = (int) (sourceArcBounds.top + intervalWidth); int arcBoundsRight = (int) (sourceArcBounds.right - intervalWidth); int arcBoundsBottom = (int) (sourceArcBounds.bottom - intervalWidth); - arcBounds.set(arcBoundsLeft, arcBoundsTop, arcBoundsRight, arcBoundsBottom); + mTempArcBounds.set(arcBoundsLeft, arcBoundsTop, arcBoundsRight, arcBoundsBottom); - return arcBounds; + return mTempArcBounds; } @Override - public void computeRender(float renderProgress) { - // Moving the start trim only occurs in the first 50% of a - // single ring animation + protected void computeRender(float renderProgress) { + // Moving the start trim only occurs in the first 50% of a single ring animation if (renderProgress <= START_TRIM_DURATION_OFFSET) { float startTrimProgress = (renderProgress) / (1.0f - START_TRIM_DURATION_OFFSET); mStartDegrees = mOriginStartDegrees + MAX_SWIPE_DEGREES * MATERIAL_INTERPOLATOR.getInterpolation(startTrimProgress); } - // Moving the end trim starts after 50% of a single ring - // animation completes + // Moving the end trim starts after 50% of a single ring animation if (renderProgress > START_TRIM_DURATION_OFFSET) { float endTrimProgress = (renderProgress - START_TRIM_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_TRIM_DURATION_OFFSET); mEndDegrees = mOriginEndDegrees + MAX_SWIPE_DEGREES * MATERIAL_INTERPOLATOR.getInterpolation(endTrimProgress); } - if (Math.abs(mEndDegrees - mStartDegrees) > MIN_SWIPE_DEGREE) { + if (Math.abs(mEndDegrees - mStartDegrees) > 0) { mSwipeDegrees = mEndDegrees - mStartDegrees; } mGroupRotation = ((FULL_GROUP_ROTATION / NUM_POINTS) * renderProgress) + (FULL_GROUP_ROTATION * (mRotationCount / NUM_POINTS)); - mRotationIncrement = mOriginRotationIncrement + (MAX_ROTATION_INCREMENT * renderProgress); } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { resetOriginals(); } - public void setColors(@NonNull int[] colors) { - mColors = colors; - } - - public void setInsets(int width, int height) { - final float minEdge = (float) Math.min(width, height); - float insets; - if (mCenterRadius <= 0 || minEdge < 0) { - insets = (float) Math.ceil(mStrokeWidth / 2.0f); - } else { - insets = minEdge / 2.0f - mCenterRadius; - } - mStrokeInset = insets; + private void initStrokeInset(float width, float height) { + float minSize = Math.min(width, height); + float strokeInset = minSize / 2.0f - mCenterRadius; + float minStrokeInset = (float) Math.ceil(mStrokeWidth / 2.0f); + mStrokeInset = strokeInset < minStrokeInset ? minStrokeInset : strokeInset; } private void storeOriginals() { mOriginEndDegrees = mEndDegrees; - mOriginStartDegrees = mStartDegrees; - mOriginRotationIncrement = mRotationIncrement; + mOriginStartDegrees = mEndDegrees; } private void resetOriginals() { mOriginEndDegrees = 0; mOriginStartDegrees = 0; - mOriginRotationIncrement = 0; mEndDegrees = 0; mStartDegrees = 0; - mRotationIncrement = 0; - mSwipeDegrees = MIN_SWIPE_DEGREE; + mSwipeDegrees = 0; + } + + private void apply(Builder builder) { + this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; + this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; + this.mStrokeWidth = builder.mStrokeWidth > 0 ? builder.mStrokeWidth : this.mStrokeWidth; + this.mCenterRadius = builder.mCenterRadius > 0 ? builder.mCenterRadius : this.mCenterRadius; + + this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; + + this.mColors = builder.mColors != null && builder.mColors.length > 0 ? builder.mColors : this.mColors; + + setupPaint(); + initStrokeInset(this.mWidth, this.mHeight); + } + + public static class Builder { + private Context mContext; + + private int mWidth; + private int mHeight; + private int mStrokeWidth; + private int mCenterRadius; + + private int mDuration; + + private int[] mColors; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public Builder setWidth(int width) { + this.mWidth = width; + return this; + } + + public Builder setHeight(int height) { + this.mHeight = height; + return this; + } + + public Builder setStrokeWidth(int strokeWidth) { + this.mStrokeWidth = strokeWidth; + return this; + } + + public Builder setCenterRadius(int centerRadius) { + this.mCenterRadius = centerRadius; + return this; + } + + public Builder setDuration(int duration) { + this.mDuration = duration; + return this; + } + + public Builder setColors(int[] colors) { + this.mColors = colors; + return this; + } + + public WhorlLoadingRenderer build() { + WhorlLoadingRenderer loadingRenderer = new WhorlLoadingRenderer(mContext); + loadingRenderer.apply(this); + return loadingRenderer; + } } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/BalloonLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/BalloonLoadingRenderer.java index 283f69e..269ecac 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/BalloonLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/BalloonLoadingRenderer.java @@ -78,7 +78,7 @@ public class BalloonLoadingRenderer extends LoadingRenderer { private int mCannulaColor; private int mPipeBodyColor; - public BalloonLoadingRenderer(Context context) { + private BalloonLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -110,7 +110,7 @@ private void init(Context context) { mProgressText = 10 + PERCENT_SIGN; - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -119,7 +119,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mCurrentBounds; @@ -160,7 +160,7 @@ public void draw(Canvas canvas, Rect bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { RectF arcBounds = mCurrentBounds; //compute gas tube bounds mGasTubeBounds.set(arcBounds.centerX() - mGasTubeWidth / 2.0f, arcBounds.centerY(), @@ -282,18 +282,30 @@ private Path createBalloonPath(RectF balloonRect, float progress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); } @Override - public void reset() { + protected void reset() { + } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public BalloonLoadingRenderer build() { + BalloonLoadingRenderer loadingRenderer = new BalloonLoadingRenderer(mContext); + return loadingRenderer; + } } } \ No newline at end of file diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/WaterBottleLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/WaterBottleLoadingRenderer.java index 92ebe92..5f86023 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/WaterBottleLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/goods/WaterBottleLoadingRenderer.java @@ -66,7 +66,7 @@ public class WaterBottleLoadingRenderer extends LoadingRenderer { private int mWaveCount; - public WaterBottleLoadingRenderer(Context context) { + private WaterBottleLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -88,7 +88,7 @@ private void init(Context context) { mWaveCount = DEFAULT_WAVE_COUNT; - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -98,7 +98,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mCurrentBounds; @@ -130,7 +130,7 @@ public void draw(Canvas canvas, Rect bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (mCurrentBounds.width() <= 0) { return; } @@ -278,19 +278,19 @@ private float getMaxRiseHeight(float bottleRadius, float waterDropRadius, float } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { } private class WaterDropHolder { @@ -306,4 +306,17 @@ private class WaterDropHolder { public boolean mNeedDraw; } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public WaterBottleLoadingRenderer build() { + WaterBottleLoadingRenderer loadingRenderer = new WaterBottleLoadingRenderer(mContext); + return loadingRenderer; + } + } } \ No newline at end of file diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/DayNightLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/DayNightLoadingRenderer.java index 42b9406..cf5d319 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/DayNightLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/DayNightLoadingRenderer.java @@ -109,7 +109,7 @@ public void onAnimationRepeat(Animator animator) { private int mSunRayCount; - public DayNightLoadingRenderer(Context context) { + private DayNightLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -140,7 +140,7 @@ private void init(Context context) { mCurrentColor = DEFAULT_COLOR; - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -152,7 +152,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mTempBounds; @@ -201,7 +201,7 @@ public void draw(Canvas canvas, Rect bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (renderProgress <= SUN_RISE_DURATION_OFFSET) { float sunRiseProgress = renderProgress / SUN_RISE_DURATION_OFFSET; mSunCoordinateY = mInitSun$MoonCoordinateY - mMaxSun$MoonRiseDistance * MATERIAL_INTERPOLATOR.getInterpolation(sunRiseProgress); @@ -273,19 +273,19 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { } private void initStarHolders(RectF currentBounds) { @@ -344,4 +344,17 @@ public StarHolder(float flashOffset, PointF mPoint) { this.mInterpolator = INTERPOLATORS[mRandom.nextInt(INTERPOLATORS.length)]; } } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public DayNightLoadingRenderer build() { + DayNightLoadingRenderer loadingRenderer = new DayNightLoadingRenderer(mContext); + return loadingRenderer; + } + } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/ElectricFanLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/ElectricFanLoadingRenderer.java index e325b3b..63c8fd8 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/ElectricFanLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/scenery/ElectricFanLoadingRenderer.java @@ -120,7 +120,7 @@ public void onAnimationRepeat(Animator animator) { private Drawable mLoadingDrawable; private Drawable mElectricFanDrawable; - public ElectricFanLoadingRenderer(Context context) { + private ElectricFanLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -146,8 +146,8 @@ private void init(Context context) { mLoadingDrawable = context.getResources().getDrawable(R.drawable.ic_loading); mElectricFanDrawable = context.getResources().getDrawable(R.drawable.ic_eletric_fan); - setDuration(ANIMATION_DURATION); - setInsets((int) getWidth(), (int) getHeight()); + mDuration = ANIMATION_DURATION; + setInsets((int) mWidth, (int) mHeight); } private void setupPaint() { @@ -158,7 +158,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mTempBounds; @@ -296,7 +296,7 @@ private Path createProgressPath(float progress, float circleRadius, RectF progre } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (renderProgress < DECELERATE_DURATION_PERCENTAGE) { mProgress = DECELERATE_INTERPOLATOR.getInterpolation(renderProgress / DECELERATE_DURATION_PERCENTAGE) * DECELERATE_DURATION_PERCENTAGE; } else { @@ -305,26 +305,26 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { mScale = 1.0f; mCurrentLeafCount = 0; mNextLeafCreateThreshold = 0.0f; mLeafHolders.clear(); } - public void setInsets(int width, int height) { + protected void setInsets(int width, int height) { final float minEdge = (float) Math.min(width, height); float insetXs; if (mCenterRadius <= 0 || minEdge < 0) { @@ -374,7 +374,7 @@ private ValueAnimator getBezierValueAnimator(LeafHolder target, RectF leafFlyRec animator.addUpdateListener(new BezierListener(target)); animator.setTarget(target); - animator.setDuration((long) ((mRandom.nextInt(300) + getDuration() * DEFAULT_LEAF_FLY_DURATION_FACTOR) * (1.0f - progress))); + animator.setDuration((long) ((mRandom.nextInt(300) + mDuration * DEFAULT_LEAF_FLY_DURATION_FACTOR) * (1.0f - progress))); return animator; } @@ -395,10 +395,6 @@ private PointF getPoint2(RectF leafFlyRect) { return point; } - public void setMode(@MODE int mode) { - this.mMode = mode; - } - private class BezierEvaluator implements TypeEvaluator { private PointF point1; @@ -461,4 +457,17 @@ private class LeafHolder { public float mMaxRotation = mRandom.nextInt(120); } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public ElectricFanLoadingRenderer build() { + ElectricFanLoadingRenderer loadingRenderer = new ElectricFanLoadingRenderer(mContext); + return loadingRenderer; + } + } } diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CircleBroodLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CircleBroodLoadingRenderer.java index d8dbbf4..8fb83f1 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CircleBroodLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CircleBroodLoadingRenderer.java @@ -108,7 +108,7 @@ public class CircleBroodLoadingRenderer extends LoadingRenderer { private float mStageChildForwardBottomLeftLength; private float mStageChildBackwardBottomLeftLength; - public CircleBroodLoadingRenderer(Context context) { + private CircleBroodLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -131,7 +131,7 @@ private void init(Context context) { mMaxRevealCircleRadius = (int) (Math.sqrt(mWidth * mWidth + mHeight * mHeight) / 2 + 1); - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -141,7 +141,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mCurrentBounds; @@ -258,7 +258,7 @@ private Path createLinkPath() { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (mCurrentBounds.isEmpty()) { return; } @@ -598,19 +598,19 @@ private float getRestLength(Path path, float startD) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { } private class MotherMoveInterpolator implements Interpolator { @@ -661,4 +661,17 @@ public float getInterpolation(float input) { return result; } } + + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + + public CircleBroodLoadingRenderer build() { + CircleBroodLoadingRenderer loadingRenderer = new CircleBroodLoadingRenderer(mContext); + return loadingRenderer; + } + } } \ No newline at end of file diff --git a/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CoolWaitLoadingRenderer.java b/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CoolWaitLoadingRenderer.java index 85dc7ed..a404e78 100644 --- a/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CoolWaitLoadingRenderer.java +++ b/library/src/main/java/app/dinus/com/loadingdrawable/render/shapechange/CoolWaitLoadingRenderer.java @@ -60,7 +60,7 @@ public class CoolWaitLoadingRenderer extends LoadingRenderer { private int mMiddleColor; private int mBottomColor; - public CoolWaitLoadingRenderer(Context context) { + private CoolWaitLoadingRenderer(Context context) { super(context); init(context); setupPaint(); @@ -76,7 +76,7 @@ private void init(Context context) { mMiddleColor = Color.parseColor("#FFF3C742"); mBottomColor = Color.parseColor("#FF89CC59"); - setDuration(ANIMATION_DURATION); + mDuration = ANIMATION_DURATION; } private void setupPaint() { @@ -88,7 +88,7 @@ private void setupPaint() { } @Override - public void draw(Canvas canvas, Rect bounds) { + protected void draw(Canvas canvas, Rect bounds) { int saveCount = canvas.save(); RectF arcBounds = mCurrentBounds; arcBounds.set(bounds); @@ -145,7 +145,7 @@ private Path createWaitPath(RectF bounds) { } @Override - public void computeRender(float renderProgress) { + protected void computeRender(float renderProgress) { if (mCurrentBounds.isEmpty()) { return; } @@ -240,20 +240,31 @@ public void computeRender(float renderProgress) { } @Override - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { mPaint.setAlpha(alpha); - invalidateSelf(); + } @Override - public void setColorFilter(ColorFilter cf) { + protected void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); - invalidateSelf(); + } @Override - public void reset() { + protected void reset() { } + public static class Builder { + private Context mContext; + + public Builder(Context mContext) { + this.mContext = mContext; + } + public CoolWaitLoadingRenderer build() { + CoolWaitLoadingRenderer loadingRenderer = new CoolWaitLoadingRenderer(mContext); + return loadingRenderer; + } + } }