├── .gitignore ├── LICENSE ├── README.md ├── README_zh-CN.md ├── art ├── ChasingDots.gif ├── Circle.gif ├── CubeGrid.gif ├── DoubleBounce.gif ├── FadingCircle.gif ├── FoldingCube.gif ├── Pulse.gif ├── RotatingCircle.gif ├── RotatingPlane.gif ├── ThreeBounce.gif ├── WanderingCubes.gif ├── Wave.gif ├── screen.gif ├── screen2.gif └── spinkit.apk ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── ybq │ │ └── android │ │ └── spinkit │ │ ├── SpinKitView.java │ │ ├── SpriteFactory.java │ │ ├── Style.java │ │ ├── animation │ │ ├── AnimationUtils.java │ │ ├── FloatProperty.java │ │ ├── IntProperty.java │ │ ├── SpriteAnimatorBuilder.java │ │ └── interpolator │ │ │ ├── Ease.java │ │ │ ├── KeyFrameInterpolator.java │ │ │ ├── PathInterpolatorCompat.java │ │ │ ├── PathInterpolatorCompatApi21.java │ │ │ ├── PathInterpolatorCompatBase.java │ │ │ └── PathInterpolatorDonut.java │ │ ├── sprite │ │ ├── CircleLayoutContainer.java │ │ ├── CircleSprite.java │ │ ├── RectSprite.java │ │ ├── RingSprite.java │ │ ├── ShapeSprite.java │ │ ├── Sprite.java │ │ └── SpriteContainer.java │ │ └── style │ │ ├── ChasingDots.java │ │ ├── Circle.java │ │ ├── CubeGrid.java │ │ ├── DoubleBounce.java │ │ ├── FadingCircle.java │ │ ├── FoldingCube.java │ │ ├── MultiplePulse.java │ │ ├── MultiplePulseRing.java │ │ ├── Pulse.java │ │ ├── PulseRing.java │ │ ├── RotatingCircle.java │ │ ├── RotatingPlane.java │ │ ├── ThreeBounce.java │ │ ├── WanderingCubes.java │ │ └── Wave.java │ └── res │ └── values │ ├── attrs.xml │ └── styles.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── ybq │ │ └── android │ │ └── loading │ │ ├── ArgbEvaluator.java │ │ ├── Colors.java │ │ ├── DetailActivity.java │ │ ├── MainActivity.java │ │ ├── SquareFrameLayout.java │ │ ├── StyleFragment.java │ │ └── WidgetFragment.java │ └── res │ ├── layout │ ├── activity_detail.xml │ ├── activity_main.xml │ ├── fragment_style.xml │ ├── fragment_widget.xml │ ├── item_pager.xml │ └── item_style.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea 38 | # Keystore files 39 | *.jks -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2016 ybq 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-SpinKit 2 | >Android loading animations(I wrote a android edition according [SpinKit](https://tobiasahlin.com/spinkit)) 3 | 4 | [Demo Apk](https://raw.githubusercontent.com/ybq/AndroidSpinKit/master/art/spinkit.apk) 5 | 6 | ## Preview 7 | 8 | 9 | 10 | 11 | 12 | ## Gradle Dependency 13 | 14 | ``` gradle 15 | dependencies { 16 | implementation 'com.github.ybq:Android-SpinKit:1.4.0' 17 | } 18 | ``` 19 | 20 | 21 | ## Usage 22 | - Xml 23 | 24 | ```xml 25 | 33 | ``` 34 | 35 | - ProgressBar 36 | 37 | ```java 38 | ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress); 39 | Sprite doubleBounce = new DoubleBounce(); 40 | progressBar.setIndeterminateDrawable(doubleBounce); 41 | ``` 42 | 43 | ## Style 44 | > 45 | ```xml 46 | @style/SpinKitView 47 | @style/SpinKitView.Circle 48 | @style/SpinKitView.Large 49 | @style/SpinKitView.Small 50 | @style/SpinKitView.Small.DoubleBounce 51 | ``` 52 | 53 | Style | Preview 54 | ------------ | ------------- 55 | RotatingPlane | RotatingPlane 56 | DoubleBounce | DoubleBounce 57 | Wave | Wave 58 | WanderingCubes | WanderingCubes 59 | Pulse | Pulse 60 | ChasingDots | ChasingDots 61 | ThreeBounce | ThreeBounce 62 | Circle | Circle 63 | CubeGrid | CubeGrid 64 | FadingCircle | FadingCircle 65 | FoldingCube | FoldingCube 66 | RotatingCircle | RotatingCircle 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ## Acknowledgements 75 | - [SpinKit](https://github.com/tobiasahlin/SpinKit). 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /README_zh-CN.md: -------------------------------------------------------------------------------- 1 | 2 | # Android-SpinKit 3 | 4 | > Android 加载动画([SpinKit](https://tobiasahlin.com/spinkit)的Android版本实现) 5 | 6 | [Demo Apk](https://raw.githubusercontent.com/ybq/AndroidSpinKit/master/art/spinkit.apk) 7 | 8 | ## 效果 9 | 10 | 11 | 12 | 13 | 14 | 15 | ## Gradle 依赖 16 | 17 | 18 | ``` gradle 19 | dependencies { 20 | implementation 'com.github.ybq:Android-SpinKit:1.4.0' 21 | } 22 | ``` 23 | 24 | 25 | ## 使用 26 | - Xml 27 | 28 | ```xml 29 | 37 | ``` 38 | 39 | 40 | - ProgressBar 41 | 42 | ```java 43 | ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress); 44 | DoubleBounce doubleBounce = new DoubleBounce(); 45 | progressBar.setIndeterminateDrawable(doubleBounce); 46 | ``` 47 | 48 | ###样式: 49 | 50 | 样式 | 预览 51 | ------------ | ------------- 52 | RotatingPlane | RotatingPlane 53 | DoubleBounce | DoubleBounce 54 | Wave | Wave 55 | WanderingCubes | WanderingCubes 56 | Pulse | Pulse 57 | ChasingDots | ChasingDots 58 | ThreeBounce | ThreeBounce 59 | Circle | Circle 60 | CubeGrid | CubeGrid 61 | FadingCircle | FadingCircle 62 | FoldingCube | FoldingCube 63 | RotatingCircle | RotatingCircle 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | ##感谢 72 | - [SpinKit](https://github.com/tobiasahlin/SpinKit). 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /art/ChasingDots.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/ChasingDots.gif -------------------------------------------------------------------------------- /art/Circle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/Circle.gif -------------------------------------------------------------------------------- /art/CubeGrid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/CubeGrid.gif -------------------------------------------------------------------------------- /art/DoubleBounce.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/DoubleBounce.gif -------------------------------------------------------------------------------- /art/FadingCircle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/FadingCircle.gif -------------------------------------------------------------------------------- /art/FoldingCube.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/FoldingCube.gif -------------------------------------------------------------------------------- /art/Pulse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/Pulse.gif -------------------------------------------------------------------------------- /art/RotatingCircle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/RotatingCircle.gif -------------------------------------------------------------------------------- /art/RotatingPlane.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/RotatingPlane.gif -------------------------------------------------------------------------------- /art/ThreeBounce.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/ThreeBounce.gif -------------------------------------------------------------------------------- /art/WanderingCubes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/WanderingCubes.gif -------------------------------------------------------------------------------- /art/Wave.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/Wave.gif -------------------------------------------------------------------------------- /art/screen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/screen.gif -------------------------------------------------------------------------------- /art/screen2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/screen2.gif -------------------------------------------------------------------------------- /art/spinkit.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/art/spinkit.apk -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:3.2.1' 8 | classpath 'com.novoda:bintray-release:0.8.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | task clean(type: Delete) { 20 | delete rootProject.buildDir 21 | } 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | android.enableJetifier=true 20 | android.useAndroidX=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Nov 14 15:17:22 WET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release' 3 | 4 | android { 5 | 6 | compileSdkVersion 28 7 | buildToolsVersion '28.0.3' 8 | 9 | defaultConfig { 10 | minSdkVersion 14 11 | targetSdkVersion 28 12 | } 13 | 14 | lintOptions { 15 | abortOnError false 16 | } 17 | } 18 | 19 | 20 | publish { 21 | userOrg = 'ybq' 22 | groupId = 'com.github.ybq' 23 | artifactId = 'Android-SpinKit' 24 | publishVersion = '1.4.0' 25 | desc = 'Android loading animations' 26 | website = 'https://github.com/ybq/Android-SpinKit' 27 | licences = ['MIT'] 28 | } -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybq/Android-SpinKit/aa83e4d0a42c76eae15e8b18b79aa2a231cca5f8/library/gradle.properties -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/ybq/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/SpinKitView.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Color; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Build; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | import android.widget.ProgressBar; 12 | 13 | import com.github.ybq.android.spinkit.sprite.Sprite; 14 | 15 | /** 16 | * Created by ybq. 17 | */ 18 | public class SpinKitView extends ProgressBar { 19 | 20 | private Style mStyle; 21 | private int mColor; 22 | private Sprite mSprite; 23 | 24 | public SpinKitView(Context context) { 25 | this(context, null); 26 | } 27 | 28 | public SpinKitView(Context context, AttributeSet attrs) { 29 | this(context, attrs, R.attr.SpinKitViewStyle); 30 | } 31 | 32 | public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr) { 33 | this(context, attrs, defStyleAttr, R.style.SpinKitView); 34 | } 35 | 36 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 37 | public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 38 | super(context, attrs, defStyleAttr, defStyleRes); 39 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpinKitView, defStyleAttr, 40 | defStyleRes); 41 | mStyle = Style.values()[a.getInt(R.styleable.SpinKitView_SpinKit_Style, 0)]; 42 | mColor = a.getColor(R.styleable.SpinKitView_SpinKit_Color, Color.WHITE); 43 | a.recycle(); 44 | init(); 45 | setIndeterminate(true); 46 | } 47 | 48 | private void init() { 49 | Sprite sprite = SpriteFactory.create(mStyle); 50 | sprite.setColor(mColor); 51 | setIndeterminateDrawable(sprite); 52 | } 53 | 54 | @Override 55 | public void setIndeterminateDrawable(Drawable d) { 56 | if (!(d instanceof Sprite)) { 57 | throw new IllegalArgumentException("this d must be instanceof Sprite"); 58 | } 59 | setIndeterminateDrawable((Sprite) d); 60 | } 61 | 62 | public void setIndeterminateDrawable(Sprite d) { 63 | super.setIndeterminateDrawable(d); 64 | mSprite = d; 65 | if (mSprite.getColor() == 0) { 66 | 67 | mSprite.setColor(mColor); 68 | } 69 | onSizeChanged(getWidth(), getHeight(), getWidth(), getHeight()); 70 | if (getVisibility() == VISIBLE) { 71 | 72 | mSprite.start(); 73 | } 74 | } 75 | 76 | @Override 77 | public Sprite getIndeterminateDrawable() { 78 | return mSprite; 79 | } 80 | 81 | public void setColor(int color) { 82 | this.mColor = color; 83 | if (mSprite != null) { 84 | 85 | mSprite.setColor(color); 86 | } 87 | invalidate(); 88 | } 89 | 90 | @Override 91 | public void unscheduleDrawable(Drawable who) { 92 | super.unscheduleDrawable(who); 93 | if (who instanceof Sprite) { 94 | 95 | ((Sprite) who).stop(); 96 | } 97 | } 98 | 99 | @Override 100 | public void onWindowFocusChanged(boolean hasWindowFocus) { 101 | super.onWindowFocusChanged(hasWindowFocus); 102 | if (hasWindowFocus) { 103 | if (mSprite != null && getVisibility() == VISIBLE) { 104 | 105 | mSprite.start(); 106 | } 107 | } 108 | } 109 | 110 | @Override 111 | public void onScreenStateChanged(int screenState) { 112 | super.onScreenStateChanged(screenState); 113 | if (screenState == View.SCREEN_STATE_OFF) { 114 | 115 | if (mSprite != null) { 116 | 117 | mSprite.stop(); 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/SpriteFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit; 2 | 3 | import com.github.ybq.android.spinkit.sprite.Sprite; 4 | import com.github.ybq.android.spinkit.style.ChasingDots; 5 | import com.github.ybq.android.spinkit.style.Circle; 6 | import com.github.ybq.android.spinkit.style.CubeGrid; 7 | import com.github.ybq.android.spinkit.style.DoubleBounce; 8 | import com.github.ybq.android.spinkit.style.FadingCircle; 9 | import com.github.ybq.android.spinkit.style.FoldingCube; 10 | import com.github.ybq.android.spinkit.style.MultiplePulse; 11 | import com.github.ybq.android.spinkit.style.MultiplePulseRing; 12 | import com.github.ybq.android.spinkit.style.Pulse; 13 | import com.github.ybq.android.spinkit.style.PulseRing; 14 | import com.github.ybq.android.spinkit.style.RotatingCircle; 15 | import com.github.ybq.android.spinkit.style.RotatingPlane; 16 | import com.github.ybq.android.spinkit.style.ThreeBounce; 17 | import com.github.ybq.android.spinkit.style.WanderingCubes; 18 | import com.github.ybq.android.spinkit.style.Wave; 19 | 20 | /** 21 | * Created by ybq. 22 | */ 23 | public class SpriteFactory { 24 | 25 | public static Sprite create(Style style) { 26 | Sprite sprite = null; 27 | switch (style) { 28 | case ROTATING_PLANE: 29 | sprite = new RotatingPlane(); 30 | break; 31 | case DOUBLE_BOUNCE: 32 | sprite = new DoubleBounce(); 33 | break; 34 | case WAVE: 35 | sprite = new Wave(); 36 | break; 37 | case WANDERING_CUBES: 38 | sprite = new WanderingCubes(); 39 | break; 40 | case PULSE: 41 | sprite = new Pulse(); 42 | break; 43 | case CHASING_DOTS: 44 | sprite = new ChasingDots(); 45 | break; 46 | case THREE_BOUNCE: 47 | sprite = new ThreeBounce(); 48 | break; 49 | case CIRCLE: 50 | sprite = new Circle(); 51 | break; 52 | case CUBE_GRID: 53 | sprite = new CubeGrid(); 54 | break; 55 | case FADING_CIRCLE: 56 | sprite = new FadingCircle(); 57 | break; 58 | case FOLDING_CUBE: 59 | sprite = new FoldingCube(); 60 | break; 61 | case ROTATING_CIRCLE: 62 | sprite = new RotatingCircle(); 63 | break; 64 | case MULTIPLE_PULSE: 65 | sprite = new MultiplePulse(); 66 | break; 67 | case PULSE_RING: 68 | sprite = new PulseRing(); 69 | break; 70 | case MULTIPLE_PULSE_RING: 71 | sprite = new MultiplePulseRing(); 72 | break; 73 | default: 74 | break; 75 | } 76 | return sprite; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/Style.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit; 2 | 3 | /** 4 | * Created by ybq. 5 | */ 6 | public enum Style { 7 | 8 | ROTATING_PLANE(0), 9 | DOUBLE_BOUNCE(1), 10 | WAVE(2), 11 | WANDERING_CUBES(3), 12 | PULSE(4), 13 | CHASING_DOTS(5), 14 | THREE_BOUNCE(6), 15 | CIRCLE(7), 16 | CUBE_GRID(8), 17 | FADING_CIRCLE(9), 18 | FOLDING_CUBE(10), 19 | ROTATING_CIRCLE(11), 20 | MULTIPLE_PULSE(12), 21 | PULSE_RING(13), 22 | MULTIPLE_PULSE_RING(14); 23 | 24 | @SuppressWarnings({"FieldCanBeLocal", "unused"}) 25 | private int value; 26 | 27 | Style(int value) { 28 | this.value = value; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/AnimationUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.animation; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | 6 | import com.github.ybq.android.spinkit.sprite.Sprite; 7 | 8 | /** 9 | * Created by ybq. 10 | */ 11 | public class AnimationUtils { 12 | 13 | public static void start(Animator animator) { 14 | if (animator != null && !animator.isStarted()) { 15 | animator.start(); 16 | } 17 | } 18 | 19 | public static void stop(Animator animator) { 20 | if (animator != null && !animator.isRunning()) { 21 | animator.end(); 22 | } 23 | } 24 | 25 | public static void start(Sprite... sprites) { 26 | for (Sprite sprite : sprites) { 27 | sprite.start(); 28 | } 29 | } 30 | 31 | public static void stop(Sprite... sprites) { 32 | for (Sprite sprite : sprites) { 33 | sprite.stop(); 34 | } 35 | } 36 | 37 | public static boolean isRunning(Sprite... sprites) { 38 | for (Sprite sprite : sprites) { 39 | if (sprite.isRunning()) { 40 | return true; 41 | } 42 | } 43 | return false; 44 | } 45 | 46 | public static boolean isRunning(ValueAnimator animator) { 47 | return animator != null && animator.isRunning(); 48 | } 49 | 50 | public static boolean isStarted(ValueAnimator animator) { 51 | return animator != null && animator.isStarted(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/FloatProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.ybq.android.spinkit.animation; 17 | 18 | import android.util.Property; 19 | 20 | /** 21 | * An implementation of {@link android.util.Property} to be used specifically with fields of type 22 | * float. This type-specific subclass enables performance benefit by allowing 23 | * calls to a {@link #set(Object, Float) set()} function that takes the primitive 24 | * float type and avoids autoboxing and other overhead associated with the 25 | * Float class. 26 | * 27 | * @param The class on which the Property is declared. 28 | */ 29 | public abstract class FloatProperty extends Property { 30 | 31 | public FloatProperty(String name) { 32 | super(Float.class, name); 33 | } 34 | 35 | /** 36 | * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing 37 | * with fields of type float. 38 | */ 39 | public abstract void setValue(T object, float value); 40 | 41 | @Override 42 | final public void set(T object, Float value) { 43 | setValue(object, value); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/IntProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.ybq.android.spinkit.animation; 17 | 18 | import android.util.Property; 19 | 20 | /** 21 | * An implementation of {@link android.util.Property} to be used specifically with fields of type 22 | * int. This type-specific subclass enables performance benefit by allowing 23 | * calls to a {@link #set(Object, Integer) set()} function that takes the primitive 24 | * int type and avoids autoboxing and other overhead associated with the 25 | * Integer class. 26 | * 27 | * @param The class on which the Property is declared. 28 | */ 29 | public abstract class IntProperty extends Property { 30 | 31 | public IntProperty(String name) { 32 | super(Integer.class, name); 33 | } 34 | 35 | /** 36 | * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing 37 | * with fields of type int. 38 | */ 39 | public abstract void setValue(T object, int value); 40 | 41 | @Override 42 | final public void set(T object, Integer value) { 43 | setValue(object, value); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/SpriteAnimatorBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.animation; 2 | 3 | import android.animation.Keyframe; 4 | import android.animation.ObjectAnimator; 5 | import android.animation.PropertyValuesHolder; 6 | import android.util.Log; 7 | import android.util.Property; 8 | import android.view.animation.Animation; 9 | import android.view.animation.Interpolator; 10 | 11 | import com.github.ybq.android.spinkit.animation.interpolator.KeyFrameInterpolator; 12 | import com.github.ybq.android.spinkit.sprite.Sprite; 13 | 14 | import java.util.HashMap; 15 | import java.util.Locale; 16 | import java.util.Map; 17 | 18 | /** 19 | * Created by ybq. 20 | */ 21 | public class SpriteAnimatorBuilder { 22 | 23 | private static final String TAG = "SpriteAnimatorBuilder"; 24 | private Sprite sprite; 25 | private Interpolator interpolator; 26 | private int repeatCount = Animation.INFINITE; 27 | private long duration = 2000; 28 | private int startFrame = 0; 29 | private Map fds = new HashMap<>(); 30 | 31 | 32 | class FrameData { 33 | public FrameData(float[] fractions, Property property, T[] values) { 34 | this.fractions = fractions; 35 | this.property = property; 36 | this.values = values; 37 | } 38 | 39 | float[] fractions; 40 | Property property; 41 | T[] values; 42 | } 43 | 44 | class IntFrameData extends FrameData { 45 | 46 | public IntFrameData(float[] fractions, Property property, Integer[] values) { 47 | super(fractions, property, values); 48 | } 49 | } 50 | 51 | class FloatFrameData extends FrameData { 52 | 53 | public FloatFrameData(float[] fractions, Property property, Float[] values) { 54 | super(fractions, property, values); 55 | } 56 | } 57 | 58 | public SpriteAnimatorBuilder(Sprite sprite) { 59 | this.sprite = sprite; 60 | } 61 | 62 | public SpriteAnimatorBuilder scale(float fractions[], Float... scale) { 63 | holder(fractions, Sprite.SCALE, scale); 64 | return this; 65 | } 66 | 67 | public SpriteAnimatorBuilder alpha(float fractions[], Integer... alpha) { 68 | holder(fractions, Sprite.ALPHA, alpha); 69 | return this; 70 | } 71 | 72 | @SuppressWarnings("unused") 73 | public SpriteAnimatorBuilder scaleX(float fractions[], Float... scaleX) { 74 | holder(fractions, Sprite.SCALE, scaleX); 75 | return this; 76 | } 77 | 78 | public SpriteAnimatorBuilder scaleY(float fractions[], Float... scaleY) { 79 | holder(fractions, Sprite.SCALE_Y, scaleY); 80 | return this; 81 | } 82 | 83 | public SpriteAnimatorBuilder rotateX(float fractions[], Integer... rotateX) { 84 | holder(fractions, Sprite.ROTATE_X, rotateX); 85 | return this; 86 | } 87 | 88 | public SpriteAnimatorBuilder rotateY(float fractions[], Integer... rotateY) { 89 | holder(fractions, Sprite.ROTATE_Y, rotateY); 90 | return this; 91 | } 92 | 93 | @SuppressWarnings("unused") 94 | public SpriteAnimatorBuilder translateX(float fractions[], Integer... translateX) { 95 | holder(fractions, Sprite.TRANSLATE_X, translateX); 96 | return this; 97 | } 98 | 99 | 100 | @SuppressWarnings("unused") 101 | public SpriteAnimatorBuilder translateY(float fractions[], Integer... translateY) { 102 | holder(fractions, Sprite.TRANSLATE_Y, translateY); 103 | return this; 104 | } 105 | 106 | 107 | public SpriteAnimatorBuilder rotate(float fractions[], Integer... rotate) { 108 | holder(fractions, Sprite.ROTATE, rotate); 109 | return this; 110 | } 111 | 112 | public SpriteAnimatorBuilder translateXPercentage(float fractions[], Float... translateXPercentage) { 113 | holder(fractions, Sprite.TRANSLATE_X_PERCENTAGE, translateXPercentage); 114 | return this; 115 | } 116 | 117 | public SpriteAnimatorBuilder translateYPercentage(float[] fractions, Float... translateYPercentage) { 118 | holder(fractions, Sprite.TRANSLATE_Y_PERCENTAGE, translateYPercentage); 119 | return this; 120 | } 121 | 122 | private void holder(float[] fractions, Property property, Float[] values) { 123 | ensurePair(fractions.length, values.length); 124 | fds.put(property.getName(), new FloatFrameData(fractions, property, values)); 125 | } 126 | 127 | 128 | private void holder(float[] fractions, Property property, Integer[] values) { 129 | ensurePair(fractions.length, values.length); 130 | fds.put(property.getName(), new IntFrameData(fractions, property, values)); 131 | } 132 | 133 | private void ensurePair(int fractionsLength, int valuesLength) { 134 | if (fractionsLength != valuesLength) { 135 | throw new IllegalStateException(String.format( 136 | Locale.getDefault(), 137 | "The fractions.length must equal values.length, " + 138 | "fraction.length[%d], values.length[%d]", 139 | fractionsLength, 140 | valuesLength)); 141 | } 142 | } 143 | 144 | 145 | public SpriteAnimatorBuilder interpolator(Interpolator interpolator) { 146 | this.interpolator = interpolator; 147 | return this; 148 | } 149 | 150 | public SpriteAnimatorBuilder easeInOut(float... fractions) { 151 | interpolator(KeyFrameInterpolator.easeInOut( 152 | fractions 153 | )); 154 | return this; 155 | } 156 | 157 | 158 | public SpriteAnimatorBuilder duration(long duration) { 159 | this.duration = duration; 160 | return this; 161 | } 162 | 163 | @SuppressWarnings("unused") 164 | public SpriteAnimatorBuilder repeatCount(int repeatCount) { 165 | this.repeatCount = repeatCount; 166 | return this; 167 | } 168 | 169 | public SpriteAnimatorBuilder startFrame(int startFrame) { 170 | if (startFrame < 0) { 171 | Log.w(TAG, "startFrame should always be non-negative"); 172 | startFrame = 0; 173 | } 174 | this.startFrame = startFrame; 175 | return this; 176 | } 177 | 178 | public ObjectAnimator build() { 179 | 180 | PropertyValuesHolder[] holders = new PropertyValuesHolder[fds.size()]; 181 | int i = 0; 182 | for (Map.Entry fd : fds.entrySet()) { 183 | FrameData data = fd.getValue(); 184 | Keyframe[] keyframes = new Keyframe[data.fractions.length]; 185 | float[] fractions = data.fractions; 186 | float startF = fractions[startFrame]; 187 | for (int j = startFrame; j < (startFrame + data.values.length); j++) { 188 | int key = j - startFrame; 189 | int vk = j % data.values.length; 190 | float fraction = fractions[vk] - startF; 191 | if (fraction < 0) { 192 | fraction = fractions[fractions.length - 1] + fraction; 193 | } 194 | if (data instanceof IntFrameData) { 195 | keyframes[key] = Keyframe.ofInt(fraction, (Integer) data.values[vk]); 196 | } else if (data instanceof FloatFrameData) { 197 | keyframes[key] = Keyframe.ofFloat(fraction, (Float) data.values[vk]); 198 | } else { 199 | keyframes[key] = Keyframe.ofObject(fraction, data.values[vk]); 200 | } 201 | } 202 | holders[i] = PropertyValuesHolder.ofKeyframe(data.property, keyframes); 203 | i++; 204 | } 205 | 206 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(sprite, 207 | holders); 208 | animator.setDuration(duration); 209 | animator.setRepeatCount(repeatCount); 210 | animator.setInterpolator(interpolator); 211 | return animator; 212 | } 213 | 214 | } 215 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/Ease.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.animation.interpolator; 2 | 3 | import android.view.animation.Interpolator; 4 | 5 | /** 6 | * Created by ybq. 7 | */ 8 | public class Ease { 9 | public static Interpolator inOut() { 10 | return PathInterpolatorCompat.create(0.42f, 0f, 0.58f, 1f); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/KeyFrameInterpolator.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.animation.interpolator; 2 | 3 | import android.animation.TimeInterpolator; 4 | import android.view.animation.Interpolator; 5 | 6 | /** 7 | * Created by ybq. 8 | */ 9 | public class KeyFrameInterpolator implements Interpolator { 10 | 11 | private TimeInterpolator interpolator; 12 | private float[] fractions; 13 | 14 | 15 | public static KeyFrameInterpolator easeInOut(float... fractions) { 16 | KeyFrameInterpolator interpolator = new KeyFrameInterpolator(Ease.inOut()); 17 | interpolator.setFractions(fractions); 18 | return interpolator; 19 | } 20 | 21 | public static KeyFrameInterpolator pathInterpolator(float controlX1, float controlY1, 22 | float controlX2, float controlY2, 23 | float... fractions) { 24 | KeyFrameInterpolator interpolator = new KeyFrameInterpolator(PathInterpolatorCompat.create(controlX1, controlY1, controlX2, controlY2)); 25 | interpolator.setFractions(fractions); 26 | return interpolator; 27 | } 28 | 29 | public KeyFrameInterpolator(TimeInterpolator interpolator, float... fractions) { 30 | this.interpolator = interpolator; 31 | this.fractions = fractions; 32 | } 33 | 34 | public void setFractions(float... fractions) { 35 | this.fractions = fractions; 36 | } 37 | 38 | @Override 39 | public float getInterpolation(float input) { 40 | if (fractions.length > 1) { 41 | for (int i = 0; i < fractions.length - 1; i++) { 42 | float start = fractions[i]; 43 | float end = fractions[i + 1]; 44 | float duration = end - start; 45 | if (input >= start && input <= end) { 46 | input = (input - start) / duration; 47 | return start + (interpolator.getInterpolation(input) 48 | * duration); 49 | } 50 | } 51 | } 52 | return interpolator.getInterpolation(input); 53 | } 54 | } -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.ybq.android.spinkit.animation.interpolator; 18 | 19 | import android.graphics.Path; 20 | import android.os.Build; 21 | import android.view.animation.Interpolator; 22 | 23 | /** 24 | * Helper for creating path-based {@link Interpolator} instances. On API 21 or newer, the 25 | * platform implementation will be used and on older platforms a compatible alternative 26 | * implementation will be used. 27 | */ 28 | public class PathInterpolatorCompat { 29 | 30 | private PathInterpolatorCompat() { 31 | // prevent instantiation 32 | } 33 | 34 | /** 35 | * Create an {@link Interpolator} for an arbitrary {@link Path}. The {@link Path} 36 | * must begin at {@code (0, 0)} and end at {@code (1, 1)}. The x-coordinate along the 37 | * {@link Path} is the input value and the output is the y coordinate of the line at that 38 | * point. This means that the Path must conform to a function {@code y = f(x)}. 39 | *

40 | * The {@link Path} must not have gaps in the x direction and must not 41 | * loop back on itself such that there can be two points sharing the same x coordinate. 42 | * 43 | * @param path the {@link Path} to use to make the line representing the {@link Interpolator} 44 | * @return the {@link Interpolator} representing the {@link Path} 45 | */ 46 | @SuppressWarnings("unused") 47 | public static Interpolator create(Path path) { 48 | if (Build.VERSION.SDK_INT >= 21) { 49 | return PathInterpolatorCompatApi21.create(path); 50 | } 51 | return PathInterpolatorCompatBase.create(path); 52 | } 53 | 54 | /** 55 | * Create an {@link Interpolator} for a quadratic Bezier curve. The end points 56 | * {@code (0, 0)} and {@code (1, 1)} are assumed. 57 | * 58 | * @param controlX the x coordinate of the quadratic Bezier control point 59 | * @param controlY the y coordinate of the quadratic Bezier control point 60 | * @return the {@link Interpolator} representing the quadratic Bezier curve 61 | */ 62 | @SuppressWarnings("unused") 63 | public static Interpolator create(float controlX, float controlY) { 64 | if (Build.VERSION.SDK_INT >= 21) { 65 | return PathInterpolatorCompatApi21.create(controlX, controlY); 66 | } 67 | return PathInterpolatorCompatBase.create(controlX, controlY); 68 | } 69 | 70 | /** 71 | * Create an {@link Interpolator} for a cubic Bezier curve. The end points 72 | * {@code (0, 0)} and {@code (1, 1)} are assumed. 73 | * 74 | * @param controlX1 the x coordinate of the first control point of the cubic Bezier 75 | * @param controlY1 the y coordinate of the first control point of the cubic Bezier 76 | * @param controlX2 the x coordinate of the second control point of the cubic Bezier 77 | * @param controlY2 the y coordinate of the second control point of the cubic Bezier 78 | * @return the {@link Interpolator} representing the cubic Bezier curve 79 | */ 80 | public static Interpolator create(float controlX1, float controlY1, 81 | float controlX2, float controlY2) { 82 | if (Build.VERSION.SDK_INT >= 21) { 83 | return PathInterpolatorCompatApi21.create(controlX1, controlY1, controlX2, controlY2); 84 | } 85 | return PathInterpolatorCompatBase.create(controlX1, controlY1, controlX2, controlY2); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorCompatApi21.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.ybq.android.spinkit.animation.interpolator; 18 | 19 | import android.annotation.TargetApi; 20 | import android.graphics.Path; 21 | import android.os.Build; 22 | import android.view.animation.Interpolator; 23 | import android.view.animation.PathInterpolator; 24 | 25 | /** 26 | * API 21+ implementation for path interpolator compatibility. 27 | */ 28 | class PathInterpolatorCompatApi21 { 29 | 30 | private PathInterpolatorCompatApi21() { 31 | // prevent instantiation 32 | } 33 | 34 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 35 | public static Interpolator create(Path path) { 36 | return new PathInterpolator(path); 37 | } 38 | 39 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 40 | public static Interpolator create(float controlX, float controlY) { 41 | return new PathInterpolator(controlX, controlY); 42 | } 43 | 44 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 45 | public static Interpolator create(float controlX1, float controlY1, 46 | float controlX2, float controlY2) { 47 | return new PathInterpolator(controlX1, controlY1, controlX2, controlY2); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorCompatBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.ybq.android.spinkit.animation.interpolator; 18 | 19 | import android.graphics.Path; 20 | import android.view.animation.Interpolator; 21 | 22 | /** 23 | * Base implementation for path interpolator compatibility. 24 | */ 25 | class PathInterpolatorCompatBase { 26 | 27 | private PathInterpolatorCompatBase() { 28 | // prevent instantiation 29 | } 30 | 31 | public static Interpolator create(Path path) { 32 | return new PathInterpolatorDonut(path); 33 | } 34 | 35 | public static Interpolator create(float controlX, float controlY) { 36 | return new PathInterpolatorDonut(controlX, controlY); 37 | } 38 | 39 | public static Interpolator create(float controlX1, float controlY1, 40 | float controlX2, float controlY2) { 41 | return new PathInterpolatorDonut(controlX1, controlY1, controlX2, controlY2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorDonut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.ybq.android.spinkit.animation.interpolator; 17 | 18 | import android.graphics.Path; 19 | import android.graphics.PathMeasure; 20 | import android.view.animation.Interpolator; 21 | 22 | /** 23 | * A path interpolator implementation compatible with API 4+. 24 | */ 25 | class PathInterpolatorDonut implements Interpolator { 26 | 27 | /** 28 | * Governs the accuracy of the approximation of the {@link Path}. 29 | */ 30 | private static final float PRECISION = 0.002f; 31 | 32 | private final float[] mX; 33 | private final float[] mY; 34 | 35 | public PathInterpolatorDonut(Path path) { 36 | final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); 37 | 38 | final float pathLength = pathMeasure.getLength(); 39 | final int numPoints = (int) (pathLength / PRECISION) + 1; 40 | 41 | mX = new float[numPoints]; 42 | mY = new float[numPoints]; 43 | 44 | final float[] position = new float[2]; 45 | for (int i = 0; i < numPoints; ++i) { 46 | final float distance = (i * pathLength) / (numPoints - 1); 47 | pathMeasure.getPosTan(distance, position, null /* tangent */); 48 | 49 | mX[i] = position[0]; 50 | mY[i] = position[1]; 51 | } 52 | } 53 | 54 | public PathInterpolatorDonut(float controlX, float controlY) { 55 | this(createQuad(controlX, controlY)); 56 | } 57 | 58 | public PathInterpolatorDonut(float controlX1, float controlY1, 59 | float controlX2, float controlY2) { 60 | this(createCubic(controlX1, controlY1, controlX2, controlY2)); 61 | } 62 | 63 | @Override 64 | public float getInterpolation(float t) { 65 | if (t <= 0.0f) { 66 | return 0.0f; 67 | } else if (t >= 1.0f) { 68 | return 1.0f; 69 | } 70 | 71 | // Do a binary search for the correct x to interpolate between. 72 | int startIndex = 0; 73 | int endIndex = mX.length - 1; 74 | while (endIndex - startIndex > 1) { 75 | int midIndex = (startIndex + endIndex) / 2; 76 | if (t < mX[midIndex]) { 77 | endIndex = midIndex; 78 | } else { 79 | startIndex = midIndex; 80 | } 81 | } 82 | 83 | final float xRange = mX[endIndex] - mX[startIndex]; 84 | if (xRange == 0) { 85 | return mY[startIndex]; 86 | } 87 | 88 | final float tInRange = t - mX[startIndex]; 89 | final float fraction = tInRange / xRange; 90 | 91 | final float startY = mY[startIndex]; 92 | final float endY = mY[endIndex]; 93 | 94 | return startY + (fraction * (endY - startY)); 95 | } 96 | 97 | private static Path createQuad(float controlX, float controlY) { 98 | final Path path = new Path(); 99 | path.moveTo(0.0f, 0.0f); 100 | path.quadTo(controlX, controlY, 1.0f, 1.0f); 101 | return path; 102 | } 103 | 104 | private static Path createCubic(float controlX1, float controlY1, 105 | float controlX2, float controlY2) { 106 | final Path path = new Path(); 107 | path.moveTo(0.0f, 0.0f); 108 | path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f); 109 | return path; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/CircleLayoutContainer.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | 6 | /** 7 | * Created by ybq. 8 | */ 9 | public abstract class CircleLayoutContainer extends SpriteContainer { 10 | 11 | @Override 12 | public void drawChild(Canvas canvas) { 13 | for (int i = 0; i < getChildCount(); i++) { 14 | Sprite sprite = getChildAt(i); 15 | int count = canvas.save(); 16 | canvas.rotate(i * 360 / getChildCount(), 17 | getBounds().centerX(), 18 | getBounds().centerY()); 19 | sprite.draw(canvas); 20 | canvas.restoreToCount(count); 21 | } 22 | } 23 | 24 | @Override 25 | protected void onBoundsChange(Rect bounds) { 26 | super.onBoundsChange(bounds); 27 | bounds = clipSquare(bounds); 28 | int radius = (int) (bounds.width() * Math.PI / 3.6f / getChildCount()); 29 | int left = bounds.centerX() - radius; 30 | int right = bounds.centerX() + radius; 31 | for (int i = 0; i < getChildCount(); i++) { 32 | Sprite sprite = getChildAt(i); 33 | sprite.setDrawBounds(left, bounds.top, right, bounds.top + radius * 2); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/CircleSprite.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | 7 | /** 8 | * Created by ybq. 9 | */ 10 | public class CircleSprite extends ShapeSprite { 11 | 12 | @Override 13 | public ValueAnimator onCreateAnimation() { 14 | return null; 15 | } 16 | 17 | @Override 18 | public void drawShape(Canvas canvas, Paint paint) { 19 | if (getDrawBounds() != null) { 20 | int radius = Math.min(getDrawBounds().width(), getDrawBounds().height()) / 2; 21 | canvas.drawCircle(getDrawBounds().centerX(), 22 | getDrawBounds().centerY(), 23 | radius, paint); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/RectSprite.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | 7 | /** 8 | * Created by ybq. 9 | */ 10 | public class RectSprite extends ShapeSprite { 11 | @Override 12 | public ValueAnimator onCreateAnimation() { 13 | return null; 14 | } 15 | 16 | @Override 17 | public void drawShape(Canvas canvas, Paint paint) { 18 | if (getDrawBounds() != null) { 19 | canvas.drawRect(getDrawBounds(), paint); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/RingSprite.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | 7 | /** 8 | * Created by ybq. 9 | */ 10 | public class RingSprite extends ShapeSprite { 11 | 12 | 13 | @Override 14 | public void drawShape(Canvas canvas, Paint paint) { 15 | if (getDrawBounds() != null) { 16 | paint.setStyle(Paint.Style.STROKE); 17 | int radius = Math.min(getDrawBounds().width(), getDrawBounds().height()) / 2; 18 | paint.setStrokeWidth(radius / 12); 19 | canvas.drawCircle(getDrawBounds().centerX(), 20 | getDrawBounds().centerY(), 21 | radius, paint); 22 | } 23 | } 24 | 25 | @Override 26 | public ValueAnimator onCreateAnimation() { 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/ShapeSprite.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.ColorFilter; 6 | import android.graphics.Paint; 7 | 8 | /** 9 | * Created by ybq. 10 | */ 11 | public abstract class ShapeSprite extends Sprite { 12 | 13 | private Paint mPaint; 14 | private int mUseColor; 15 | private int mBaseColor; 16 | 17 | public ShapeSprite() { 18 | setColor(Color.WHITE); 19 | mPaint = new Paint(); 20 | mPaint.setAntiAlias(true); 21 | mPaint.setColor(mUseColor); 22 | } 23 | 24 | @Override 25 | public void setColor(int color) { 26 | mBaseColor = color; 27 | updateUseColor(); 28 | } 29 | 30 | @Override 31 | public int getColor() { 32 | return mBaseColor; 33 | } 34 | 35 | @SuppressWarnings("unused") 36 | public int getUseColor() { 37 | return mUseColor; 38 | } 39 | 40 | @Override 41 | public void setAlpha(int alpha) { 42 | super.setAlpha(alpha); 43 | updateUseColor(); 44 | } 45 | 46 | private void updateUseColor() { 47 | int alpha = getAlpha(); 48 | alpha += alpha >> 7; 49 | final int baseAlpha = mBaseColor >>> 24; 50 | final int useAlpha = baseAlpha * alpha >> 8; 51 | mUseColor = (mBaseColor << 8 >>> 8) | (useAlpha << 24); 52 | } 53 | 54 | @Override 55 | public void setColorFilter(ColorFilter colorFilter) { 56 | mPaint.setColorFilter(colorFilter); 57 | } 58 | 59 | @Override 60 | protected final void drawSelf(Canvas canvas) { 61 | mPaint.setColor(mUseColor); 62 | drawShape(canvas, mPaint); 63 | } 64 | 65 | public abstract void drawShape(Canvas canvas, Paint paint); 66 | } 67 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/Sprite.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Camera; 5 | import android.graphics.Canvas; 6 | import android.graphics.ColorFilter; 7 | import android.graphics.Matrix; 8 | import android.graphics.PixelFormat; 9 | import android.graphics.Rect; 10 | import android.graphics.drawable.Animatable; 11 | import android.graphics.drawable.Drawable; 12 | import android.util.Property; 13 | 14 | import com.github.ybq.android.spinkit.animation.AnimationUtils; 15 | import com.github.ybq.android.spinkit.animation.FloatProperty; 16 | import com.github.ybq.android.spinkit.animation.IntProperty; 17 | 18 | /** 19 | * Created by ybq. 20 | */ 21 | public abstract class Sprite extends Drawable implements 22 | ValueAnimator.AnimatorUpdateListener 23 | , Animatable 24 | , Drawable.Callback { 25 | 26 | private float scale = 1; 27 | private float scaleX = 1; 28 | private float scaleY = 1; 29 | private float pivotX; 30 | private float pivotY; 31 | private int animationDelay; 32 | private int rotateX; 33 | private int rotateY; 34 | private int translateX; 35 | private int translateY; 36 | private int rotate; 37 | private float translateXPercentage; 38 | private float translateYPercentage; 39 | private ValueAnimator animator; 40 | private int alpha = 255; 41 | private static final Rect ZERO_BOUNDS_RECT = new Rect(); 42 | protected Rect drawBounds = ZERO_BOUNDS_RECT; 43 | private Camera mCamera; 44 | private Matrix mMatrix; 45 | 46 | public Sprite() { 47 | mCamera = new Camera(); 48 | mMatrix = new Matrix(); 49 | } 50 | 51 | public abstract int getColor(); 52 | 53 | public abstract void setColor(int color); 54 | 55 | @Override 56 | public void setAlpha(int alpha) { 57 | this.alpha = alpha; 58 | } 59 | 60 | @Override 61 | public int getAlpha() { 62 | return alpha; 63 | } 64 | 65 | @Override 66 | public int getOpacity() { 67 | return PixelFormat.TRANSLUCENT; 68 | } 69 | 70 | public float getTranslateXPercentage() { 71 | return translateXPercentage; 72 | } 73 | 74 | public void setTranslateXPercentage(float translateXPercentage) { 75 | this.translateXPercentage = translateXPercentage; 76 | } 77 | 78 | public float getTranslateYPercentage() { 79 | return translateYPercentage; 80 | } 81 | 82 | public void setTranslateYPercentage(float translateYPercentage) { 83 | this.translateYPercentage = translateYPercentage; 84 | } 85 | 86 | public int getTranslateX() { 87 | return translateX; 88 | } 89 | 90 | public void setTranslateX(int translateX) { 91 | this.translateX = translateX; 92 | } 93 | 94 | public int getTranslateY() { 95 | return translateY; 96 | } 97 | 98 | public void setTranslateY(int translateY) { 99 | this.translateY = translateY; 100 | } 101 | 102 | public int getRotate() { 103 | return rotate; 104 | } 105 | 106 | public void setRotate(int rotate) { 107 | this.rotate = rotate; 108 | } 109 | 110 | public float getScale() { 111 | return scale; 112 | } 113 | 114 | public void setScale(float scale) { 115 | this.scale = scale; 116 | setScaleX(scale); 117 | setScaleY(scale); 118 | } 119 | 120 | public float getScaleX() { 121 | return scaleX; 122 | } 123 | 124 | public void setScaleX(float scaleX) { 125 | this.scaleX = scaleX; 126 | } 127 | 128 | public float getScaleY() { 129 | return scaleY; 130 | } 131 | 132 | public void setScaleY(float scaleY) { 133 | this.scaleY = scaleY; 134 | } 135 | 136 | public int getRotateX() { 137 | return rotateX; 138 | } 139 | 140 | public void setRotateX(int rotateX) { 141 | this.rotateX = rotateX; 142 | } 143 | 144 | public int getRotateY() { 145 | return rotateY; 146 | } 147 | 148 | public void setRotateY(int rotateY) { 149 | this.rotateY = rotateY; 150 | } 151 | 152 | public float getPivotX() { 153 | return pivotX; 154 | } 155 | 156 | public void setPivotX(float pivotX) { 157 | this.pivotX = pivotX; 158 | } 159 | 160 | public float getPivotY() { 161 | return pivotY; 162 | } 163 | 164 | public void setPivotY(float pivotY) { 165 | this.pivotY = pivotY; 166 | } 167 | 168 | @SuppressWarnings("unused") 169 | public int getAnimationDelay() { 170 | return animationDelay; 171 | } 172 | 173 | public Sprite setAnimationDelay(int animationDelay) { 174 | this.animationDelay = animationDelay; 175 | return this; 176 | } 177 | 178 | @Override 179 | public void setColorFilter(ColorFilter colorFilter) { 180 | 181 | } 182 | 183 | public abstract ValueAnimator onCreateAnimation(); 184 | 185 | @Override 186 | public void start() { 187 | if (AnimationUtils.isStarted(animator)) { 188 | return; 189 | } 190 | 191 | animator = obtainAnimation(); 192 | if (animator == null) { 193 | return; 194 | } 195 | 196 | AnimationUtils.start(animator); 197 | invalidateSelf(); 198 | } 199 | 200 | public ValueAnimator obtainAnimation() { 201 | if (animator == null) { 202 | animator = onCreateAnimation(); 203 | } 204 | if (animator != null) { 205 | animator.addUpdateListener(this); 206 | animator.setStartDelay(animationDelay); 207 | } 208 | return animator; 209 | } 210 | 211 | @Override 212 | public void stop() { 213 | if (AnimationUtils.isStarted(animator)) { 214 | animator.removeAllUpdateListeners(); 215 | animator.end(); 216 | reset(); 217 | } 218 | } 219 | 220 | protected abstract void drawSelf(Canvas canvas); 221 | 222 | public void reset() { 223 | scale = 1; 224 | rotateX = 0; 225 | rotateY = 0; 226 | translateX = 0; 227 | translateY = 0; 228 | rotate = 0; 229 | translateXPercentage = 0f; 230 | translateYPercentage = 0f; 231 | } 232 | 233 | @Override 234 | public boolean isRunning() { 235 | return AnimationUtils.isRunning(animator); 236 | } 237 | 238 | @Override 239 | protected void onBoundsChange(Rect bounds) { 240 | super.onBoundsChange(bounds); 241 | setDrawBounds(bounds); 242 | } 243 | 244 | public void setDrawBounds(Rect drawBounds) { 245 | setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom); 246 | } 247 | 248 | public void setDrawBounds(int left, int top, int right, int bottom) { 249 | this.drawBounds = new Rect(left, top, right, bottom); 250 | setPivotX(getDrawBounds().centerX()); 251 | setPivotY(getDrawBounds().centerY()); 252 | } 253 | 254 | @Override 255 | public void invalidateDrawable(Drawable who) { 256 | invalidateSelf(); 257 | } 258 | 259 | @Override 260 | public void scheduleDrawable(Drawable who, Runnable what, long when) { 261 | 262 | } 263 | 264 | @Override 265 | public void unscheduleDrawable(Drawable who, Runnable what) { 266 | 267 | } 268 | 269 | @Override 270 | public void onAnimationUpdate(ValueAnimator animation) { 271 | final Callback callback = getCallback(); 272 | if (callback != null) { 273 | callback.invalidateDrawable(this); 274 | } 275 | } 276 | 277 | public Rect getDrawBounds() { 278 | return drawBounds; 279 | } 280 | 281 | @Override 282 | public void draw(Canvas canvas) { 283 | int tx = getTranslateX(); 284 | tx = tx == 0 ? (int) (getBounds().width() * getTranslateXPercentage()) : tx; 285 | int ty = getTranslateY(); 286 | ty = ty == 0 ? (int) (getBounds().height() * getTranslateYPercentage()) : ty; 287 | canvas.translate(tx, ty); 288 | canvas.scale(getScaleX(), getScaleY(), getPivotX(), getPivotY()); 289 | canvas.rotate(getRotate(), getPivotX(), getPivotY()); 290 | 291 | if (getRotateX() != 0 || getRotateY() != 0) { 292 | mCamera.save(); 293 | mCamera.rotateX(getRotateX()); 294 | mCamera.rotateY(getRotateY()); 295 | mCamera.getMatrix(mMatrix); 296 | mMatrix.preTranslate(-getPivotX(), -getPivotY()); 297 | mMatrix.postTranslate(getPivotX(), getPivotY()); 298 | mCamera.restore(); 299 | canvas.concat(mMatrix); 300 | } 301 | drawSelf(canvas); 302 | } 303 | 304 | public Rect clipSquare(Rect rect) { 305 | int w = rect.width(); 306 | int h = rect.height(); 307 | int min = Math.min(w, h); 308 | int cx = rect.centerX(); 309 | int cy = rect.centerY(); 310 | int r = min / 2; 311 | return new Rect( 312 | cx - r, 313 | cy - r, 314 | cx + r, 315 | cy + r 316 | ); 317 | } 318 | 319 | public static final Property ROTATE_X = new IntProperty("rotateX") { 320 | @Override 321 | public void setValue(Sprite object, int value) { 322 | object.setRotateX(value); 323 | } 324 | 325 | @Override 326 | public Integer get(Sprite object) { 327 | return object.getRotateX(); 328 | } 329 | }; 330 | 331 | public static final Property ROTATE = new IntProperty("rotate") { 332 | @Override 333 | public void setValue(Sprite object, int value) { 334 | object.setRotate(value); 335 | } 336 | 337 | @Override 338 | public Integer get(Sprite object) { 339 | return object.getRotate(); 340 | } 341 | }; 342 | 343 | public static final Property ROTATE_Y = new IntProperty("rotateY") { 344 | @Override 345 | public void setValue(Sprite object, int value) { 346 | object.setRotateY(value); 347 | } 348 | 349 | @Override 350 | public Integer get(Sprite object) { 351 | return object.getRotateY(); 352 | } 353 | }; 354 | 355 | @SuppressWarnings("unused") 356 | public static final Property TRANSLATE_X = new IntProperty("translateX") { 357 | @Override 358 | public void setValue(Sprite object, int value) { 359 | object.setTranslateX(value); 360 | } 361 | 362 | @Override 363 | public Integer get(Sprite object) { 364 | return object.getTranslateX(); 365 | } 366 | }; 367 | 368 | @SuppressWarnings("unused") 369 | public static final Property TRANSLATE_Y = new IntProperty("translateY") { 370 | @Override 371 | public void setValue(Sprite object, int value) { 372 | object.setTranslateY(value); 373 | } 374 | 375 | @Override 376 | public Integer get(Sprite object) { 377 | return object.getTranslateY(); 378 | } 379 | }; 380 | 381 | public static final Property TRANSLATE_X_PERCENTAGE = new FloatProperty("translateXPercentage") { 382 | @Override 383 | public void setValue(Sprite object, float value) { 384 | object.setTranslateXPercentage(value); 385 | } 386 | 387 | @Override 388 | public Float get(Sprite object) { 389 | return object.getTranslateXPercentage(); 390 | } 391 | }; 392 | 393 | public static final Property TRANSLATE_Y_PERCENTAGE = new FloatProperty("translateYPercentage") { 394 | @Override 395 | public void setValue(Sprite object, float value) { 396 | object.setTranslateYPercentage(value); 397 | } 398 | 399 | @Override 400 | public Float get(Sprite object) { 401 | return object.getTranslateYPercentage(); 402 | } 403 | }; 404 | 405 | @SuppressWarnings("unused") 406 | public static final Property SCALE_X = new FloatProperty("scaleX") { 407 | @Override 408 | public void setValue(Sprite object, float value) { 409 | object.setScaleX(value); 410 | } 411 | 412 | @Override 413 | public Float get(Sprite object) { 414 | return object.getScaleX(); 415 | } 416 | }; 417 | 418 | public static final Property SCALE_Y = new FloatProperty("scaleY") { 419 | @Override 420 | public void setValue(Sprite object, float value) { 421 | object.setScaleY(value); 422 | } 423 | 424 | @Override 425 | public Float get(Sprite object) { 426 | return object.getScaleY(); 427 | } 428 | }; 429 | 430 | public static final Property SCALE = new FloatProperty("scale") { 431 | @Override 432 | public void setValue(Sprite object, float value) { 433 | object.setScale(value); 434 | } 435 | 436 | @Override 437 | public Float get(Sprite object) { 438 | return object.getScale(); 439 | } 440 | }; 441 | 442 | public static final Property ALPHA = new IntProperty("alpha") { 443 | @Override 444 | public void setValue(Sprite object, int value) { 445 | object.setAlpha(value); 446 | } 447 | 448 | @Override 449 | public Integer get(Sprite object) { 450 | return object.getAlpha(); 451 | } 452 | }; 453 | 454 | } 455 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/sprite/SpriteContainer.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.sprite; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Canvas; 5 | import android.graphics.Rect; 6 | 7 | import com.github.ybq.android.spinkit.animation.AnimationUtils; 8 | 9 | /** 10 | * Created by ybq. 11 | */ 12 | public abstract class SpriteContainer extends Sprite { 13 | 14 | private Sprite[] sprites; 15 | 16 | private int color; 17 | 18 | public SpriteContainer() { 19 | sprites = onCreateChild(); 20 | initCallBack(); 21 | onChildCreated(sprites); 22 | } 23 | 24 | private void initCallBack() { 25 | if (sprites != null) { 26 | for (Sprite sprite : sprites) { 27 | sprite.setCallback(this); 28 | } 29 | } 30 | } 31 | 32 | public void onChildCreated(Sprite... sprites) { 33 | 34 | } 35 | 36 | public int getChildCount() { 37 | return sprites == null ? 0 : sprites.length; 38 | } 39 | 40 | public Sprite getChildAt(int index) { 41 | return sprites == null ? null : sprites[index]; 42 | } 43 | 44 | @Override 45 | public void setColor(int color) { 46 | this.color = color; 47 | for (int i = 0; i < getChildCount(); i++) { 48 | getChildAt(i).setColor(color); 49 | } 50 | } 51 | 52 | @Override 53 | public int getColor() { 54 | return color; 55 | } 56 | 57 | @Override 58 | public void draw(Canvas canvas) { 59 | super.draw(canvas); 60 | drawChild(canvas); 61 | } 62 | 63 | public void drawChild(Canvas canvas) { 64 | if (sprites != null) { 65 | for (Sprite sprite : sprites) { 66 | int count = canvas.save(); 67 | sprite.draw(canvas); 68 | canvas.restoreToCount(count); 69 | } 70 | } 71 | } 72 | 73 | @Override 74 | protected void drawSelf(Canvas canvas) { 75 | } 76 | 77 | @Override 78 | protected void onBoundsChange(Rect bounds) { 79 | super.onBoundsChange(bounds); 80 | for (Sprite sprite : sprites) { 81 | sprite.setBounds(bounds); 82 | } 83 | } 84 | 85 | @Override 86 | public void start() { 87 | super.start(); 88 | AnimationUtils.start(sprites); 89 | } 90 | 91 | @Override 92 | public void stop() { 93 | super.stop(); 94 | AnimationUtils.stop(sprites); 95 | } 96 | 97 | @Override 98 | public boolean isRunning() { 99 | return AnimationUtils.isRunning(sprites) || super.isRunning(); 100 | } 101 | 102 | public abstract Sprite[] onCreateChild(); 103 | 104 | @Override 105 | public ValueAnimator onCreateAnimation() { 106 | return null; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/ChasingDots.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Rect; 5 | import android.os.Build; 6 | import android.view.animation.LinearInterpolator; 7 | 8 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 9 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 10 | import com.github.ybq.android.spinkit.sprite.Sprite; 11 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 12 | 13 | /** 14 | * Created by ybq. 15 | */ 16 | public class ChasingDots extends SpriteContainer { 17 | 18 | @Override 19 | public Sprite[] onCreateChild() { 20 | return new Sprite[]{ 21 | new Dot(), 22 | new Dot() 23 | }; 24 | } 25 | 26 | @Override 27 | public void onChildCreated(Sprite... sprites) { 28 | super.onChildCreated(sprites); 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 30 | sprites[1].setAnimationDelay(1000); 31 | } else { 32 | sprites[1].setAnimationDelay(-1000); 33 | } 34 | } 35 | 36 | @Override 37 | public ValueAnimator onCreateAnimation() { 38 | float fractions[] = new float[]{0f, 1f}; 39 | return new SpriteAnimatorBuilder(this). 40 | rotate(fractions, 0, 360). 41 | duration(2000). 42 | interpolator(new LinearInterpolator()). 43 | build(); 44 | } 45 | 46 | @Override 47 | protected void onBoundsChange(Rect bounds) { 48 | super.onBoundsChange(bounds); 49 | bounds = clipSquare(bounds); 50 | int drawW = (int) (bounds.width() * 0.6f); 51 | getChildAt(0).setDrawBounds( 52 | bounds.right - drawW, 53 | bounds.top, 54 | bounds.right 55 | , bounds.top + drawW 56 | ); 57 | getChildAt(1).setDrawBounds( 58 | bounds.right - drawW, 59 | bounds.bottom - drawW, 60 | bounds.right, 61 | bounds.bottom 62 | ); 63 | } 64 | 65 | private class Dot extends CircleSprite { 66 | 67 | Dot() { 68 | setScale(0f); 69 | } 70 | 71 | @Override 72 | public ValueAnimator onCreateAnimation() { 73 | float fractions[] = new float[]{0f, 0.5f, 1f}; 74 | return new SpriteAnimatorBuilder(this). 75 | scale(fractions, 0f, 1f, 0f). 76 | duration(2000). 77 | easeInOut(fractions) 78 | .build(); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/Circle.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.os.Build; 5 | 6 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 7 | import com.github.ybq.android.spinkit.sprite.CircleLayoutContainer; 8 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 9 | import com.github.ybq.android.spinkit.sprite.Sprite; 10 | 11 | /** 12 | * Created by ybq. 13 | */ 14 | public class Circle extends CircleLayoutContainer { 15 | 16 | @Override 17 | public Sprite[] onCreateChild() { 18 | Dot[] dots = new Dot[12]; 19 | for (int i = 0; i < dots.length; i++) { 20 | dots[i] = new Dot(); 21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 22 | dots[i].setAnimationDelay(1200 / 12 * i); 23 | } else { 24 | dots[i].setAnimationDelay(1200 / 12 * i + -1200); 25 | } 26 | } 27 | return dots; 28 | } 29 | 30 | private class Dot extends CircleSprite { 31 | 32 | Dot() { 33 | setScale(0f); 34 | } 35 | 36 | @Override 37 | public ValueAnimator onCreateAnimation() { 38 | float fractions[] = new float[]{0f, 0.5f, 1f}; 39 | return new SpriteAnimatorBuilder(this). 40 | scale(fractions, 0f, 1f, 0f). 41 | duration(1200). 42 | easeInOut(fractions) 43 | .build(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/CubeGrid.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Rect; 5 | 6 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 7 | import com.github.ybq.android.spinkit.sprite.RectSprite; 8 | import com.github.ybq.android.spinkit.sprite.Sprite; 9 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 10 | 11 | /** 12 | * Created by ybq. 13 | */ 14 | public class CubeGrid extends SpriteContainer { 15 | 16 | @Override 17 | public Sprite[] onCreateChild() { 18 | int delays[] = new int[]{ 19 | 200, 300, 400 20 | , 100, 200, 300 21 | , 0, 100, 200 22 | }; 23 | GridItem[] gridItems = new GridItem[9]; 24 | for (int i = 0; i < gridItems.length; i++) { 25 | gridItems[i] = new GridItem(); 26 | gridItems[i].setAnimationDelay(delays[i]); 27 | } 28 | return gridItems; 29 | } 30 | 31 | @Override 32 | protected void onBoundsChange(Rect bounds) { 33 | super.onBoundsChange(bounds); 34 | bounds = clipSquare(bounds); 35 | int width = (int) (bounds.width() * 0.33f); 36 | int height = (int) (bounds.height() * 0.33f); 37 | for (int i = 0; i < getChildCount(); i++) { 38 | int x = i % 3; 39 | int y = i / 3; 40 | int l = bounds.left + x * width; 41 | int t = bounds.top + y * height; 42 | Sprite sprite = getChildAt(i); 43 | sprite.setDrawBounds(l, t, l + width, t + height); 44 | } 45 | } 46 | 47 | private class GridItem extends RectSprite { 48 | @Override 49 | public ValueAnimator onCreateAnimation() { 50 | float fractions[] = new float[]{0f, 0.35f, 0.7f, 1f}; 51 | return new SpriteAnimatorBuilder(this). 52 | scale(fractions, 1f, 0f, 1f, 1f). 53 | duration(1300). 54 | easeInOut(fractions) 55 | .build(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/DoubleBounce.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.os.Build; 5 | 6 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 7 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 8 | import com.github.ybq.android.spinkit.sprite.Sprite; 9 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 10 | 11 | /** 12 | * Created by ybq. 13 | */ 14 | public class DoubleBounce extends SpriteContainer { 15 | 16 | @Override 17 | public Sprite[] onCreateChild() { 18 | return new Sprite[]{ 19 | new Bounce(), new Bounce() 20 | }; 21 | } 22 | 23 | @Override 24 | public void onChildCreated(Sprite... sprites) { 25 | super.onChildCreated(sprites); 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 27 | sprites[1].setAnimationDelay(1000); 28 | } else { 29 | sprites[1].setAnimationDelay(-1000); 30 | } 31 | } 32 | 33 | private class Bounce extends CircleSprite { 34 | 35 | Bounce() { 36 | setAlpha(153); 37 | setScale(0f); 38 | } 39 | 40 | @Override 41 | public ValueAnimator onCreateAnimation() { 42 | float fractions[] = new float[]{0f, 0.5f, 1f}; 43 | return new SpriteAnimatorBuilder(this).scale(fractions, 0f, 1f, 0f). 44 | duration(2000). 45 | easeInOut(fractions) 46 | .build(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/FadingCircle.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.os.Build; 5 | 6 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 7 | import com.github.ybq.android.spinkit.sprite.CircleLayoutContainer; 8 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 9 | import com.github.ybq.android.spinkit.sprite.Sprite; 10 | 11 | /** 12 | * Created by ybq. 13 | */ 14 | public class FadingCircle extends CircleLayoutContainer { 15 | 16 | @Override 17 | public Sprite[] onCreateChild() { 18 | Dot[] dots = new Dot[12]; 19 | for (int i = 0; i < dots.length; i++) { 20 | dots[i] = new Dot(); 21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 22 | dots[i].setAnimationDelay(1200 / 12 * i); 23 | } else { 24 | dots[i].setAnimationDelay(1200 / 12 * i + -1200); 25 | } 26 | } 27 | return dots; 28 | } 29 | 30 | private class Dot extends CircleSprite { 31 | 32 | Dot() { 33 | setAlpha(0); 34 | } 35 | 36 | @Override 37 | public ValueAnimator onCreateAnimation() { 38 | float fractions[] = new float[]{0f, 0.39f, 0.4f, 1f}; 39 | return new SpriteAnimatorBuilder(this). 40 | alpha(fractions, 0, 0, 255, 0). 41 | duration(1200). 42 | easeInOut(fractions).build(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/FoldingCube.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Canvas; 5 | import android.graphics.Rect; 6 | import android.os.Build; 7 | import android.view.animation.LinearInterpolator; 8 | 9 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 10 | import com.github.ybq.android.spinkit.sprite.RectSprite; 11 | import com.github.ybq.android.spinkit.sprite.Sprite; 12 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 13 | 14 | /** 15 | * Created by ybq. 16 | */ 17 | public class FoldingCube extends SpriteContainer { 18 | 19 | @SuppressWarnings("FieldCanBeLocal") 20 | private boolean wrapContent = false; 21 | 22 | @Override 23 | public Sprite[] onCreateChild() { 24 | Cube[] cubes 25 | = new Cube[4]; 26 | for (int i = 0; i < cubes.length; i++) { 27 | cubes[i] = new Cube(); 28 | 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 30 | cubes[i].setAnimationDelay(300 * i); 31 | } else { 32 | cubes[i].setAnimationDelay(300 * i - 1200); 33 | } 34 | } 35 | return cubes; 36 | } 37 | 38 | @Override 39 | protected void onBoundsChange(Rect bounds) { 40 | super.onBoundsChange(bounds); 41 | bounds = clipSquare(bounds); 42 | int size = Math.min(bounds.width(), bounds.height()); 43 | if (wrapContent) { 44 | size = (int) Math.sqrt( 45 | (size 46 | * size) / 2); 47 | int oW = (bounds.width() - size) / 2; 48 | int oH = (bounds.height() - size) / 2; 49 | bounds = new Rect( 50 | bounds.left + oW, 51 | bounds.top + oH, 52 | bounds.right - oW, 53 | bounds.bottom - oH 54 | ); 55 | } 56 | 57 | int px = bounds.left + size / 2 + 1; 58 | int py = bounds.top + size / 2 + 1; 59 | for (int i = 0; i < getChildCount(); i++) { 60 | Sprite sprite = getChildAt(i); 61 | sprite.setDrawBounds( 62 | bounds.left, 63 | bounds.top, 64 | px, 65 | py 66 | ); 67 | sprite.setPivotX(sprite.getDrawBounds().right); 68 | sprite.setPivotY(sprite.getDrawBounds().bottom); 69 | } 70 | } 71 | 72 | @Override 73 | public void drawChild(Canvas canvas) { 74 | 75 | Rect bounds = clipSquare(getBounds()); 76 | for (int i = 0; i < getChildCount(); i++) { 77 | int count = canvas.save(); 78 | canvas.rotate(45 + i * 90, bounds.centerX(), bounds.centerY()); 79 | Sprite sprite = getChildAt(i); 80 | sprite.draw(canvas); 81 | canvas.restoreToCount(count); 82 | } 83 | } 84 | 85 | private class Cube extends RectSprite { 86 | 87 | Cube() { 88 | setAlpha(0); 89 | setRotateX(-180); 90 | } 91 | 92 | @Override 93 | public ValueAnimator onCreateAnimation() { 94 | float fractions[] = new float[]{0f, 0.1f, 0.25f, 0.75f, 0.9f, 1f}; 95 | return new SpriteAnimatorBuilder(this). 96 | alpha(fractions, 0, 0, 255, 255, 0, 0). 97 | rotateX(fractions, -180, -180, 0, 0, 0, 0). 98 | rotateY(fractions, 0, 0, 0, 0, 180, 180). 99 | duration(2400). 100 | interpolator(new LinearInterpolator()) 101 | .build(); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/MultiplePulse.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import com.github.ybq.android.spinkit.sprite.Sprite; 4 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 5 | 6 | /** 7 | * Created by ybq. 8 | */ 9 | public class MultiplePulse extends SpriteContainer { 10 | @Override 11 | public Sprite[] onCreateChild() { 12 | return new Sprite[]{ 13 | new Pulse(), 14 | new Pulse(), 15 | new Pulse(), 16 | }; 17 | } 18 | 19 | @Override 20 | public void onChildCreated(Sprite... sprites) { 21 | for (int i = 0; i < sprites.length; i++) { 22 | sprites[i].setAnimationDelay(200 * (i + 1)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/MultiplePulseRing.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import com.github.ybq.android.spinkit.sprite.Sprite; 4 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 5 | 6 | /** 7 | * Created by ybq. 8 | */ 9 | public class MultiplePulseRing extends SpriteContainer { 10 | 11 | @Override 12 | public Sprite[] onCreateChild() { 13 | return new Sprite[]{ 14 | new PulseRing(), 15 | new PulseRing(), 16 | new PulseRing(), 17 | }; 18 | } 19 | 20 | @Override 21 | public void onChildCreated(Sprite... sprites) { 22 | for (int i = 0; i < sprites.length; i++) { 23 | sprites[i].setAnimationDelay(200 * (i + 1)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/Pulse.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | 5 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 6 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 7 | 8 | /** 9 | * Created by ybq. 10 | */ 11 | public class Pulse extends CircleSprite { 12 | 13 | public Pulse() { 14 | setScale(0f); 15 | } 16 | 17 | @Override 18 | public ValueAnimator onCreateAnimation() { 19 | float fractions[] = new float[]{0f, 1f}; 20 | return new SpriteAnimatorBuilder(this). 21 | scale(fractions, 0f, 1f). 22 | alpha(fractions, 255, 0). 23 | duration(1000). 24 | easeInOut(fractions) 25 | .build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/PulseRing.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | 5 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 6 | import com.github.ybq.android.spinkit.animation.interpolator.KeyFrameInterpolator; 7 | import com.github.ybq.android.spinkit.sprite.RingSprite; 8 | 9 | /** 10 | * Created by ybq. 11 | */ 12 | public class PulseRing extends RingSprite { 13 | 14 | public PulseRing() { 15 | setScale(0f); 16 | } 17 | 18 | @Override 19 | public ValueAnimator onCreateAnimation() { 20 | float fractions[] = new float[]{0f, 0.7f, 1f}; 21 | return new SpriteAnimatorBuilder(this). 22 | scale(fractions, 0f, 1f, 1f). 23 | alpha(fractions, 255, (int) (255 * 0.7), 0). 24 | duration(1000). 25 | interpolator(KeyFrameInterpolator.pathInterpolator(0.21f, 0.53f, 0.56f, 0.8f, fractions)). 26 | build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/RotatingCircle.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | 5 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 6 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 7 | 8 | public class RotatingCircle extends CircleSprite { 9 | 10 | @Override 11 | public ValueAnimator onCreateAnimation() { 12 | float fractions[] = new float[]{0f, 0.5f, 1f}; 13 | return new SpriteAnimatorBuilder(this). 14 | rotateX(fractions, 0, -180, -180). 15 | rotateY(fractions, 0, 0, -180). 16 | duration(1200). 17 | easeInOut(fractions) 18 | .build(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/RotatingPlane.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Rect; 5 | 6 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 7 | import com.github.ybq.android.spinkit.sprite.RectSprite; 8 | 9 | /** 10 | * Created by ybq. 11 | */ 12 | public class RotatingPlane extends RectSprite { 13 | @Override 14 | protected void onBoundsChange(Rect bounds) { 15 | setDrawBounds(clipSquare(bounds)); 16 | } 17 | 18 | @Override 19 | public ValueAnimator onCreateAnimation() { 20 | float fractions[] = new float[]{0f, 0.5f, 1f}; 21 | return new SpriteAnimatorBuilder(this). 22 | rotateX(fractions, 0, -180, -180). 23 | rotateY(fractions, 0, 0, -180). 24 | duration(1200). 25 | easeInOut(fractions) 26 | .build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/ThreeBounce.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Rect; 5 | 6 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 7 | import com.github.ybq.android.spinkit.sprite.CircleSprite; 8 | import com.github.ybq.android.spinkit.sprite.Sprite; 9 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 10 | 11 | /** 12 | * Created by ybq. 13 | */ 14 | public class ThreeBounce extends SpriteContainer { 15 | 16 | @Override 17 | public Sprite[] onCreateChild() { 18 | return new Sprite[]{ 19 | new Bounce(), 20 | new Bounce(), 21 | new Bounce() 22 | }; 23 | } 24 | 25 | @Override 26 | public void onChildCreated(Sprite... sprites) { 27 | super.onChildCreated(sprites); 28 | sprites[1].setAnimationDelay(160); 29 | sprites[2].setAnimationDelay(320); 30 | } 31 | 32 | @Override 33 | protected void onBoundsChange(Rect bounds) { 34 | super.onBoundsChange(bounds); 35 | bounds = clipSquare(bounds); 36 | int radius = bounds.width() / 8; 37 | int top = bounds.centerY() - radius; 38 | int bottom = bounds.centerY() + radius; 39 | 40 | for (int i = 0; i < getChildCount(); i++) { 41 | int left = bounds.width() * i / 3 42 | + bounds.left; 43 | getChildAt(i).setDrawBounds( 44 | left, top, left + radius * 2, bottom 45 | ); 46 | } 47 | } 48 | 49 | private class Bounce extends CircleSprite { 50 | 51 | Bounce() { 52 | setScale(0f); 53 | } 54 | 55 | @Override 56 | public ValueAnimator onCreateAnimation() { 57 | float fractions[] = new float[]{0f, 0.4f, 0.8f, 1f}; 58 | return new SpriteAnimatorBuilder(this).scale(fractions, 0f, 1f, 0f, 0f). 59 | duration(1400). 60 | easeInOut(fractions) 61 | .build(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/WanderingCubes.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Rect; 5 | import android.os.Build; 6 | 7 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 8 | import com.github.ybq.android.spinkit.sprite.RectSprite; 9 | import com.github.ybq.android.spinkit.sprite.Sprite; 10 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 11 | 12 | /** 13 | * Created by ybq. 14 | */ 15 | public class WanderingCubes extends SpriteContainer { 16 | 17 | @Override 18 | public Sprite[] onCreateChild() { 19 | return new Sprite[]{ 20 | new Cube(0), 21 | new Cube(3) 22 | }; 23 | } 24 | 25 | @Override 26 | public void onChildCreated(Sprite... sprites) { 27 | super.onChildCreated(sprites); 28 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { 29 | sprites[1].setAnimationDelay(-900); 30 | } 31 | } 32 | 33 | @Override 34 | protected void onBoundsChange(Rect bounds) { 35 | bounds = clipSquare(bounds); 36 | super.onBoundsChange(bounds); 37 | for (int i = 0; i < getChildCount(); i++) { 38 | Sprite sprite = getChildAt(i); 39 | sprite.setDrawBounds( 40 | bounds.left, 41 | bounds.top, 42 | bounds.left + bounds.width() / 4, 43 | bounds.top + bounds.height() / 4 44 | ); 45 | } 46 | } 47 | 48 | private class Cube extends RectSprite { 49 | int startFrame; 50 | 51 | public Cube(int startFrame) { 52 | this.startFrame = startFrame; 53 | } 54 | 55 | @Override 56 | public ValueAnimator onCreateAnimation() { 57 | float fractions[] = new float[]{0f, 0.25f, 0.5f, 0.51f, 0.75f, 1f}; 58 | SpriteAnimatorBuilder builder = new SpriteAnimatorBuilder(this). 59 | rotate(fractions, 0, -90, -179, -180, -270, -360). 60 | translateXPercentage(fractions, 0f, 0.75f, 0.75f, 0.75f, 0f, 0f). 61 | translateYPercentage(fractions, 0f, 0f, 0.75f, 0.75f, 0.75f, 0f). 62 | scale(fractions, 1f, 0.5f, 1f, 1f, 0.5f, 1f). 63 | duration(1800). 64 | easeInOut(fractions); 65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 66 | builder. 67 | startFrame(startFrame); 68 | } 69 | return builder.build(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /library/src/main/java/com/github/ybq/android/spinkit/style/Wave.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.spinkit.style; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.graphics.Rect; 5 | import android.os.Build; 6 | 7 | import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; 8 | import com.github.ybq.android.spinkit.sprite.RectSprite; 9 | import com.github.ybq.android.spinkit.sprite.Sprite; 10 | import com.github.ybq.android.spinkit.sprite.SpriteContainer; 11 | 12 | /** 13 | * Created by ybq. 14 | */ 15 | public class Wave extends SpriteContainer { 16 | 17 | @Override 18 | public Sprite[] onCreateChild() { 19 | WaveItem[] waveItems = new WaveItem[5]; 20 | for (int i = 0; i < waveItems.length; i++) { 21 | waveItems[i] = new WaveItem(); 22 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 23 | waveItems[i].setAnimationDelay(600 + i * 100); 24 | } else { 25 | waveItems[i].setAnimationDelay(-1200 + i * 100); 26 | } 27 | 28 | } 29 | return waveItems; 30 | } 31 | 32 | @Override 33 | protected void onBoundsChange(Rect bounds) { 34 | super.onBoundsChange(bounds); 35 | bounds = clipSquare(bounds); 36 | int rw = bounds.width() / getChildCount(); 37 | int width = bounds.width() / 5 * 3 / 5; 38 | for (int i = 0; i < getChildCount(); i++) { 39 | Sprite sprite = getChildAt(i); 40 | int l = bounds.left + i * rw + rw / 5; 41 | int r = l + width; 42 | sprite.setDrawBounds(l, bounds.top, r, bounds.bottom); 43 | } 44 | } 45 | 46 | private class WaveItem extends RectSprite { 47 | 48 | WaveItem() { 49 | setScaleY(0.4f); 50 | } 51 | 52 | @Override 53 | public ValueAnimator onCreateAnimation() { 54 | float fractions[] = new float[]{0f, 0.2f, 0.4f, 1f}; 55 | return new SpriteAnimatorBuilder(this).scaleY(fractions, 0.4f, 1f, 0.4f, 0.4f). 56 | duration(1200). 57 | easeInOut(fractions) 58 | .build(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /library/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 39 | 40 | 43 | 44 | 47 | 48 | 51 | 52 | 55 | 56 | 59 | 60 | 63 | 64 | 67 | 68 | 71 | 72 | 78 | 79 | 82 | 83 | 86 | 87 | 90 | 91 | 94 | 95 | 98 | 99 | 102 | 103 | 106 | 107 | 110 | 111 | 114 | 115 | 118 | 119 | 122 | 123 | 126 | 127 | 130 | 131 | 134 | 135 | 138 | 139 | 145 | 146 | 149 | 150 | 153 | 154 | 157 | 158 | 161 | 162 | 165 | 166 | 169 | 170 | 173 | 174 | 177 | 178 | 181 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | 5 | compileSdkVersion 28 6 | buildToolsVersion '28.0.3' 7 | 8 | defaultConfig { 9 | applicationId "com.github.ybq.android.spinkit" 10 | minSdkVersion 14 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(include: ['*.jar'], dir: 'libs') 26 | implementation 'androidx.appcompat:appcompat:1.0.0' 27 | implementation 'com.google.android.material:material:1.0.0' 28 | implementation project(':library') 29 | } 30 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/ybq/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/ArgbEvaluator.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2010 The Android Open Source Project 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.github.ybq.android.loading; 19 | 20 | import android.animation.TypeEvaluator; 21 | 22 | /** 23 | * This evaluator can be used to perform type interpolation between integer 24 | * values that represent ARGB colors. 25 | */ 26 | public class ArgbEvaluator implements TypeEvaluator { 27 | private static final ArgbEvaluator sInstance = new ArgbEvaluator(); 28 | 29 | /** 30 | * Returns an instance of ArgbEvaluator that may be used in 31 | * {@link android.animation.ValueAnimator#setEvaluator(TypeEvaluator)}. The same instance may 32 | * be used in multiple Animators because it holds no state. 33 | * 34 | * @return An instance of ArgbEvalutor. 35 | */ 36 | public static ArgbEvaluator getInstance() { 37 | return sInstance; 38 | } 39 | 40 | /** 41 | * This function returns the calculated in-between value for a color 42 | * given integers that represent the start and end values in the four 43 | * bytes of the 32-bit int. Each channel is separately linearly interpolated 44 | * and the resulting calculated values are recombined into the return value. 45 | * 46 | * @param fraction The fraction from the starting to the ending values 47 | * @param startValue A 32-bit int value representing colors in the 48 | * separate bytes of the parameter 49 | * @param endValue A 32-bit int value representing colors in the 50 | * separate bytes of the parameter 51 | * @return A value that is calculated to be the linearly interpolated 52 | * result, derived by separating the start and end values into separate 53 | * color channels and interpolating each one separately, recombining the 54 | * resulting values in the same way. 55 | */ 56 | public Object evaluate(float fraction, Object startValue, Object endValue) { 57 | int startInt = (Integer) startValue; 58 | int startA = (startInt >> 24) & 0xff; 59 | int startR = (startInt >> 16) & 0xff; 60 | int startG = (startInt >> 8) & 0xff; 61 | int startB = startInt & 0xff; 62 | int endInt = (Integer) endValue; 63 | int endA = (endInt >> 24) & 0xff; 64 | int endR = (endInt >> 16) & 0xff; 65 | int endG = (endInt >> 8) & 0xff; 66 | int endB = endInt & 0xff; 67 | return (startA + (int) (fraction * (endA - startA))) << 24 | 68 | (startR + (int) (fraction * (endR - startR))) << 16 | 69 | (startG + (int) (fraction * (endG - startG))) << 8 | 70 | (startB + (int) (fraction * (endB - startB))); 71 | } 72 | } -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/Colors.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.loading; 2 | 3 | /** 4 | * Created by ybq. 5 | */ 6 | public interface Colors { 7 | int[] colors = new int[]{ 8 | 0XFFD55400, 9 | 0XFF2B3E51, 10 | 0XFF00BD9C, 11 | 0XFF227FBB, 12 | 0XFF7F8C8D, 13 | 0XFFFFCC5C, 14 | 0XFFD55400, 15 | 0XFF1AAF5D, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.loading; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.github.ybq.android.spinkit.SpinKitView; 13 | import com.github.ybq.android.spinkit.SpriteFactory; 14 | import com.github.ybq.android.spinkit.Style; 15 | import com.github.ybq.android.spinkit.sprite.Sprite; 16 | 17 | import androidx.appcompat.app.AppCompatActivity; 18 | import androidx.viewpager.widget.PagerAdapter; 19 | import androidx.viewpager.widget.ViewPager; 20 | 21 | public class DetailActivity extends AppCompatActivity implements Colors { 22 | 23 | public static void start(Context context, int position) { 24 | Intent intent = new Intent(context, DetailActivity.class); 25 | intent.putExtra("position", position); 26 | context.startActivity(intent); 27 | } 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_detail); 33 | ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager); 34 | viewPager.setOffscreenPageLimit(0); 35 | viewPager.setAdapter(new PagerAdapter() { 36 | @Override 37 | public int getCount() { 38 | return Style.values().length; 39 | } 40 | 41 | @Override 42 | public boolean isViewFromObject(View view, Object object) { 43 | return view == object; 44 | } 45 | 46 | @Override 47 | public Object instantiateItem(ViewGroup container, int position) { 48 | @SuppressLint("InflateParams") View view = LayoutInflater.from(container.getContext()).inflate(R.layout.item_pager, null); 49 | 50 | SpinKitView spinKitView = (SpinKitView) view.findViewById(R.id.spin_kit); 51 | TextView name = (TextView) view.findViewById(R.id.name); 52 | Style style = Style.values()[position]; 53 | name.setText(style.name().toLowerCase()); 54 | Sprite drawable = SpriteFactory.create(style); 55 | spinKitView.setIndeterminateDrawable(drawable); 56 | container.addView(view); 57 | 58 | return view; 59 | } 60 | 61 | @Override 62 | public void destroyItem(ViewGroup container, int position, Object object) { 63 | container.removeView((View) object); 64 | } 65 | }); 66 | 67 | viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 68 | @Override 69 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 70 | int color = (int) ArgbEvaluator.getInstance().evaluate(positionOffset, 71 | colors[position % colors.length], 72 | colors[(position + 1) % colors.length]); 73 | getWindow().getDecorView().setBackgroundColor(color); 74 | } 75 | 76 | @Override 77 | public void onPageSelected(int position) { 78 | getWindow().getDecorView().setBackgroundColor(colors[position % colors.length]); 79 | } 80 | 81 | @Override 82 | public void onPageScrollStateChanged(int state) { 83 | 84 | } 85 | }); 86 | 87 | viewPager.setCurrentItem(getIntent().getIntExtra("position", 0)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.loading; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.google.android.material.tabs.TabLayout; 6 | 7 | import androidx.appcompat.app.AppCompatActivity; 8 | import androidx.fragment.app.Fragment; 9 | import androidx.fragment.app.FragmentPagerAdapter; 10 | import androidx.viewpager.widget.ViewPager; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | 14 | TabLayout mTabLayout; 15 | ViewPager mViewPager; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | mTabLayout = (TabLayout) findViewById(R.id.tabs); 22 | mViewPager = (ViewPager) findViewById(R.id.viewpager); 23 | 24 | mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { 25 | 26 | String[] titles = new String[]{ 27 | "Style", "Widget" 28 | }; 29 | 30 | @Override 31 | public Fragment getItem(int position) { 32 | if (position == 0) { 33 | return StyleFragment.newInstance(); 34 | } else { 35 | return WidgetFragment.newInstance(); 36 | } 37 | } 38 | 39 | @Override 40 | public int getCount() { 41 | return 2; 42 | } 43 | 44 | @Override 45 | public CharSequence getPageTitle(int position) { 46 | return titles[position]; 47 | } 48 | }); 49 | mTabLayout.setupWithViewPager(mViewPager); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/SquareFrameLayout.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.loading; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.util.AttributeSet; 7 | import android.widget.FrameLayout; 8 | 9 | /** 10 | * Created by ybq. 11 | */ 12 | public class SquareFrameLayout extends FrameLayout { 13 | public SquareFrameLayout(Context context) { 14 | super(context); 15 | } 16 | 17 | public SquareFrameLayout(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | } 24 | 25 | @SuppressWarnings("unused") 26 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 27 | public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 28 | super(context, attrs, defStyleAttr, defStyleRes); 29 | } 30 | 31 | @Override 32 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 33 | //noinspection SuspiciousNameCombination 34 | super.onMeasure(widthMeasureSpec, widthMeasureSpec); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/StyleFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.loading; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.github.ybq.android.spinkit.SpinKitView; 10 | import com.github.ybq.android.spinkit.SpriteFactory; 11 | import com.github.ybq.android.spinkit.Style; 12 | import com.github.ybq.android.spinkit.sprite.Sprite; 13 | 14 | import androidx.annotation.Nullable; 15 | import androidx.fragment.app.Fragment; 16 | import androidx.recyclerview.widget.GridLayoutManager; 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | /** 20 | * Created by ybq. 21 | */ 22 | public class StyleFragment extends Fragment implements Colors { 23 | 24 | public static StyleFragment newInstance() { 25 | return new StyleFragment(); 26 | } 27 | 28 | 29 | @SuppressLint("InflateParams") 30 | @Nullable 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 33 | return inflater.inflate(R.layout.fragment_style, null); 34 | } 35 | 36 | @Override 37 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 38 | super.onViewCreated(view, savedInstanceState); 39 | RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list); 40 | GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 4); 41 | layoutManager.setOrientation(RecyclerView.VERTICAL); 42 | recyclerView.setLayoutManager(layoutManager); 43 | 44 | recyclerView.setAdapter(new RecyclerView.Adapter() { 45 | @Override 46 | public Holder onCreateViewHolder(ViewGroup parent, int viewType) { 47 | @SuppressLint("InflateParams") View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_style, null); 48 | return new Holder(view); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(Holder holder, int position) { 53 | holder.bind(position); 54 | } 55 | 56 | @Override 57 | public int getItemCount() { 58 | return Style.values().length; 59 | } 60 | }); 61 | } 62 | 63 | class Holder extends RecyclerView.ViewHolder { 64 | 65 | SpinKitView spinKitView; 66 | 67 | public Holder(View itemView) { 68 | super(itemView); 69 | spinKitView = (SpinKitView) itemView.findViewById(R.id.spin_kit); 70 | } 71 | 72 | public void bind(int position) { 73 | itemView.setBackgroundColor(colors[position % colors.length]); 74 | final int finalPosition = position; 75 | itemView.setOnClickListener(new View.OnClickListener() { 76 | @Override 77 | public void onClick(View v) { 78 | DetailActivity.start(v.getContext(), finalPosition); 79 | } 80 | }); 81 | position = position % 15; 82 | Style style = Style.values()[position]; 83 | Sprite drawable = SpriteFactory.create(style); 84 | spinKitView.setIndeterminateDrawable(drawable); 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/ybq/android/loading/WidgetFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.ybq.android.loading; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Button; 9 | import android.widget.ImageView; 10 | import android.widget.ProgressBar; 11 | import android.widget.TextView; 12 | 13 | import com.github.ybq.android.spinkit.style.ChasingDots; 14 | import com.github.ybq.android.spinkit.style.Circle; 15 | import com.github.ybq.android.spinkit.style.DoubleBounce; 16 | import com.github.ybq.android.spinkit.style.Wave; 17 | 18 | import androidx.annotation.Nullable; 19 | import androidx.fragment.app.Fragment; 20 | 21 | /** 22 | * Created by ybq. 23 | */ 24 | public class WidgetFragment extends Fragment implements Colors { 25 | 26 | private Wave mWaveDrawable; 27 | private Circle mCircleDrawable; 28 | private ChasingDots mChasingDotsDrawable; 29 | 30 | public static WidgetFragment newInstance() { 31 | return new WidgetFragment(); 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 37 | return inflater.inflate(R.layout.fragment_widget, null); 38 | } 39 | 40 | @Override 41 | public void onViewCreated(View view, Bundle savedInstanceState) { 42 | super.onViewCreated(view, savedInstanceState); 43 | 44 | //ProgressBar 45 | ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progress); 46 | DoubleBounce doubleBounce = new DoubleBounce(); 47 | doubleBounce.setBounds(0, 0, 100, 100); 48 | doubleBounce.setColor(colors[7]); 49 | progressBar.setIndeterminateDrawable(doubleBounce); 50 | 51 | //Button 52 | Button button = (Button) view.findViewById(R.id.button); 53 | mWaveDrawable = new Wave(); 54 | mWaveDrawable.setBounds(0, 0, 100, 100); 55 | //noinspection deprecation 56 | mWaveDrawable.setColor(getResources().getColor(R.color.colorAccent)); 57 | button.setCompoundDrawables(mWaveDrawable, null, null, null); 58 | 59 | //TextView 60 | TextView textView = (TextView) view.findViewById(R.id.text); 61 | mCircleDrawable = new Circle(); 62 | mCircleDrawable.setBounds(0, 0, 100, 100); 63 | mCircleDrawable.setColor(Color.WHITE); 64 | textView.setCompoundDrawables(null, null, mCircleDrawable, null); 65 | textView.setBackgroundColor(colors[2]); 66 | 67 | //ImageView 68 | ImageView imageView = (ImageView) view.findViewById(R.id.image); 69 | mChasingDotsDrawable = new ChasingDots(); 70 | mChasingDotsDrawable.setColor(Color.WHITE); 71 | imageView.setImageDrawable(mChasingDotsDrawable); 72 | imageView.setBackgroundColor(colors[0]); 73 | } 74 | 75 | @Override 76 | public void onResume() { 77 | super.onResume(); 78 | mWaveDrawable.start(); 79 | mCircleDrawable.start(); 80 | mChasingDotsDrawable.start(); 81 | } 82 | 83 | @Override 84 | public void onStop() { 85 | super.onStop(); 86 | mWaveDrawable.stop(); 87 | mCircleDrawable.stop(); 88 | mChasingDotsDrawable.stop(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/fragment_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/fragment_widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 17 | 18 | 23 | 24 | 29 | 30 | 36 | 37 | 38 | 39 | 45 | 46 | 51 | 52 |