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