Skip to content
This repository has been archived by the owner on Sep 13, 2024. It is now read-only.

Commit

Permalink
Improve callbacks access through Listener class
Browse files Browse the repository at this point in the history
  • Loading branch information
acolombo11 committed Jul 3, 2019
1 parent 87f725b commit d021da2
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 26 deletions.
68 changes: 54 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# progress-indicator-view
A custom Android view showing determinate progress through a stupid but funny animation.
A custom Android view showing determinate progress through a fun/stupid animation.

There are a lot of cool animations for indeterminate progress bars, but there are not many ways to add a little fun to determinate progress bars. We needed a progress bar to show the download state of a [Dynamic Module](https://developer.android.com/studio/projects/dynamic-delivery). The designer working with me thought that the awesome Android 6 [boot animation](https://www.youtube.com/watch?v=8TGC6EmVXlU) shows the current progress of boot, and she asked me to replicate it. While that's not correct, I was intrigued by the idea and this is the result.
I did nothing more than extending romandanylyk's [PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView), adding similar setters and getters to Android [ProgressBar](https://developer.android.com/reference/android/widget/ProgressBar), and implementing a [finite-state machine](https://en.wikipedia.org/wiki/Finite-state_machine) to manage the animation while progressing.
There are a lot of cool animations for indeterminate progress bars, but there are not many ways to add a little fun to determinate progress bars. I did nothing more than extending romandanylyk's [PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView), adding similar setters and getters to Android [ProgressBar](https://developer.android.com/reference/android/widget/ProgressBar), and implementing a [finite-state machine](https://en.wikipedia.org/wiki/Finite-state_machine) to manage the animation while progressing.

![exmaple Shenzen](docs/gifs/Progress_Indicator_View_Example_2019-07-01-14-57-22.gif)
![example Shenyang](docs/gifs/Progress_Indicator_View_Example_2019-07-01-14-58-38.gif)
![exmaple Shenzen](docs/gifs/Progress_Indicator_View_Example_2019-07-03-09-41-26.gif)
![example Shenyang](docs/gifs/Progress_Indicator_View_Example_2019-07-03-09-42-41.gif)

## Download   [![Release](https://jitpack.io/v/eu.acolombo/progress-indicator-view.svg)](https://jitpack.io/#eu.acolombo/progress-indicator-view)

Expand All @@ -27,17 +26,58 @@ allprojects {

This library is AndroidX only, if you are still using Support libraries you can either migrate your app to AndroidX or you can contribute by downgrading the dependencies and subitting a pull-request, which will be merged in a different branch.

## Customization
## Usage

All [PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView)'s attributes are still valid and can be used both through Java/Kotlin and through XML. I also added a few more similar to ProgressBar's ones and a few more which I'll explain/illustrate later.
See [PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView)'s README, all the `piv_` attributes attributes are still valid (I wouldn't attach it to a ViewPager though) and in the sample below I used the most relevant ones.

stopOnStep
stepToMin
skipSteps
balanceForward
```xml
<eu.acolombo.progressindicatorview.ProgressIndicatorView
android:id="@+id/progressIndicatorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:piv_min="100"
app:piv_max="100"
app:piv_progress="0"
app:piv_count="8"
app:piv_radius="4dp"
app:piv_padding="16dp"
app:piv_animationDuration="200"
app:piv_animationType="slide"
app:piv_selectedColor="@color/colorPrimary"
app:piv_unselectedColor="@color/colorPrimaryDark" />
```

There are also a few `ProgressIndicatorView` specific attributes. They can be accessed in XML under the same prefix, `piv_`, and in kotlin/java through their respective getters/setters. The first group of attributes replicate the `ProgressBar`'ones, while the following are all flags defining the behavior of the component:

name | format | default | description
---------------- | ------- | ------- | ------------------
`min` | integer | 0 | Same as `ProgressBar` `min`. Defines the minimum value.
`max` | integer | 100 | Same as `ProgressBar` `max`. Defines the maximum value.
`progress` | integer | 0 | Same as `ProgressBar` `max`. Defines the default progress value, between min and max.
`stopOnStep` | boolean | false | When the `progress` is exactly between steps, the animation stops.
`stopOnStart` | boolean | true | When the `progress` is the same as the starting limit, the animation stops. This limit is `min` if `balanceForward` is true, `max` otherwise.
`stepToMin` | boolean | false | The animation always goes back to the first step instead of going back to the previous one.
`skipSteps` | boolean | false | If the `progress` is faster than the animation, the animation will catch up by skipping steps. *Use `setProgress(progress: Int, animate: Boolean)` if you want to skip the animation altogether.*
`balanceForward` | boolean | true | Defines the direction of the animation when the `progress` is between the two central steps (i.e. 50 with a max of 100). *Not valid when the progress is going up and down because the direction of the progress is more signficant, but it still affects `stopOnStart` as explained above.*

I also added three callbacks:

onStepChanged
onMinReached
onMaxReached
+onStepChanged
+onMinReached
+onMaxReached

I'm sorry for Java users since I didn't use the usual Listener interface to implement. I made it in a more functional way to be faster and cleaner to use in kotlin.

Their names are self explanatory and you can use them in two ways. If you want to use more than one, use the constructor for `ProgressIndicatorView.Listener`:
```kotlin
progressIndicatorView.listener = ProgressIndicatorView.Listener(
onMaxReached = { Log.d(TAG, "max" ) },
onStepChanged = { step, forward -> Log.d(TAG, "$step $forward" ) },
onMinReached = { Log.d(TAG, "min" ) }
)
```
Otherwise just redefine one of them or each at a time:
```kotlin
progressIndicatorView.listener.onMaxReached = { Log.d(TAG, "max" ) }
```
<small>*I'd like to receive some feedbacks for this choice I made and how I decided to tackle it, so if you're reading this go check out the [implementation](https://github.com/acolombo25/progress-indicator-view/blob/master/progress-indicator-view/src/main/java/eu/acolombo/progressindicatorview/ProgressIndicatorView.kt#L16) and let me know what you think.*</small>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.util.Log
import android.view.View
import android.widget.SeekBar
import androidx.fragment.app.Fragment
import eu.acolombo.progressindicatorview.ProgressIndicatorView
import kotlinx.android.synthetic.main.fragment_shenzen.*
import kotlin.random.Random

Expand All @@ -23,9 +24,13 @@ abstract class BaseFragment : Fragment() {
textMax?.text = "${progressIndicatorView.max}%"
textMin?.text = "${progressIndicatorView.min}%"

progressIndicatorView.onMaxReached = { Log.d(javaClass.name, "MAX" ) }
progressIndicatorView.onStepChanged = { step, forward -> Log.d(javaClass.name, "$step $forward" ) }
progressIndicatorView.onMinReached = { Log.d(javaClass.name, "MIN" ) }
progressIndicatorView.listener = ProgressIndicatorView.Listener(
onMaxReached = { Log.d(javaClass.name, "MAX" ) },
onStepChanged = { step, forward -> Log.d(javaClass.name, "$step $forward" ) },
onMinReached = { Log.d(javaClass.name, "MIN" ) }
)

progressIndicatorView.listener.onMaxReached = { Log.d(javaClass.name, "MAX" ) }
}

fun setupProgress(progress: Int) {
Expand Down Expand Up @@ -68,6 +73,11 @@ abstract class BaseFragment : Fragment() {
}
}

textProgress.setOnLongClickListener {
setupProgress(0)
true
}

val animator = ValueAnimator()
val random = Random(69)
val randomUnit = 60
Expand Down
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ class ProgressIndicatorView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : PageIndicatorView(context, attrs, defStyleAttr) {

class Listener(
var onStepChanged: (step: Int, forward: Boolean) -> Unit = { _, _ -> },
var onMinReached: () -> Unit = { },
var onMaxReached: () -> Unit = { }
)

var listener = Listener()

private val typedArray: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressIndicatorView)
var progress = typedArray.getInt(R.styleable.ProgressIndicatorView_piv_progress, 0)
var min = typedArray.getInt(R.styleable.ProgressIndicatorView_piv_min, 0)
Expand All @@ -24,10 +32,6 @@ class ProgressIndicatorView @JvmOverloads constructor(
var skipSteps: Boolean = typedArray.getBoolean(R.styleable.ProgressIndicatorView_piv_skipSteps, false)
var balanceForward: Boolean = typedArray.getBoolean(R.styleable.ProgressIndicatorView_piv_balanceForward, true)

var onStepChanged: (step: Int, forward: Boolean) -> Unit = { _, _ -> }
var onMinReached: () -> Unit = { }
var onMaxReached: () -> Unit = { }

fun setProgress(progress: Int, animate: Boolean) {
this.progress = progress
if (!animate) setSelected(stepProgress)
Expand Down Expand Up @@ -72,9 +76,9 @@ class ProgressIndicatorView @JvmOverloads constructor(
selection != stepProgress - 1 && skipSteps -> {
selection = stepProgress - 1
when (progress) {
min -> onMinReached()
max -> onMaxReached()
else -> onStepChanged(selection + 1, step < selection +1)
min -> listener.onMinReached()
max -> listener.onMaxReached()
else -> listener.onStepChanged(selection + 1, step < selection +1)
}
}
}
Expand All @@ -85,7 +89,7 @@ class ProgressIndicatorView @JvmOverloads constructor(
state = if ((progress < next || statePrev == State.BACKWARD && progress <= next) && !stopOnThisStep) {
State.BACKWARD
} else {
if (step < count - 1) onStepChanged(++step, true) else onMaxReached()
if (step < count - 1) listener.onStepChanged(++step, true) else listener.onMaxReached()
statePrev = state
State.STOP
}
Expand All @@ -96,7 +100,7 @@ class ProgressIndicatorView @JvmOverloads constructor(
state = if ((progress > prev || statePrev == State.FORWARD && progress >= prev) && !stopOnThisStep) {
State.FORWARD
} else {
if (step > 1) onStepChanged(--step, false) else onMinReached()
if (step > 1) listener.onStepChanged(--step, false) else listener.onMinReached()
statePrev = state
State.STOP
}
Expand Down

0 comments on commit d021da2

Please sign in to comment.