Repository: ybq/Android-SpinKit Branch: master Commit: aa83e4d0a42c Files: 75 Total size: 120.1 KB Directory structure: gitextract_xp6aiyyo/ ├── .gitignore ├── LICENSE ├── README.md ├── README_zh-CN.md ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.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 │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── values-v21/ │ └── styles.xml └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Built application files *.apk *.ap_ # Files for the Dalvik VM *.dex # Java class files *.class # Generated files bin/ gen/ out/ # Gradle files .gradle/ build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ # Log Files *.log # Android Studio Navigation editor temp files .navigation/ # Android Studio captures folder captures/ # Intellij *.iml .idea # Keystore files *.jks ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright © 2016 ybq 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of 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.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. ================================================ FILE: README.md ================================================ # Android-SpinKit >Android loading animations(I wrote a android edition according [SpinKit](https://tobiasahlin.com/spinkit)) [Demo Apk](https://raw.githubusercontent.com/ybq/AndroidSpinKit/master/art/spinkit.apk) ## Preview ## Gradle Dependency ``` gradle dependencies { implementation 'com.github.ybq:Android-SpinKit:1.4.0' } ``` ## Usage - Xml ```xml ``` - ProgressBar ```java ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress); Sprite doubleBounce = new DoubleBounce(); progressBar.setIndeterminateDrawable(doubleBounce); ``` ## Style > ```xml @style/SpinKitView @style/SpinKitView.Circle @style/SpinKitView.Large @style/SpinKitView.Small @style/SpinKitView.Small.DoubleBounce ``` Style | Preview ------------ | ------------- RotatingPlane | RotatingPlane DoubleBounce | DoubleBounce Wave | Wave WanderingCubes | WanderingCubes Pulse | Pulse ChasingDots | ChasingDots ThreeBounce | ThreeBounce Circle | Circle CubeGrid | CubeGrid FadingCircle | FadingCircle FoldingCube | FoldingCube RotatingCircle | RotatingCircle ## Acknowledgements - [SpinKit](https://github.com/tobiasahlin/SpinKit). ================================================ FILE: README_zh-CN.md ================================================ # Android-SpinKit > Android 加载动画([SpinKit](https://tobiasahlin.com/spinkit)的Android版本实现) [Demo Apk](https://raw.githubusercontent.com/ybq/AndroidSpinKit/master/art/spinkit.apk) ## 效果 ## Gradle 依赖 ``` gradle dependencies { implementation 'com.github.ybq:Android-SpinKit:1.4.0' } ``` ## 使用 - Xml ```xml ``` - ProgressBar ```java ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress); DoubleBounce doubleBounce = new DoubleBounce(); progressBar.setIndeterminateDrawable(doubleBounce); ``` ###样式: 样式 | 预览 ------------ | ------------- RotatingPlane | RotatingPlane DoubleBounce | DoubleBounce Wave | Wave WanderingCubes | WanderingCubes Pulse | Pulse ChasingDots | ChasingDots ThreeBounce | ThreeBounce Circle | Circle CubeGrid | CubeGrid FadingCircle | FadingCircle FoldingCube | FoldingCube RotatingCircle | RotatingCircle ##感谢 - [SpinKit](https://github.com/tobiasahlin/SpinKit). ================================================ FILE: build.gradle ================================================ buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.novoda:bintray-release:0.8.1' } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Tue Nov 14 15:17:22 WET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip ================================================ FILE: gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true android.enableJetifier=true android.useAndroidX=true ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: library/.gitignore ================================================ /build ================================================ FILE: library/build.gradle ================================================ apply plugin: 'com.android.library' apply plugin: 'com.novoda.bintray-release' android { compileSdkVersion 28 buildToolsVersion '28.0.3' defaultConfig { minSdkVersion 14 targetSdkVersion 28 } lintOptions { abortOnError false } } publish { userOrg = 'ybq' groupId = 'com.github.ybq' artifactId = 'Android-SpinKit' publishVersion = '1.4.0' desc = 'Android loading animations' website = 'https://github.com/ybq/Android-SpinKit' licences = ['MIT'] } ================================================ FILE: library/gradle.properties ================================================ ================================================ FILE: library/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/ybq/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: library/src/main/AndroidManifest.xml ================================================ ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/SpinKitView.java ================================================ package com.github.ybq.android.spinkit; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.widget.ProgressBar; import com.github.ybq.android.spinkit.sprite.Sprite; /** * Created by ybq. */ public class SpinKitView extends ProgressBar { private Style mStyle; private int mColor; private Sprite mSprite; public SpinKitView(Context context) { this(context, null); } public SpinKitView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.SpinKitViewStyle); } public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, R.style.SpinKitView); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpinKitView, defStyleAttr, defStyleRes); mStyle = Style.values()[a.getInt(R.styleable.SpinKitView_SpinKit_Style, 0)]; mColor = a.getColor(R.styleable.SpinKitView_SpinKit_Color, Color.WHITE); a.recycle(); init(); setIndeterminate(true); } private void init() { Sprite sprite = SpriteFactory.create(mStyle); sprite.setColor(mColor); setIndeterminateDrawable(sprite); } @Override public void setIndeterminateDrawable(Drawable d) { if (!(d instanceof Sprite)) { throw new IllegalArgumentException("this d must be instanceof Sprite"); } setIndeterminateDrawable((Sprite) d); } public void setIndeterminateDrawable(Sprite d) { super.setIndeterminateDrawable(d); mSprite = d; if (mSprite.getColor() == 0) { mSprite.setColor(mColor); } onSizeChanged(getWidth(), getHeight(), getWidth(), getHeight()); if (getVisibility() == VISIBLE) { mSprite.start(); } } @Override public Sprite getIndeterminateDrawable() { return mSprite; } public void setColor(int color) { this.mColor = color; if (mSprite != null) { mSprite.setColor(color); } invalidate(); } @Override public void unscheduleDrawable(Drawable who) { super.unscheduleDrawable(who); if (who instanceof Sprite) { ((Sprite) who).stop(); } } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); if (hasWindowFocus) { if (mSprite != null && getVisibility() == VISIBLE) { mSprite.start(); } } } @Override public void onScreenStateChanged(int screenState) { super.onScreenStateChanged(screenState); if (screenState == View.SCREEN_STATE_OFF) { if (mSprite != null) { mSprite.stop(); } } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/SpriteFactory.java ================================================ package com.github.ybq.android.spinkit; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.style.ChasingDots; import com.github.ybq.android.spinkit.style.Circle; import com.github.ybq.android.spinkit.style.CubeGrid; import com.github.ybq.android.spinkit.style.DoubleBounce; import com.github.ybq.android.spinkit.style.FadingCircle; import com.github.ybq.android.spinkit.style.FoldingCube; import com.github.ybq.android.spinkit.style.MultiplePulse; import com.github.ybq.android.spinkit.style.MultiplePulseRing; import com.github.ybq.android.spinkit.style.Pulse; import com.github.ybq.android.spinkit.style.PulseRing; import com.github.ybq.android.spinkit.style.RotatingCircle; import com.github.ybq.android.spinkit.style.RotatingPlane; import com.github.ybq.android.spinkit.style.ThreeBounce; import com.github.ybq.android.spinkit.style.WanderingCubes; import com.github.ybq.android.spinkit.style.Wave; /** * Created by ybq. */ public class SpriteFactory { public static Sprite create(Style style) { Sprite sprite = null; switch (style) { case ROTATING_PLANE: sprite = new RotatingPlane(); break; case DOUBLE_BOUNCE: sprite = new DoubleBounce(); break; case WAVE: sprite = new Wave(); break; case WANDERING_CUBES: sprite = new WanderingCubes(); break; case PULSE: sprite = new Pulse(); break; case CHASING_DOTS: sprite = new ChasingDots(); break; case THREE_BOUNCE: sprite = new ThreeBounce(); break; case CIRCLE: sprite = new Circle(); break; case CUBE_GRID: sprite = new CubeGrid(); break; case FADING_CIRCLE: sprite = new FadingCircle(); break; case FOLDING_CUBE: sprite = new FoldingCube(); break; case ROTATING_CIRCLE: sprite = new RotatingCircle(); break; case MULTIPLE_PULSE: sprite = new MultiplePulse(); break; case PULSE_RING: sprite = new PulseRing(); break; case MULTIPLE_PULSE_RING: sprite = new MultiplePulseRing(); break; default: break; } return sprite; } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/Style.java ================================================ package com.github.ybq.android.spinkit; /** * Created by ybq. */ public enum Style { ROTATING_PLANE(0), DOUBLE_BOUNCE(1), WAVE(2), WANDERING_CUBES(3), PULSE(4), CHASING_DOTS(5), THREE_BOUNCE(6), CIRCLE(7), CUBE_GRID(8), FADING_CIRCLE(9), FOLDING_CUBE(10), ROTATING_CIRCLE(11), MULTIPLE_PULSE(12), PULSE_RING(13), MULTIPLE_PULSE_RING(14); @SuppressWarnings({"FieldCanBeLocal", "unused"}) private int value; Style(int value) { this.value = value; } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/AnimationUtils.java ================================================ package com.github.ybq.android.spinkit.animation; import android.animation.Animator; import android.animation.ValueAnimator; import com.github.ybq.android.spinkit.sprite.Sprite; /** * Created by ybq. */ public class AnimationUtils { public static void start(Animator animator) { if (animator != null && !animator.isStarted()) { animator.start(); } } public static void stop(Animator animator) { if (animator != null && !animator.isRunning()) { animator.end(); } } public static void start(Sprite... sprites) { for (Sprite sprite : sprites) { sprite.start(); } } public static void stop(Sprite... sprites) { for (Sprite sprite : sprites) { sprite.stop(); } } public static boolean isRunning(Sprite... sprites) { for (Sprite sprite : sprites) { if (sprite.isRunning()) { return true; } } return false; } public static boolean isRunning(ValueAnimator animator) { return animator != null && animator.isRunning(); } public static boolean isStarted(ValueAnimator animator) { return animator != null && animator.isStarted(); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/FloatProperty.java ================================================ /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.spinkit.animation; import android.util.Property; /** * An implementation of {@link android.util.Property} to be used specifically with fields of type * float. This type-specific subclass enables performance benefit by allowing * calls to a {@link #set(Object, Float) set()} function that takes the primitive * float type and avoids autoboxing and other overhead associated with the * Float class. * * @param The class on which the Property is declared. */ public abstract class FloatProperty extends Property { public FloatProperty(String name) { super(Float.class, name); } /** * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing * with fields of type float. */ public abstract void setValue(T object, float value); @Override final public void set(T object, Float value) { setValue(object, value); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/IntProperty.java ================================================ /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.spinkit.animation; import android.util.Property; /** * An implementation of {@link android.util.Property} to be used specifically with fields of type * int. This type-specific subclass enables performance benefit by allowing * calls to a {@link #set(Object, Integer) set()} function that takes the primitive * int type and avoids autoboxing and other overhead associated with the * Integer class. * * @param The class on which the Property is declared. */ public abstract class IntProperty extends Property { public IntProperty(String name) { super(Integer.class, name); } /** * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing * with fields of type int. */ public abstract void setValue(T object, int value); @Override final public void set(T object, Integer value) { setValue(object, value); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/SpriteAnimatorBuilder.java ================================================ package com.github.ybq.android.spinkit.animation; import android.animation.Keyframe; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.util.Log; import android.util.Property; import android.view.animation.Animation; import android.view.animation.Interpolator; import com.github.ybq.android.spinkit.animation.interpolator.KeyFrameInterpolator; import com.github.ybq.android.spinkit.sprite.Sprite; import java.util.HashMap; import java.util.Locale; import java.util.Map; /** * Created by ybq. */ public class SpriteAnimatorBuilder { private static final String TAG = "SpriteAnimatorBuilder"; private Sprite sprite; private Interpolator interpolator; private int repeatCount = Animation.INFINITE; private long duration = 2000; private int startFrame = 0; private Map fds = new HashMap<>(); class FrameData { public FrameData(float[] fractions, Property property, T[] values) { this.fractions = fractions; this.property = property; this.values = values; } float[] fractions; Property property; T[] values; } class IntFrameData extends FrameData { public IntFrameData(float[] fractions, Property property, Integer[] values) { super(fractions, property, values); } } class FloatFrameData extends FrameData { public FloatFrameData(float[] fractions, Property property, Float[] values) { super(fractions, property, values); } } public SpriteAnimatorBuilder(Sprite sprite) { this.sprite = sprite; } public SpriteAnimatorBuilder scale(float fractions[], Float... scale) { holder(fractions, Sprite.SCALE, scale); return this; } public SpriteAnimatorBuilder alpha(float fractions[], Integer... alpha) { holder(fractions, Sprite.ALPHA, alpha); return this; } @SuppressWarnings("unused") public SpriteAnimatorBuilder scaleX(float fractions[], Float... scaleX) { holder(fractions, Sprite.SCALE, scaleX); return this; } public SpriteAnimatorBuilder scaleY(float fractions[], Float... scaleY) { holder(fractions, Sprite.SCALE_Y, scaleY); return this; } public SpriteAnimatorBuilder rotateX(float fractions[], Integer... rotateX) { holder(fractions, Sprite.ROTATE_X, rotateX); return this; } public SpriteAnimatorBuilder rotateY(float fractions[], Integer... rotateY) { holder(fractions, Sprite.ROTATE_Y, rotateY); return this; } @SuppressWarnings("unused") public SpriteAnimatorBuilder translateX(float fractions[], Integer... translateX) { holder(fractions, Sprite.TRANSLATE_X, translateX); return this; } @SuppressWarnings("unused") public SpriteAnimatorBuilder translateY(float fractions[], Integer... translateY) { holder(fractions, Sprite.TRANSLATE_Y, translateY); return this; } public SpriteAnimatorBuilder rotate(float fractions[], Integer... rotate) { holder(fractions, Sprite.ROTATE, rotate); return this; } public SpriteAnimatorBuilder translateXPercentage(float fractions[], Float... translateXPercentage) { holder(fractions, Sprite.TRANSLATE_X_PERCENTAGE, translateXPercentage); return this; } public SpriteAnimatorBuilder translateYPercentage(float[] fractions, Float... translateYPercentage) { holder(fractions, Sprite.TRANSLATE_Y_PERCENTAGE, translateYPercentage); return this; } private void holder(float[] fractions, Property property, Float[] values) { ensurePair(fractions.length, values.length); fds.put(property.getName(), new FloatFrameData(fractions, property, values)); } private void holder(float[] fractions, Property property, Integer[] values) { ensurePair(fractions.length, values.length); fds.put(property.getName(), new IntFrameData(fractions, property, values)); } private void ensurePair(int fractionsLength, int valuesLength) { if (fractionsLength != valuesLength) { throw new IllegalStateException(String.format( Locale.getDefault(), "The fractions.length must equal values.length, " + "fraction.length[%d], values.length[%d]", fractionsLength, valuesLength)); } } public SpriteAnimatorBuilder interpolator(Interpolator interpolator) { this.interpolator = interpolator; return this; } public SpriteAnimatorBuilder easeInOut(float... fractions) { interpolator(KeyFrameInterpolator.easeInOut( fractions )); return this; } public SpriteAnimatorBuilder duration(long duration) { this.duration = duration; return this; } @SuppressWarnings("unused") public SpriteAnimatorBuilder repeatCount(int repeatCount) { this.repeatCount = repeatCount; return this; } public SpriteAnimatorBuilder startFrame(int startFrame) { if (startFrame < 0) { Log.w(TAG, "startFrame should always be non-negative"); startFrame = 0; } this.startFrame = startFrame; return this; } public ObjectAnimator build() { PropertyValuesHolder[] holders = new PropertyValuesHolder[fds.size()]; int i = 0; for (Map.Entry fd : fds.entrySet()) { FrameData data = fd.getValue(); Keyframe[] keyframes = new Keyframe[data.fractions.length]; float[] fractions = data.fractions; float startF = fractions[startFrame]; for (int j = startFrame; j < (startFrame + data.values.length); j++) { int key = j - startFrame; int vk = j % data.values.length; float fraction = fractions[vk] - startF; if (fraction < 0) { fraction = fractions[fractions.length - 1] + fraction; } if (data instanceof IntFrameData) { keyframes[key] = Keyframe.ofInt(fraction, (Integer) data.values[vk]); } else if (data instanceof FloatFrameData) { keyframes[key] = Keyframe.ofFloat(fraction, (Float) data.values[vk]); } else { keyframes[key] = Keyframe.ofObject(fraction, data.values[vk]); } } holders[i] = PropertyValuesHolder.ofKeyframe(data.property, keyframes); i++; } ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(sprite, holders); animator.setDuration(duration); animator.setRepeatCount(repeatCount); animator.setInterpolator(interpolator); return animator; } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/Ease.java ================================================ package com.github.ybq.android.spinkit.animation.interpolator; import android.view.animation.Interpolator; /** * Created by ybq. */ public class Ease { public static Interpolator inOut() { return PathInterpolatorCompat.create(0.42f, 0f, 0.58f, 1f); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/KeyFrameInterpolator.java ================================================ package com.github.ybq.android.spinkit.animation.interpolator; import android.animation.TimeInterpolator; import android.view.animation.Interpolator; /** * Created by ybq. */ public class KeyFrameInterpolator implements Interpolator { private TimeInterpolator interpolator; private float[] fractions; public static KeyFrameInterpolator easeInOut(float... fractions) { KeyFrameInterpolator interpolator = new KeyFrameInterpolator(Ease.inOut()); interpolator.setFractions(fractions); return interpolator; } public static KeyFrameInterpolator pathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2, float... fractions) { KeyFrameInterpolator interpolator = new KeyFrameInterpolator(PathInterpolatorCompat.create(controlX1, controlY1, controlX2, controlY2)); interpolator.setFractions(fractions); return interpolator; } public KeyFrameInterpolator(TimeInterpolator interpolator, float... fractions) { this.interpolator = interpolator; this.fractions = fractions; } public void setFractions(float... fractions) { this.fractions = fractions; } @Override public float getInterpolation(float input) { if (fractions.length > 1) { for (int i = 0; i < fractions.length - 1; i++) { float start = fractions[i]; float end = fractions[i + 1]; float duration = end - start; if (input >= start && input <= end) { input = (input - start) / duration; return start + (interpolator.getInterpolation(input) * duration); } } } return interpolator.getInterpolation(input); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorCompat.java ================================================ /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.spinkit.animation.interpolator; import android.graphics.Path; import android.os.Build; import android.view.animation.Interpolator; /** * Helper for creating path-based {@link Interpolator} instances. On API 21 or newer, the * platform implementation will be used and on older platforms a compatible alternative * implementation will be used. */ public class PathInterpolatorCompat { private PathInterpolatorCompat() { // prevent instantiation } /** * Create an {@link Interpolator} for an arbitrary {@link Path}. The {@link Path} * must begin at {@code (0, 0)} and end at {@code (1, 1)}. The x-coordinate along the * {@link Path} is the input value and the output is the y coordinate of the line at that * point. This means that the Path must conform to a function {@code y = f(x)}. *

* The {@link Path} must not have gaps in the x direction and must not * loop back on itself such that there can be two points sharing the same x coordinate. * * @param path the {@link Path} to use to make the line representing the {@link Interpolator} * @return the {@link Interpolator} representing the {@link Path} */ @SuppressWarnings("unused") public static Interpolator create(Path path) { if (Build.VERSION.SDK_INT >= 21) { return PathInterpolatorCompatApi21.create(path); } return PathInterpolatorCompatBase.create(path); } /** * Create an {@link Interpolator} for a quadratic Bezier curve. The end points * {@code (0, 0)} and {@code (1, 1)} are assumed. * * @param controlX the x coordinate of the quadratic Bezier control point * @param controlY the y coordinate of the quadratic Bezier control point * @return the {@link Interpolator} representing the quadratic Bezier curve */ @SuppressWarnings("unused") public static Interpolator create(float controlX, float controlY) { if (Build.VERSION.SDK_INT >= 21) { return PathInterpolatorCompatApi21.create(controlX, controlY); } return PathInterpolatorCompatBase.create(controlX, controlY); } /** * Create an {@link Interpolator} for a cubic Bezier curve. The end points * {@code (0, 0)} and {@code (1, 1)} are assumed. * * @param controlX1 the x coordinate of the first control point of the cubic Bezier * @param controlY1 the y coordinate of the first control point of the cubic Bezier * @param controlX2 the x coordinate of the second control point of the cubic Bezier * @param controlY2 the y coordinate of the second control point of the cubic Bezier * @return the {@link Interpolator} representing the cubic Bezier curve */ public static Interpolator create(float controlX1, float controlY1, float controlX2, float controlY2) { if (Build.VERSION.SDK_INT >= 21) { return PathInterpolatorCompatApi21.create(controlX1, controlY1, controlX2, controlY2); } return PathInterpolatorCompatBase.create(controlX1, controlY1, controlX2, controlY2); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorCompatApi21.java ================================================ /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.spinkit.animation.interpolator; import android.annotation.TargetApi; import android.graphics.Path; import android.os.Build; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; /** * API 21+ implementation for path interpolator compatibility. */ class PathInterpolatorCompatApi21 { private PathInterpolatorCompatApi21() { // prevent instantiation } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static Interpolator create(Path path) { return new PathInterpolator(path); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static Interpolator create(float controlX, float controlY) { return new PathInterpolator(controlX, controlY); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public static Interpolator create(float controlX1, float controlY1, float controlX2, float controlY2) { return new PathInterpolator(controlX1, controlY1, controlX2, controlY2); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorCompatBase.java ================================================ /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.spinkit.animation.interpolator; import android.graphics.Path; import android.view.animation.Interpolator; /** * Base implementation for path interpolator compatibility. */ class PathInterpolatorCompatBase { private PathInterpolatorCompatBase() { // prevent instantiation } public static Interpolator create(Path path) { return new PathInterpolatorDonut(path); } public static Interpolator create(float controlX, float controlY) { return new PathInterpolatorDonut(controlX, controlY); } public static Interpolator create(float controlX1, float controlY1, float controlX2, float controlY2) { return new PathInterpolatorDonut(controlX1, controlY1, controlX2, controlY2); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/animation/interpolator/PathInterpolatorDonut.java ================================================ /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.spinkit.animation.interpolator; import android.graphics.Path; import android.graphics.PathMeasure; import android.view.animation.Interpolator; /** * A path interpolator implementation compatible with API 4+. */ class PathInterpolatorDonut implements Interpolator { /** * Governs the accuracy of the approximation of the {@link Path}. */ private static final float PRECISION = 0.002f; private final float[] mX; private final float[] mY; public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); final float pathLength = pathMeasure.getLength(); final int numPoints = (int) (pathLength / PRECISION) + 1; mX = new float[numPoints]; mY = new float[numPoints]; final float[] position = new float[2]; for (int i = 0; i < numPoints; ++i) { final float distance = (i * pathLength) / (numPoints - 1); pathMeasure.getPosTan(distance, position, null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } } public PathInterpolatorDonut(float controlX, float controlY) { this(createQuad(controlX, controlY)); } public PathInterpolatorDonut(float controlX1, float controlY1, float controlX2, float controlY2) { this(createCubic(controlX1, controlY1, controlX2, controlY2)); } @Override public float getInterpolation(float t) { if (t <= 0.0f) { return 0.0f; } else if (t >= 1.0f) { return 1.0f; } // Do a binary search for the correct x to interpolate between. int startIndex = 0; int endIndex = mX.length - 1; while (endIndex - startIndex > 1) { int midIndex = (startIndex + endIndex) / 2; if (t < mX[midIndex]) { endIndex = midIndex; } else { startIndex = midIndex; } } final float xRange = mX[endIndex] - mX[startIndex]; if (xRange == 0) { return mY[startIndex]; } final float tInRange = t - mX[startIndex]; final float fraction = tInRange / xRange; final float startY = mY[startIndex]; final float endY = mY[endIndex]; return startY + (fraction * (endY - startY)); } private static Path createQuad(float controlX, float controlY) { final Path path = new Path(); path.moveTo(0.0f, 0.0f); path.quadTo(controlX, controlY, 1.0f, 1.0f); return path; } private static Path createCubic(float controlX1, float controlY1, float controlX2, float controlY2) { final Path path = new Path(); path.moveTo(0.0f, 0.0f); path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f); return path; } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/CircleLayoutContainer.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.graphics.Canvas; import android.graphics.Rect; /** * Created by ybq. */ public abstract class CircleLayoutContainer extends SpriteContainer { @Override public void drawChild(Canvas canvas) { for (int i = 0; i < getChildCount(); i++) { Sprite sprite = getChildAt(i); int count = canvas.save(); canvas.rotate(i * 360 / getChildCount(), getBounds().centerX(), getBounds().centerY()); sprite.draw(canvas); canvas.restoreToCount(count); } } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); bounds = clipSquare(bounds); int radius = (int) (bounds.width() * Math.PI / 3.6f / getChildCount()); int left = bounds.centerX() - radius; int right = bounds.centerX() + radius; for (int i = 0; i < getChildCount(); i++) { Sprite sprite = getChildAt(i); sprite.setDrawBounds(left, bounds.top, right, bounds.top + radius * 2); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/CircleSprite.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; /** * Created by ybq. */ public class CircleSprite extends ShapeSprite { @Override public ValueAnimator onCreateAnimation() { return null; } @Override public void drawShape(Canvas canvas, Paint paint) { if (getDrawBounds() != null) { int radius = Math.min(getDrawBounds().width(), getDrawBounds().height()) / 2; canvas.drawCircle(getDrawBounds().centerX(), getDrawBounds().centerY(), radius, paint); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/RectSprite.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; /** * Created by ybq. */ public class RectSprite extends ShapeSprite { @Override public ValueAnimator onCreateAnimation() { return null; } @Override public void drawShape(Canvas canvas, Paint paint) { if (getDrawBounds() != null) { canvas.drawRect(getDrawBounds(), paint); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/RingSprite.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; /** * Created by ybq. */ public class RingSprite extends ShapeSprite { @Override public void drawShape(Canvas canvas, Paint paint) { if (getDrawBounds() != null) { paint.setStyle(Paint.Style.STROKE); int radius = Math.min(getDrawBounds().width(), getDrawBounds().height()) / 2; paint.setStrokeWidth(radius / 12); canvas.drawCircle(getDrawBounds().centerX(), getDrawBounds().centerY(), radius, paint); } } @Override public ValueAnimator onCreateAnimation() { return null; } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/ShapeSprite.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; /** * Created by ybq. */ public abstract class ShapeSprite extends Sprite { private Paint mPaint; private int mUseColor; private int mBaseColor; public ShapeSprite() { setColor(Color.WHITE); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(mUseColor); } @Override public void setColor(int color) { mBaseColor = color; updateUseColor(); } @Override public int getColor() { return mBaseColor; } @SuppressWarnings("unused") public int getUseColor() { return mUseColor; } @Override public void setAlpha(int alpha) { super.setAlpha(alpha); updateUseColor(); } private void updateUseColor() { int alpha = getAlpha(); alpha += alpha >> 7; final int baseAlpha = mBaseColor >>> 24; final int useAlpha = baseAlpha * alpha >> 8; mUseColor = (mBaseColor << 8 >>> 8) | (useAlpha << 24); } @Override public void setColorFilter(ColorFilter colorFilter) { mPaint.setColorFilter(colorFilter); } @Override protected final void drawSelf(Canvas canvas) { mPaint.setColor(mUseColor); drawShape(canvas, mPaint); } public abstract void drawShape(Canvas canvas, Paint paint); } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/Sprite.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.animation.ValueAnimator; import android.graphics.Camera; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.util.Property; import com.github.ybq.android.spinkit.animation.AnimationUtils; import com.github.ybq.android.spinkit.animation.FloatProperty; import com.github.ybq.android.spinkit.animation.IntProperty; /** * Created by ybq. */ public abstract class Sprite extends Drawable implements ValueAnimator.AnimatorUpdateListener , Animatable , Drawable.Callback { private float scale = 1; private float scaleX = 1; private float scaleY = 1; private float pivotX; private float pivotY; private int animationDelay; private int rotateX; private int rotateY; private int translateX; private int translateY; private int rotate; private float translateXPercentage; private float translateYPercentage; private ValueAnimator animator; private int alpha = 255; private static final Rect ZERO_BOUNDS_RECT = new Rect(); protected Rect drawBounds = ZERO_BOUNDS_RECT; private Camera mCamera; private Matrix mMatrix; public Sprite() { mCamera = new Camera(); mMatrix = new Matrix(); } public abstract int getColor(); public abstract void setColor(int color); @Override public void setAlpha(int alpha) { this.alpha = alpha; } @Override public int getAlpha() { return alpha; } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } public float getTranslateXPercentage() { return translateXPercentage; } public void setTranslateXPercentage(float translateXPercentage) { this.translateXPercentage = translateXPercentage; } public float getTranslateYPercentage() { return translateYPercentage; } public void setTranslateYPercentage(float translateYPercentage) { this.translateYPercentage = translateYPercentage; } public int getTranslateX() { return translateX; } public void setTranslateX(int translateX) { this.translateX = translateX; } public int getTranslateY() { return translateY; } public void setTranslateY(int translateY) { this.translateY = translateY; } public int getRotate() { return rotate; } public void setRotate(int rotate) { this.rotate = rotate; } public float getScale() { return scale; } public void setScale(float scale) { this.scale = scale; setScaleX(scale); setScaleY(scale); } public float getScaleX() { return scaleX; } public void setScaleX(float scaleX) { this.scaleX = scaleX; } public float getScaleY() { return scaleY; } public void setScaleY(float scaleY) { this.scaleY = scaleY; } public int getRotateX() { return rotateX; } public void setRotateX(int rotateX) { this.rotateX = rotateX; } public int getRotateY() { return rotateY; } public void setRotateY(int rotateY) { this.rotateY = rotateY; } public float getPivotX() { return pivotX; } public void setPivotX(float pivotX) { this.pivotX = pivotX; } public float getPivotY() { return pivotY; } public void setPivotY(float pivotY) { this.pivotY = pivotY; } @SuppressWarnings("unused") public int getAnimationDelay() { return animationDelay; } public Sprite setAnimationDelay(int animationDelay) { this.animationDelay = animationDelay; return this; } @Override public void setColorFilter(ColorFilter colorFilter) { } public abstract ValueAnimator onCreateAnimation(); @Override public void start() { if (AnimationUtils.isStarted(animator)) { return; } animator = obtainAnimation(); if (animator == null) { return; } AnimationUtils.start(animator); invalidateSelf(); } public ValueAnimator obtainAnimation() { if (animator == null) { animator = onCreateAnimation(); } if (animator != null) { animator.addUpdateListener(this); animator.setStartDelay(animationDelay); } return animator; } @Override public void stop() { if (AnimationUtils.isStarted(animator)) { animator.removeAllUpdateListeners(); animator.end(); reset(); } } protected abstract void drawSelf(Canvas canvas); public void reset() { scale = 1; rotateX = 0; rotateY = 0; translateX = 0; translateY = 0; rotate = 0; translateXPercentage = 0f; translateYPercentage = 0f; } @Override public boolean isRunning() { return AnimationUtils.isRunning(animator); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); setDrawBounds(bounds); } public void setDrawBounds(Rect drawBounds) { setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom); } public void setDrawBounds(int left, int top, int right, int bottom) { this.drawBounds = new Rect(left, top, right, bottom); setPivotX(getDrawBounds().centerX()); setPivotY(getDrawBounds().centerY()); } @Override public void invalidateDrawable(Drawable who) { invalidateSelf(); } @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { } @Override public void unscheduleDrawable(Drawable who, Runnable what) { } @Override public void onAnimationUpdate(ValueAnimator animation) { final Callback callback = getCallback(); if (callback != null) { callback.invalidateDrawable(this); } } public Rect getDrawBounds() { return drawBounds; } @Override public void draw(Canvas canvas) { int tx = getTranslateX(); tx = tx == 0 ? (int) (getBounds().width() * getTranslateXPercentage()) : tx; int ty = getTranslateY(); ty = ty == 0 ? (int) (getBounds().height() * getTranslateYPercentage()) : ty; canvas.translate(tx, ty); canvas.scale(getScaleX(), getScaleY(), getPivotX(), getPivotY()); canvas.rotate(getRotate(), getPivotX(), getPivotY()); if (getRotateX() != 0 || getRotateY() != 0) { mCamera.save(); mCamera.rotateX(getRotateX()); mCamera.rotateY(getRotateY()); mCamera.getMatrix(mMatrix); mMatrix.preTranslate(-getPivotX(), -getPivotY()); mMatrix.postTranslate(getPivotX(), getPivotY()); mCamera.restore(); canvas.concat(mMatrix); } drawSelf(canvas); } public Rect clipSquare(Rect rect) { int w = rect.width(); int h = rect.height(); int min = Math.min(w, h); int cx = rect.centerX(); int cy = rect.centerY(); int r = min / 2; return new Rect( cx - r, cy - r, cx + r, cy + r ); } public static final Property ROTATE_X = new IntProperty("rotateX") { @Override public void setValue(Sprite object, int value) { object.setRotateX(value); } @Override public Integer get(Sprite object) { return object.getRotateX(); } }; public static final Property ROTATE = new IntProperty("rotate") { @Override public void setValue(Sprite object, int value) { object.setRotate(value); } @Override public Integer get(Sprite object) { return object.getRotate(); } }; public static final Property ROTATE_Y = new IntProperty("rotateY") { @Override public void setValue(Sprite object, int value) { object.setRotateY(value); } @Override public Integer get(Sprite object) { return object.getRotateY(); } }; @SuppressWarnings("unused") public static final Property TRANSLATE_X = new IntProperty("translateX") { @Override public void setValue(Sprite object, int value) { object.setTranslateX(value); } @Override public Integer get(Sprite object) { return object.getTranslateX(); } }; @SuppressWarnings("unused") public static final Property TRANSLATE_Y = new IntProperty("translateY") { @Override public void setValue(Sprite object, int value) { object.setTranslateY(value); } @Override public Integer get(Sprite object) { return object.getTranslateY(); } }; public static final Property TRANSLATE_X_PERCENTAGE = new FloatProperty("translateXPercentage") { @Override public void setValue(Sprite object, float value) { object.setTranslateXPercentage(value); } @Override public Float get(Sprite object) { return object.getTranslateXPercentage(); } }; public static final Property TRANSLATE_Y_PERCENTAGE = new FloatProperty("translateYPercentage") { @Override public void setValue(Sprite object, float value) { object.setTranslateYPercentage(value); } @Override public Float get(Sprite object) { return object.getTranslateYPercentage(); } }; @SuppressWarnings("unused") public static final Property SCALE_X = new FloatProperty("scaleX") { @Override public void setValue(Sprite object, float value) { object.setScaleX(value); } @Override public Float get(Sprite object) { return object.getScaleX(); } }; public static final Property SCALE_Y = new FloatProperty("scaleY") { @Override public void setValue(Sprite object, float value) { object.setScaleY(value); } @Override public Float get(Sprite object) { return object.getScaleY(); } }; public static final Property SCALE = new FloatProperty("scale") { @Override public void setValue(Sprite object, float value) { object.setScale(value); } @Override public Float get(Sprite object) { return object.getScale(); } }; public static final Property ALPHA = new IntProperty("alpha") { @Override public void setValue(Sprite object, int value) { object.setAlpha(value); } @Override public Integer get(Sprite object) { return object.getAlpha(); } }; } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/sprite/SpriteContainer.java ================================================ package com.github.ybq.android.spinkit.sprite; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Rect; import com.github.ybq.android.spinkit.animation.AnimationUtils; /** * Created by ybq. */ public abstract class SpriteContainer extends Sprite { private Sprite[] sprites; private int color; public SpriteContainer() { sprites = onCreateChild(); initCallBack(); onChildCreated(sprites); } private void initCallBack() { if (sprites != null) { for (Sprite sprite : sprites) { sprite.setCallback(this); } } } public void onChildCreated(Sprite... sprites) { } public int getChildCount() { return sprites == null ? 0 : sprites.length; } public Sprite getChildAt(int index) { return sprites == null ? null : sprites[index]; } @Override public void setColor(int color) { this.color = color; for (int i = 0; i < getChildCount(); i++) { getChildAt(i).setColor(color); } } @Override public int getColor() { return color; } @Override public void draw(Canvas canvas) { super.draw(canvas); drawChild(canvas); } public void drawChild(Canvas canvas) { if (sprites != null) { for (Sprite sprite : sprites) { int count = canvas.save(); sprite.draw(canvas); canvas.restoreToCount(count); } } } @Override protected void drawSelf(Canvas canvas) { } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); for (Sprite sprite : sprites) { sprite.setBounds(bounds); } } @Override public void start() { super.start(); AnimationUtils.start(sprites); } @Override public void stop() { super.stop(); AnimationUtils.stop(sprites); } @Override public boolean isRunning() { return AnimationUtils.isRunning(sprites) || super.isRunning(); } public abstract Sprite[] onCreateChild(); @Override public ValueAnimator onCreateAnimation() { return null; } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/ChasingDots.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Rect; import android.os.Build; import android.view.animation.LinearInterpolator; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class ChasingDots extends SpriteContainer { @Override public Sprite[] onCreateChild() { return new Sprite[]{ new Dot(), new Dot() }; } @Override public void onChildCreated(Sprite... sprites) { super.onChildCreated(sprites); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { sprites[1].setAnimationDelay(1000); } else { sprites[1].setAnimationDelay(-1000); } } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 1f}; return new SpriteAnimatorBuilder(this). rotate(fractions, 0, 360). duration(2000). interpolator(new LinearInterpolator()). build(); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); bounds = clipSquare(bounds); int drawW = (int) (bounds.width() * 0.6f); getChildAt(0).setDrawBounds( bounds.right - drawW, bounds.top, bounds.right , bounds.top + drawW ); getChildAt(1).setDrawBounds( bounds.right - drawW, bounds.bottom - drawW, bounds.right, bounds.bottom ); } private class Dot extends CircleSprite { Dot() { setScale(0f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.5f, 1f}; return new SpriteAnimatorBuilder(this). scale(fractions, 0f, 1f, 0f). duration(2000). easeInOut(fractions) .build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/Circle.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.os.Build; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleLayoutContainer; import com.github.ybq.android.spinkit.sprite.CircleSprite; import com.github.ybq.android.spinkit.sprite.Sprite; /** * Created by ybq. */ public class Circle extends CircleLayoutContainer { @Override public Sprite[] onCreateChild() { Dot[] dots = new Dot[12]; for (int i = 0; i < dots.length; i++) { dots[i] = new Dot(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { dots[i].setAnimationDelay(1200 / 12 * i); } else { dots[i].setAnimationDelay(1200 / 12 * i + -1200); } } return dots; } private class Dot extends CircleSprite { Dot() { setScale(0f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.5f, 1f}; return new SpriteAnimatorBuilder(this). scale(fractions, 0f, 1f, 0f). duration(1200). easeInOut(fractions) .build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/CubeGrid.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Rect; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.RectSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class CubeGrid extends SpriteContainer { @Override public Sprite[] onCreateChild() { int delays[] = new int[]{ 200, 300, 400 , 100, 200, 300 , 0, 100, 200 }; GridItem[] gridItems = new GridItem[9]; for (int i = 0; i < gridItems.length; i++) { gridItems[i] = new GridItem(); gridItems[i].setAnimationDelay(delays[i]); } return gridItems; } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); bounds = clipSquare(bounds); int width = (int) (bounds.width() * 0.33f); int height = (int) (bounds.height() * 0.33f); for (int i = 0; i < getChildCount(); i++) { int x = i % 3; int y = i / 3; int l = bounds.left + x * width; int t = bounds.top + y * height; Sprite sprite = getChildAt(i); sprite.setDrawBounds(l, t, l + width, t + height); } } private class GridItem extends RectSprite { @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.35f, 0.7f, 1f}; return new SpriteAnimatorBuilder(this). scale(fractions, 1f, 0f, 1f, 1f). duration(1300). easeInOut(fractions) .build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/DoubleBounce.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.os.Build; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class DoubleBounce extends SpriteContainer { @Override public Sprite[] onCreateChild() { return new Sprite[]{ new Bounce(), new Bounce() }; } @Override public void onChildCreated(Sprite... sprites) { super.onChildCreated(sprites); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { sprites[1].setAnimationDelay(1000); } else { sprites[1].setAnimationDelay(-1000); } } private class Bounce extends CircleSprite { Bounce() { setAlpha(153); setScale(0f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.5f, 1f}; return new SpriteAnimatorBuilder(this).scale(fractions, 0f, 1f, 0f). duration(2000). easeInOut(fractions) .build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/FadingCircle.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.os.Build; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleLayoutContainer; import com.github.ybq.android.spinkit.sprite.CircleSprite; import com.github.ybq.android.spinkit.sprite.Sprite; /** * Created by ybq. */ public class FadingCircle extends CircleLayoutContainer { @Override public Sprite[] onCreateChild() { Dot[] dots = new Dot[12]; for (int i = 0; i < dots.length; i++) { dots[i] = new Dot(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { dots[i].setAnimationDelay(1200 / 12 * i); } else { dots[i].setAnimationDelay(1200 / 12 * i + -1200); } } return dots; } private class Dot extends CircleSprite { Dot() { setAlpha(0); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.39f, 0.4f, 1f}; return new SpriteAnimatorBuilder(this). alpha(fractions, 0, 0, 255, 0). duration(1200). easeInOut(fractions).build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/FoldingCube.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Build; import android.view.animation.LinearInterpolator; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.RectSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class FoldingCube extends SpriteContainer { @SuppressWarnings("FieldCanBeLocal") private boolean wrapContent = false; @Override public Sprite[] onCreateChild() { Cube[] cubes = new Cube[4]; for (int i = 0; i < cubes.length; i++) { cubes[i] = new Cube(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { cubes[i].setAnimationDelay(300 * i); } else { cubes[i].setAnimationDelay(300 * i - 1200); } } return cubes; } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); bounds = clipSquare(bounds); int size = Math.min(bounds.width(), bounds.height()); if (wrapContent) { size = (int) Math.sqrt( (size * size) / 2); int oW = (bounds.width() - size) / 2; int oH = (bounds.height() - size) / 2; bounds = new Rect( bounds.left + oW, bounds.top + oH, bounds.right - oW, bounds.bottom - oH ); } int px = bounds.left + size / 2 + 1; int py = bounds.top + size / 2 + 1; for (int i = 0; i < getChildCount(); i++) { Sprite sprite = getChildAt(i); sprite.setDrawBounds( bounds.left, bounds.top, px, py ); sprite.setPivotX(sprite.getDrawBounds().right); sprite.setPivotY(sprite.getDrawBounds().bottom); } } @Override public void drawChild(Canvas canvas) { Rect bounds = clipSquare(getBounds()); for (int i = 0; i < getChildCount(); i++) { int count = canvas.save(); canvas.rotate(45 + i * 90, bounds.centerX(), bounds.centerY()); Sprite sprite = getChildAt(i); sprite.draw(canvas); canvas.restoreToCount(count); } } private class Cube extends RectSprite { Cube() { setAlpha(0); setRotateX(-180); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.1f, 0.25f, 0.75f, 0.9f, 1f}; return new SpriteAnimatorBuilder(this). alpha(fractions, 0, 0, 255, 255, 0, 0). rotateX(fractions, -180, -180, 0, 0, 0, 0). rotateY(fractions, 0, 0, 0, 0, 180, 180). duration(2400). interpolator(new LinearInterpolator()) .build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/MultiplePulse.java ================================================ package com.github.ybq.android.spinkit.style; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class MultiplePulse extends SpriteContainer { @Override public Sprite[] onCreateChild() { return new Sprite[]{ new Pulse(), new Pulse(), new Pulse(), }; } @Override public void onChildCreated(Sprite... sprites) { for (int i = 0; i < sprites.length; i++) { sprites[i].setAnimationDelay(200 * (i + 1)); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/MultiplePulseRing.java ================================================ package com.github.ybq.android.spinkit.style; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class MultiplePulseRing extends SpriteContainer { @Override public Sprite[] onCreateChild() { return new Sprite[]{ new PulseRing(), new PulseRing(), new PulseRing(), }; } @Override public void onChildCreated(Sprite... sprites) { for (int i = 0; i < sprites.length; i++) { sprites[i].setAnimationDelay(200 * (i + 1)); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/Pulse.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleSprite; /** * Created by ybq. */ public class Pulse extends CircleSprite { public Pulse() { setScale(0f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 1f}; return new SpriteAnimatorBuilder(this). scale(fractions, 0f, 1f). alpha(fractions, 255, 0). duration(1000). easeInOut(fractions) .build(); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/PulseRing.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.animation.interpolator.KeyFrameInterpolator; import com.github.ybq.android.spinkit.sprite.RingSprite; /** * Created by ybq. */ public class PulseRing extends RingSprite { public PulseRing() { setScale(0f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.7f, 1f}; return new SpriteAnimatorBuilder(this). scale(fractions, 0f, 1f, 1f). alpha(fractions, 255, (int) (255 * 0.7), 0). duration(1000). interpolator(KeyFrameInterpolator.pathInterpolator(0.21f, 0.53f, 0.56f, 0.8f, fractions)). build(); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/RotatingCircle.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleSprite; public class RotatingCircle extends CircleSprite { @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.5f, 1f}; return new SpriteAnimatorBuilder(this). rotateX(fractions, 0, -180, -180). rotateY(fractions, 0, 0, -180). duration(1200). easeInOut(fractions) .build(); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/RotatingPlane.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Rect; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.RectSprite; /** * Created by ybq. */ public class RotatingPlane extends RectSprite { @Override protected void onBoundsChange(Rect bounds) { setDrawBounds(clipSquare(bounds)); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.5f, 1f}; return new SpriteAnimatorBuilder(this). rotateX(fractions, 0, -180, -180). rotateY(fractions, 0, 0, -180). duration(1200). easeInOut(fractions) .build(); } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/ThreeBounce.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Rect; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.CircleSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class ThreeBounce extends SpriteContainer { @Override public Sprite[] onCreateChild() { return new Sprite[]{ new Bounce(), new Bounce(), new Bounce() }; } @Override public void onChildCreated(Sprite... sprites) { super.onChildCreated(sprites); sprites[1].setAnimationDelay(160); sprites[2].setAnimationDelay(320); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); bounds = clipSquare(bounds); int radius = bounds.width() / 8; int top = bounds.centerY() - radius; int bottom = bounds.centerY() + radius; for (int i = 0; i < getChildCount(); i++) { int left = bounds.width() * i / 3 + bounds.left; getChildAt(i).setDrawBounds( left, top, left + radius * 2, bottom ); } } private class Bounce extends CircleSprite { Bounce() { setScale(0f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.4f, 0.8f, 1f}; return new SpriteAnimatorBuilder(this).scale(fractions, 0f, 1f, 0f, 0f). duration(1400). easeInOut(fractions) .build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/WanderingCubes.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Rect; import android.os.Build; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.RectSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class WanderingCubes extends SpriteContainer { @Override public Sprite[] onCreateChild() { return new Sprite[]{ new Cube(0), new Cube(3) }; } @Override public void onChildCreated(Sprite... sprites) { super.onChildCreated(sprites); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { sprites[1].setAnimationDelay(-900); } } @Override protected void onBoundsChange(Rect bounds) { bounds = clipSquare(bounds); super.onBoundsChange(bounds); for (int i = 0; i < getChildCount(); i++) { Sprite sprite = getChildAt(i); sprite.setDrawBounds( bounds.left, bounds.top, bounds.left + bounds.width() / 4, bounds.top + bounds.height() / 4 ); } } private class Cube extends RectSprite { int startFrame; public Cube(int startFrame) { this.startFrame = startFrame; } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.25f, 0.5f, 0.51f, 0.75f, 1f}; SpriteAnimatorBuilder builder = new SpriteAnimatorBuilder(this). rotate(fractions, 0, -90, -179, -180, -270, -360). translateXPercentage(fractions, 0f, 0.75f, 0.75f, 0.75f, 0f, 0f). translateYPercentage(fractions, 0f, 0f, 0.75f, 0.75f, 0.75f, 0f). scale(fractions, 1f, 0.5f, 1f, 1f, 0.5f, 1f). duration(1800). easeInOut(fractions); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder. startFrame(startFrame); } return builder.build(); } } } ================================================ FILE: library/src/main/java/com/github/ybq/android/spinkit/style/Wave.java ================================================ package com.github.ybq.android.spinkit.style; import android.animation.ValueAnimator; import android.graphics.Rect; import android.os.Build; import com.github.ybq.android.spinkit.animation.SpriteAnimatorBuilder; import com.github.ybq.android.spinkit.sprite.RectSprite; import com.github.ybq.android.spinkit.sprite.Sprite; import com.github.ybq.android.spinkit.sprite.SpriteContainer; /** * Created by ybq. */ public class Wave extends SpriteContainer { @Override public Sprite[] onCreateChild() { WaveItem[] waveItems = new WaveItem[5]; for (int i = 0; i < waveItems.length; i++) { waveItems[i] = new WaveItem(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { waveItems[i].setAnimationDelay(600 + i * 100); } else { waveItems[i].setAnimationDelay(-1200 + i * 100); } } return waveItems; } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); bounds = clipSquare(bounds); int rw = bounds.width() / getChildCount(); int width = bounds.width() / 5 * 3 / 5; for (int i = 0; i < getChildCount(); i++) { Sprite sprite = getChildAt(i); int l = bounds.left + i * rw + rw / 5; int r = l + width; sprite.setDrawBounds(l, bounds.top, r, bounds.bottom); } } private class WaveItem extends RectSprite { WaveItem() { setScaleY(0.4f); } @Override public ValueAnimator onCreateAnimation() { float fractions[] = new float[]{0f, 0.2f, 0.4f, 1f}; return new SpriteAnimatorBuilder(this).scaleY(fractions, 0.4f, 1f, 0.4f, 0.4f). duration(1200). easeInOut(fractions) .build(); } } } ================================================ FILE: library/src/main/res/values/attrs.xml ================================================ ================================================ FILE: library/src/main/res/values/styles.xml ================================================ ================================================ FILE: sample/.gitignore ================================================ /build ================================================ FILE: sample/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 28 buildToolsVersion '28.0.3' defaultConfig { applicationId "com.github.ybq.android.spinkit" minSdkVersion 14 targetSdkVersion 28 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'com.google.android.material:material:1.0.0' implementation project(':library') } ================================================ FILE: sample/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/ybq/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: sample/src/main/AndroidManifest.xml ================================================ ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/ArgbEvaluator.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.ybq.android.loading; import android.animation.TypeEvaluator; /** * This evaluator can be used to perform type interpolation between integer * values that represent ARGB colors. */ public class ArgbEvaluator implements TypeEvaluator { private static final ArgbEvaluator sInstance = new ArgbEvaluator(); /** * Returns an instance of ArgbEvaluator that may be used in * {@link android.animation.ValueAnimator#setEvaluator(TypeEvaluator)}. The same instance may * be used in multiple Animators because it holds no state. * * @return An instance of ArgbEvalutor. */ public static ArgbEvaluator getInstance() { return sInstance; } /** * This function returns the calculated in-between value for a color * given integers that represent the start and end values in the four * bytes of the 32-bit int. Each channel is separately linearly interpolated * and the resulting calculated values are recombined into the return value. * * @param fraction The fraction from the starting to the ending values * @param startValue A 32-bit int value representing colors in the * separate bytes of the parameter * @param endValue A 32-bit int value representing colors in the * separate bytes of the parameter * @return A value that is calculated to be the linearly interpolated * result, derived by separating the start and end values into separate * color channels and interpolating each one separately, recombining the * resulting values in the same way. */ public Object evaluate(float fraction, Object startValue, Object endValue) { int startInt = (Integer) startValue; int startA = (startInt >> 24) & 0xff; int startR = (startInt >> 16) & 0xff; int startG = (startInt >> 8) & 0xff; int startB = startInt & 0xff; int endInt = (Integer) endValue; int endA = (endInt >> 24) & 0xff; int endR = (endInt >> 16) & 0xff; int endG = (endInt >> 8) & 0xff; int endB = endInt & 0xff; return (startA + (int) (fraction * (endA - startA))) << 24 | (startR + (int) (fraction * (endR - startR))) << 16 | (startG + (int) (fraction * (endG - startG))) << 8 | (startB + (int) (fraction * (endB - startB))); } } ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/Colors.java ================================================ package com.github.ybq.android.loading; /** * Created by ybq. */ public interface Colors { int[] colors = new int[]{ 0XFFD55400, 0XFF2B3E51, 0XFF00BD9C, 0XFF227FBB, 0XFF7F8C8D, 0XFFFFCC5C, 0XFFD55400, 0XFF1AAF5D, }; } ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/DetailActivity.java ================================================ package com.github.ybq.android.loading; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.github.ybq.android.spinkit.SpinKitView; import com.github.ybq.android.spinkit.SpriteFactory; import com.github.ybq.android.spinkit.Style; import com.github.ybq.android.spinkit.sprite.Sprite; import androidx.appcompat.app.AppCompatActivity; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; public class DetailActivity extends AppCompatActivity implements Colors { public static void start(Context context, int position) { Intent intent = new Intent(context, DetailActivity.class); intent.putExtra("position", position); context.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager); viewPager.setOffscreenPageLimit(0); viewPager.setAdapter(new PagerAdapter() { @Override public int getCount() { return Style.values().length; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { @SuppressLint("InflateParams") View view = LayoutInflater.from(container.getContext()).inflate(R.layout.item_pager, null); SpinKitView spinKitView = (SpinKitView) view.findViewById(R.id.spin_kit); TextView name = (TextView) view.findViewById(R.id.name); Style style = Style.values()[position]; name.setText(style.name().toLowerCase()); Sprite drawable = SpriteFactory.create(style); spinKitView.setIndeterminateDrawable(drawable); container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { int color = (int) ArgbEvaluator.getInstance().evaluate(positionOffset, colors[position % colors.length], colors[(position + 1) % colors.length]); getWindow().getDecorView().setBackgroundColor(color); } @Override public void onPageSelected(int position) { getWindow().getDecorView().setBackgroundColor(colors[position % colors.length]); } @Override public void onPageScrollStateChanged(int state) { } }); viewPager.setCurrentItem(getIntent().getIntExtra("position", 0)); } } ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/MainActivity.java ================================================ package com.github.ybq.android.loading; import android.os.Bundle; import com.google.android.material.tabs.TabLayout; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; public class MainActivity extends AppCompatActivity { TabLayout mTabLayout; ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTabLayout = (TabLayout) findViewById(R.id.tabs); mViewPager = (ViewPager) findViewById(R.id.viewpager); mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { String[] titles = new String[]{ "Style", "Widget" }; @Override public Fragment getItem(int position) { if (position == 0) { return StyleFragment.newInstance(); } else { return WidgetFragment.newInstance(); } } @Override public int getCount() { return 2; } @Override public CharSequence getPageTitle(int position) { return titles[position]; } }); mTabLayout.setupWithViewPager(mViewPager); } } ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/SquareFrameLayout.java ================================================ package com.github.ybq.android.loading; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.widget.FrameLayout; /** * Created by ybq. */ public class SquareFrameLayout extends FrameLayout { public SquareFrameLayout(Context context) { super(context); } public SquareFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @SuppressWarnings("unused") @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //noinspection SuspiciousNameCombination super.onMeasure(widthMeasureSpec, widthMeasureSpec); } } ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/StyleFragment.java ================================================ package com.github.ybq.android.loading; import android.annotation.SuppressLint; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.github.ybq.android.spinkit.SpinKitView; import com.github.ybq.android.spinkit.SpriteFactory; import com.github.ybq.android.spinkit.Style; import com.github.ybq.android.spinkit.sprite.Sprite; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; /** * Created by ybq. */ public class StyleFragment extends Fragment implements Colors { public static StyleFragment newInstance() { return new StyleFragment(); } @SuppressLint("InflateParams") @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_style, null); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list); GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 4); layoutManager.setOrientation(RecyclerView.VERTICAL); recyclerView.setLayoutManager(layoutManager); recyclerView.setAdapter(new RecyclerView.Adapter() { @Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) { @SuppressLint("InflateParams") View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_style, null); return new Holder(view); } @Override public void onBindViewHolder(Holder holder, int position) { holder.bind(position); } @Override public int getItemCount() { return Style.values().length; } }); } class Holder extends RecyclerView.ViewHolder { SpinKitView spinKitView; public Holder(View itemView) { super(itemView); spinKitView = (SpinKitView) itemView.findViewById(R.id.spin_kit); } public void bind(int position) { itemView.setBackgroundColor(colors[position % colors.length]); final int finalPosition = position; itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DetailActivity.start(v.getContext(), finalPosition); } }); position = position % 15; Style style = Style.values()[position]; Sprite drawable = SpriteFactory.create(style); spinKitView.setIndeterminateDrawable(drawable); } } } ================================================ FILE: sample/src/main/java/com/github/ybq/android/loading/WidgetFragment.java ================================================ package com.github.ybq.android.loading; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.github.ybq.android.spinkit.style.ChasingDots; import com.github.ybq.android.spinkit.style.Circle; import com.github.ybq.android.spinkit.style.DoubleBounce; import com.github.ybq.android.spinkit.style.Wave; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; /** * Created by ybq. */ public class WidgetFragment extends Fragment implements Colors { private Wave mWaveDrawable; private Circle mCircleDrawable; private ChasingDots mChasingDotsDrawable; public static WidgetFragment newInstance() { return new WidgetFragment(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_widget, null); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); //ProgressBar ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progress); DoubleBounce doubleBounce = new DoubleBounce(); doubleBounce.setBounds(0, 0, 100, 100); doubleBounce.setColor(colors[7]); progressBar.setIndeterminateDrawable(doubleBounce); //Button Button button = (Button) view.findViewById(R.id.button); mWaveDrawable = new Wave(); mWaveDrawable.setBounds(0, 0, 100, 100); //noinspection deprecation mWaveDrawable.setColor(getResources().getColor(R.color.colorAccent)); button.setCompoundDrawables(mWaveDrawable, null, null, null); //TextView TextView textView = (TextView) view.findViewById(R.id.text); mCircleDrawable = new Circle(); mCircleDrawable.setBounds(0, 0, 100, 100); mCircleDrawable.setColor(Color.WHITE); textView.setCompoundDrawables(null, null, mCircleDrawable, null); textView.setBackgroundColor(colors[2]); //ImageView ImageView imageView = (ImageView) view.findViewById(R.id.image); mChasingDotsDrawable = new ChasingDots(); mChasingDotsDrawable.setColor(Color.WHITE); imageView.setImageDrawable(mChasingDotsDrawable); imageView.setBackgroundColor(colors[0]); } @Override public void onResume() { super.onResume(); mWaveDrawable.start(); mCircleDrawable.start(); mChasingDotsDrawable.start(); } @Override public void onStop() { super.onStop(); mWaveDrawable.stop(); mCircleDrawable.stop(); mChasingDotsDrawable.stop(); } } ================================================ FILE: sample/src/main/res/layout/activity_detail.xml ================================================ ================================================ FILE: sample/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_style.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_widget.xml ================================================