diff --git a/README.md b/README.md index df576d3..c2a071c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ latest version : [ ![Download](https://api.bintray.com/packages/agrawalsuneet/an ![lazyloader](https://user-images.githubusercontent.com/12999622/36225792-b7044432-11c3-11e8-8e22-5bbdcafa2312.gif) ![tashieloader](https://user-images.githubusercontent.com/12999622/36225793-b71f694c-11c3-11e8-9a81-8414bafb26c5.gif) -![slidingloader](https://user-images.githubusercontent.com/12999622/34130222-f58ba220-e43e-11e7-8f60-4971918fecde.gif) ![RotatingCircularDotsLoader](https://user-images.githubusercontent.com/12999622/34453427-d9aa8294-ed4c-11e7-8b1d-fe98d0c2c3dc.gif) +![slidingloader](https://user-images.githubusercontent.com/12999622/34130222-f58ba220-e43e-11e7-8f60-4971918fecde.gif) ![bounceloader](https://user-images.githubusercontent.com/12999622/56847870-1d5b9080-68ff-11e9-952f-b0414771d580.gif) ![trailingcirculardotsloader](https://user-images.githubusercontent.com/12999622/39367184-f3bb706a-4a2d-11e8-9120-5027bbef2861.gif) ![zeeloader](https://user-images.githubusercontent.com/12999622/44630261-8ba41980-a952-11e8-9ba5-45f4cafb473b.gif) @@ -18,14 +18,14 @@ latest version : [ ![Download](https://api.bintray.com/packages/agrawalsuneet/an ![pullinloader](https://user-images.githubusercontent.com/12999622/52536021-80676d80-2d7b-11e9-9b06-8135d6d15dbb.gif) ![lineardotsloader](https://user-images.githubusercontent.com/12999622/35482391-54665328-042c-11e8-954b-93a92ebe2b0c.gif) -![circulardotsloader](https://user-images.githubusercontent.com/12999622/36224573-f274b956-11bf-11e8-8f97-e4c031959465.gif) +![circulardotsloader](https://user-images.githubusercontent.com/12999622/36224573-f274b956-11bf-11e8-8f97-e4c031959465.gif) ![RotatingCircularDotsLoader](https://user-images.githubusercontent.com/12999622/34453427-d9aa8294-ed4c-11e7-8b1d-fe98d0c2c3dc.gif) Check all other loaders [here](https://agrawalsuneet.github.io/agrawalsuneet/opensourcecontribution/) ## How To use include below dependency in build.gradle of application and compile it ``` -implementation 'com.agrawalsuneet.androidlibs:dotsloader:1.3' +implementation 'com.agrawalsuneet.androidlibs:dotsloader:1.4' ``` @@ -168,39 +168,46 @@ SlidingLoader sliding = new SlidingLoader(this, 40, 10, containerLL.addView(sliding); ``` -### RotatingCircularDotsLoader +### BounceLoader ##### Through XML ``` - + app:bounce_animDuration="1200" + app:bounce_ballColor="@color/blue_selected" + app:bounce_ballRadius="22dp" + app:bounce_shadowColor="@color/black" + app:bounce_showShadow="true" /> ``` ##### Through Code * Kotlin ``` -val loader = RotatingCircularDotsLoader(this, - 20, 60, ContextCompat.getColor(this, R.color.red)) +val bounceLoader = BounceLoader(context = this, + ballRadius = 60, + ballColor = ContextCompat.getColor(this, R.color.red), + showShadow = true, + shadowColor = ContextCompat.getColor(this, R.color.black)) .apply { - animDuration = 3000 + animDuration = 1000 } - containerLL.addView(loader) - + containerLL.addView(bounceLoader) + ``` * Java ``` -RotatingCircularDotsLoader loader = new RotatingCircularDotsLoader(this, - 20, 60, ContextCompat.getColor(this, R.color.red)); - loader.setAnimDuration(3000); +BounceLoader bounceLoader = new BounceLoader(this, + 60, + ContextCompat.getColor(this, R.color.red), + true, + ContextCompat.getColor(this, R.color.black)); - containerLL.addView(loader); + bounceLoader.setAnimDuration(1000); + containerLL.addView(bounceLoader); ``` ### TrailingCircularDotsLoader @@ -558,6 +565,42 @@ CircularDotsLoader loader = new CircularDotsLoader(this); loader.setSecondShadowColor(ContextCompat.getColor(this, R.color.blue_delfault)); ``` + +### RotatingCircularDotsLoader +##### Through XML +``` + +``` + +##### Through Code + +* Kotlin +``` +val loader = RotatingCircularDotsLoader(this, + 20, 60, ContextCompat.getColor(this, R.color.red)) + .apply { + animDuration = 3000 + } + + containerLL.addView(loader) + +``` + +* Java +``` +RotatingCircularDotsLoader loader = new RotatingCircularDotsLoader(this, + 20, 60, ContextCompat.getColor(this, R.color.red)); + loader.setAnimDuration(3000); + + containerLL.addView(loader); +``` + > For avoiding overlapping in CircularDotsLoader, set BigCircleLoader nearly four times of dotsRadius. > If the showRunningShadow is true and no firstShadowColor and secondShadowColor provided, it'll take 0.7f and 0.5f alpha of selectedColor diff --git a/app/src/main/java/com/agrawalsuneet/loaders/MainActivity.kt b/app/src/main/java/com/agrawalsuneet/loaders/MainActivity.kt index bf19070..a13a856 100644 --- a/app/src/main/java/com/agrawalsuneet/loaders/MainActivity.kt +++ b/app/src/main/java/com/agrawalsuneet/loaders/MainActivity.kt @@ -14,9 +14,9 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.main_pullin) + setContentView(R.layout.main_bounce) - supportActionBar?.title = "PullInLoader" + supportActionBar?.title = "BounceLoader" containerLL = findViewById(R.id.container) as LinearLayout @@ -36,6 +36,20 @@ class MainActivity : AppCompatActivity() { //initLightsLoader() //initPullInLoader() + //initBounceLoader() + } + + private fun initBounceLoader() { + val bounceLoader = BounceLoader(context = this, + ballRadius = 60, + ballColor = ContextCompat.getColor(this, R.color.red), + showShadow = true, + shadowColor = ContextCompat.getColor(this, R.color.black)) + .apply { + animDuration = 1000 + } + + containerLL.addView(bounceLoader) } private fun initPullInLoader() { diff --git a/app/src/main/java/com/agrawalsuneet/loaders/MainActivityJava.java b/app/src/main/java/com/agrawalsuneet/loaders/MainActivityJava.java index 7d1fb0a..3b93102 100644 --- a/app/src/main/java/com/agrawalsuneet/loaders/MainActivityJava.java +++ b/app/src/main/java/com/agrawalsuneet/loaders/MainActivityJava.java @@ -8,6 +8,7 @@ import android.widget.LinearLayout; import com.agrawalsuneet.dotsloader.loaders.AllianceLoader; +import com.agrawalsuneet.dotsloader.loaders.BounceLoader; import com.agrawalsuneet.dotsloader.loaders.LightsLoader; import com.agrawalsuneet.dotsloader.loaders.PullInLoader; import com.agrawalsuneet.dotsloader.loaders.RotatingCircularDotsLoader; @@ -46,7 +47,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { tashie.setAnimDuration(500); tashie.setAnimDelay(100); tashie.setInterpolator(new LinearInterpolator()); - containerLL.addView(tashie); //sliding loader @@ -56,14 +56,12 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ContextCompat.getColor(this, R.color.green)); sliding.setAnimDuration(1000); sliding.setDistanceToMove(12); - containerLL.addView(sliding); //RotatingCircularDotsLoader RotatingCircularDotsLoader loader = new RotatingCircularDotsLoader(this, 20, 60, ContextCompat.getColor(this, R.color.red)); loader.setAnimDuration(3000); - containerLL.addView(loader); @@ -76,7 +74,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { 5); trailingCircularDotsLoader.setAnimDuration(1200); trailingCircularDotsLoader.setAnimDelay(200); - containerLL.addView(trailingCircularDotsLoader); @@ -89,10 +86,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ContextCompat.getColor(this, R.color.red)); zeeLoader.setAnimDuration(200); - containerLL.addView(zeeLoader); - AllianceLoader allianceLoader = new AllianceLoader( this, 40, @@ -104,28 +99,32 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ContextCompat.getColor(this, R.color.green)); allianceLoader.setAnimDuration(500); - containerLL.addView(allianceLoader); LightsLoader lightsLoader = new LightsLoader( this, 5, 30, 10, ContextCompat.getColor(this, R.color.red)); - - containerLL.addView(lightsLoader); PullInLoader pullInLoader = new PullInLoader(this, 20, 100, ContextCompat.getColor(this, R.color.red)); pullInLoader.setAnimDuration(2000); - containerLL.addView(pullInLoader); PullInLoader pullInLoader2 = new PullInLoader(this, 30, 160, getResources().getIntArray(R.array.vibgyorg)); pullInLoader.setAnimDuration(2000); - containerLL.addView(pullInLoader2); + + BounceLoader bounceLoader = new BounceLoader(this, + 60, + ContextCompat.getColor(this, R.color.red), + true, + ContextCompat.getColor(this, R.color.black)); + + bounceLoader.setAnimDuration(1000); + containerLL.addView(bounceLoader); } } diff --git a/app/src/main/res/layout/main_bounce.xml b/app/src/main/res/layout/main_bounce.xml new file mode 100644 index 0000000..1e54443 --- /dev/null +++ b/app/src/main/res/layout/main_bounce.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + --> + + diff --git a/dotsloader/build.gradle b/dotsloader/build.gradle index 28d1b10..aa33491 100644 --- a/dotsloader/build.gradle +++ b/dotsloader/build.gradle @@ -16,7 +16,7 @@ buildscript { ext { PUBLISH_GROUP_ID = 'com.agrawalsuneet.androidlibs' PUBLISH_ARTIFACT_ID = 'dotsloader' - PUBLISH_VERSION = '1.3' + PUBLISH_VERSION = '1.4' } configurations { @@ -29,8 +29,8 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 28 - versionCode 13 - versionName "1.3" + versionCode 14 + versionName "1.4" } buildTypes { release { diff --git a/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/basicviews/CircleView.kt b/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/basicviews/CircleView.kt index a7a8528..2aec311 100644 --- a/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/basicviews/CircleView.kt +++ b/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/basicviews/CircleView.kt @@ -19,13 +19,15 @@ class CircleView : View { var circleColor: Int = 0 var drawOnlyStroke: Boolean = false - private var xyCordinates: Float = 0.0f + var isAntiAlias: Boolean = true + private var xyCordinates: Float = 0.0f private val paint: Paint = Paint() - constructor(context: Context, circleRadius: Int, circleColor: Int) : super(context) { + constructor(context: Context, circleRadius: Int, circleColor: Int, isAntiAlias: Boolean = true) : super(context) { this.circleRadius = circleRadius this.circleColor = circleColor + this.isAntiAlias = isAntiAlias initValues() } @@ -75,12 +77,11 @@ class CircleView : View { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val widthHeight = (2 * (circleRadius)) + strokeWidth - setMeasuredDimension(widthHeight, widthHeight) } private fun initValues() { - paint.isAntiAlias = true + paint.isAntiAlias = isAntiAlias if (drawOnlyStroke) { paint.style = Paint.Style.STROKE @@ -100,6 +101,4 @@ class CircleView : View { super.onDraw(canvas) canvas.drawCircle(xyCordinates, xyCordinates, circleRadius.toFloat(), paint) } - - } \ No newline at end of file diff --git a/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/loaders/BounceLoader.kt b/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/loaders/BounceLoader.kt new file mode 100644 index 0000000..7d71915 --- /dev/null +++ b/dotsloader/src/main/java/com/agrawalsuneet/dotsloader/loaders/BounceLoader.kt @@ -0,0 +1,262 @@ +package com.agrawalsuneet.dotsloader.loaders + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.view.ViewTreeObserver +import android.view.animation.* +import android.widget.LinearLayout +import android.widget.RelativeLayout +import com.agrawalsuneet.dotsloader.R +import com.agrawalsuneet.dotsloader.basicviews.CircleView +import com.agrawalsuneet.dotsloader.contracts.LoaderContract + +/** + * Created by agrawalsuneet on 4/13/19. + */ + +class BounceLoader : LinearLayout, LoaderContract { + + var ballRadius: Int = 60 + var ballColor: Int = resources.getColor(android.R.color.holo_red_dark) + + var showShadow: Boolean = true + var shadowColor: Int = resources.getColor(android.R.color.black) + + var animDuration: Int = 1500 + set(value) { + field = if (value <= 0) 1000 else value + } + + private var relativeLayout: RelativeLayout? = null + + private var ballCircleView: CircleView? = null + private var ballShadowView: CircleView? = null + + private var calWidth: Int = 0 + private var calHeight: Int = 0 + + private val STATE_GOINGDOWN: Int = 0 + private val STATE_SQUEEZING: Int = 1 + private val STATE_RESIZING: Int = 2 + private val STATE_COMINGUP: Int = 3 + + private var state: Int = STATE_GOINGDOWN + + constructor(context: Context?) : super(context) { + initView() + } + + constructor(context: Context?, attrs: AttributeSet) : super(context, attrs) { + initAttributes(attrs) + initView() + } + + constructor(context: Context?, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + initAttributes(attrs) + initView() + } + + constructor(context: Context?, ballRadius: Int, ballColor: Int, showShadow: Boolean, shadowColor: Int = 0) : super(context) { + this.ballRadius = ballRadius + this.ballColor = ballColor + this.shadowColor = shadowColor + initView() + } + + override fun initAttributes(attrs: AttributeSet) { + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.BounceLoader, 0, 0) + + this.ballRadius = typedArray.getDimensionPixelSize(R.styleable.BounceLoader_bounce_ballRadius, 60) + this.ballColor = typedArray.getColor(R.styleable.BounceLoader_bounce_ballColor, + resources.getColor(android.R.color.holo_red_dark)) + + this.shadowColor = typedArray.getColor(R.styleable.BounceLoader_bounce_shadowColor, + resources.getColor(android.R.color.black)) + + this.showShadow = typedArray.getBoolean(R.styleable.BounceLoader_bounce_showShadow, true) + this.animDuration = typedArray.getInt(R.styleable.BounceLoader_bounce_animDuration, 1500) + + typedArray.recycle() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + + if (calWidth == 0 || calHeight == 0) { + calWidth = 5 * ballRadius + calHeight = 8 * ballRadius + } + + setMeasuredDimension(calWidth, calHeight) + } + + private fun initView() { + removeAllViews() + removeAllViewsInLayout() + + if (calWidth == 0 || calHeight == 0) { + calWidth = 5 * ballRadius + calHeight = 8 * ballRadius + } + + relativeLayout = RelativeLayout(context) + + if (showShadow) { + ballShadowView = CircleView(context = context, + circleRadius = ballRadius, + circleColor = shadowColor, + isAntiAlias = false) + + val shadowParam = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + shadowParam.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE) + shadowParam.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE) + relativeLayout?.addView(ballShadowView, shadowParam) + } + + ballCircleView = CircleView(context = context, + circleRadius = ballRadius, + circleColor = ballColor) + + val ballParam = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + + ballParam.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE) + ballParam.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE) + relativeLayout?.addView(ballCircleView, ballParam) + + val relParam = RelativeLayout.LayoutParams(calWidth, calHeight) + this.addView(relativeLayout, relParam) + + viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + startLoading() + this@BounceLoader.viewTreeObserver.removeOnGlobalLayoutListener(this) + } + }) + + } + + private fun startLoading() { + val ballAnim = getBallAnimation() + + ballAnim.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationEnd(anim: Animation?) { + state = (state + 1) % 4 + startLoading() + } + + + override fun onAnimationRepeat(p0: Animation?) { + } + + override fun onAnimationStart(p0: Animation?) { + } + + }) + + if (showShadow) { + if (state == STATE_SQUEEZING || state == STATE_RESIZING) { + ballShadowView?.clearAnimation() + ballShadowView?.visibility = View.GONE + } else { + ballShadowView?.visibility = View.VISIBLE + val shadowAnim = getShadowAnimation() + ballShadowView?.startAnimation(shadowAnim) + } + } + + ballCircleView?.startAnimation(ballAnim) + } + + private fun getBallAnimation(): Animation { + return when (state) { + STATE_GOINGDOWN -> { + TranslateAnimation(0.0f, 0.0f, + (-6 * ballRadius).toFloat(), 0.0f) + .apply { + duration = animDuration.toLong() + interpolator = AccelerateInterpolator() + } + } + + STATE_SQUEEZING -> { + ScaleAnimation(1.0f, 1.0f, 1.0f, 0.85f + , ballRadius.toFloat(), (2 * ballRadius).toFloat()) + .apply { + duration = (animDuration / 20).toLong() + interpolator = AccelerateInterpolator() + } + } + + STATE_RESIZING -> { + ScaleAnimation(1.0f, 1.0f, 0.85f, 1.0f + , ballRadius.toFloat(), (2 * ballRadius).toFloat()) + .apply { + duration = (animDuration / 20).toLong() + interpolator = DecelerateInterpolator() + } + } + + else -> { + TranslateAnimation(0.0f, 0.0f, + 0.0f, (-6 * ballRadius).toFloat()) + .apply { + duration = animDuration.toLong() + interpolator = DecelerateInterpolator() + } + } + }.apply { + fillAfter = true + repeatCount = 0 + } + } + + private fun getShadowAnimation(): AnimationSet { + + val transAnim: Animation + val scaleAnim: Animation + val alphaAnim: AlphaAnimation + + val set = AnimationSet(true) + + when (state) { + STATE_COMINGUP -> { + transAnim = TranslateAnimation(0.0f, (-4 * ballRadius).toFloat(), + 0.0f, (-3 * ballRadius).toFloat()) + + scaleAnim = ScaleAnimation(0.9f, 0.5f, 0.9f, 0.5f, + ballRadius.toFloat(), ballRadius.toFloat()) + + alphaAnim = AlphaAnimation(0.6f, 0.2f) + + set.interpolator = DecelerateInterpolator() + } + else -> { + transAnim = TranslateAnimation((-4 * ballRadius).toFloat(), 0.0f, + (-3 * ballRadius).toFloat(), 0.0f) + + scaleAnim = ScaleAnimation(0.5f, 0.9f, 0.5f, 0.9f, + ballRadius.toFloat(), ballRadius.toFloat()) + + alphaAnim = AlphaAnimation(0.2f, 0.6f) + + set.interpolator = AccelerateInterpolator() + } + } + + set.addAnimation(transAnim) + set.addAnimation(scaleAnim) + set.addAnimation(alphaAnim) + + set.apply { + duration = animDuration.toLong() + fillAfter = true + repeatCount = 0 + } + + return set + } +} \ No newline at end of file diff --git a/dotsloader/src/main/res/values/attrs.xml b/dotsloader/src/main/res/values/attrs.xml index 03dfb8a..3c0c204 100644 --- a/dotsloader/src/main/res/values/attrs.xml +++ b/dotsloader/src/main/res/values/attrs.xml @@ -117,4 +117,14 @@ + + + + + + + + + + \ No newline at end of file