├── .gitignore ├── Demo ├── QML-Loaders-Demo.pro ├── android │ ├── AndroidManifest.xml │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── res │ │ ├── drawable-hdpi │ │ └── icon.png │ │ ├── drawable-ldpi │ │ └── icon.png │ │ ├── drawable-mdpi │ │ └── icon.png │ │ └── values │ │ └── libs.xml ├── images │ └── icon │ │ └── android │ │ ├── feature_graphic.png │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-ldpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── playstore-icon.png ├── main.cpp ├── qml.qrc ├── qml │ ├── DemoCard.qml │ ├── DemoCardList.qml │ ├── Loaders │ │ ├── BlockLoader.qml │ │ ├── ClockSpinner.qml │ │ ├── FishSpinner.qml │ │ ├── LineSpinner.qml │ │ ├── PulseLoader.qml │ │ ├── RectangleLoader.qml │ │ └── SharinganLoader.qml │ └── main.qml └── src │ ├── QMLManager.h │ ├── ScreenHelper.cpp │ └── ScreenHelper.h ├── Loaders ├── BlockLoader.qml ├── ClockSpinner.qml ├── FishSpinner.qml ├── LineSpinner.qml ├── PulseLoader.qml ├── RectangleLoader.qml └── SharinganLoader.qml ├── README.md └── demo.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | qrc_*.cpp 24 | ui_*.h 25 | Makefile* 26 | *build-* 27 | 28 | # QtCreator 29 | 30 | *.autosave 31 | 32 | # QtCtreator Qml 33 | *.qmlproject.user 34 | *.qmlproject.user.* 35 | 36 | # QtCtreator CMake 37 | CMakeLists.txt.user 38 | 39 | -------------------------------------------------------------------------------- /Demo/QML-Loaders-Demo.pro: -------------------------------------------------------------------------------- 1 | # Application icon is from here: https://pixabay.com/en/loading-animation-web-design-green-1863182/ 2 | 3 | TEMPLATE = app 4 | 5 | QT += qml quick 6 | CONFIG += c++11 7 | 8 | SOURCES += main.cpp 9 | 10 | win32: { 11 | CONFIG(release, debug|release): { 12 | RESOURCES += qml.qrc 13 | } 14 | } 15 | else: { 16 | RESOURCES += qml.qrc 17 | } 18 | 19 | # Additional import path used to resolve QML modules in Qt Creator's code model 20 | QML_IMPORT_PATH = 21 | 22 | # Additional import path used to resolve QML modules just for Qt Quick Designer 23 | QML_DESIGNER_IMPORT_PATH = 24 | 25 | # The following define makes your compiler emit warnings if you use 26 | # any feature of Qt which as been marked deprecated (the exact warnings 27 | # depend on your compiler). Please consult the documentation of the 28 | # deprecated API in order to know how to port your code away from it. 29 | DEFINES += QT_DEPRECATED_WARNINGS 30 | 31 | # You can also make your code fail to compile if you use deprecated APIs. 32 | # In order to do so, uncomment the following line. 33 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 34 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 35 | 36 | # Default rules for deployment. 37 | qnx: target.path = /tmp/$${TARGET}/bin 38 | else: unix:!android: target.path = /opt/$${TARGET}/bin 39 | !isEmpty(target.path): INSTALLS += target 40 | 41 | HEADERS += \ 42 | src/QMLManager.h \ 43 | src/ScreenHelper.h \ 44 | 45 | SOURCES += \ 46 | src/ScreenHelper.cpp 47 | 48 | DISTFILES += \ 49 | android/AndroidManifest.xml \ 50 | android/gradle/wrapper/gradle-wrapper.jar \ 51 | android/gradlew \ 52 | android/res/values/libs.xml \ 53 | android/build.gradle \ 54 | android/gradle/wrapper/gradle-wrapper.properties \ 55 | android/gradlew.bat 56 | 57 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 58 | -------------------------------------------------------------------------------- /Demo/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Demo/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.1.0' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | } 15 | } 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | dependencies { 20 | compile fileTree(dir: 'libs', include: ['*.jar']) 21 | } 22 | 23 | android { 24 | /******************************************************* 25 | * The following variables: 26 | * - androidBuildToolsVersion, 27 | * - androidCompileSdkVersion 28 | * - qt5AndroidDir - holds the path to qt android files 29 | * needed to build any Qt application 30 | * on Android. 31 | * 32 | * are defined in gradle.properties file. This file is 33 | * updated by QtCreator and androiddeployqt tools. 34 | * Changing them manually might break the compilation! 35 | *******************************************************/ 36 | 37 | compileSdkVersion androidCompileSdkVersion.toInteger() 38 | 39 | buildToolsVersion androidBuildToolsVersion 40 | 41 | sourceSets { 42 | main { 43 | manifest.srcFile 'AndroidManifest.xml' 44 | java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] 45 | aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] 46 | res.srcDirs = [qt5AndroidDir + '/res', 'res'] 47 | resources.srcDirs = ['src'] 48 | renderscript.srcDirs = ['src'] 49 | assets.srcDirs = ['assets'] 50 | jniLibs.srcDirs = ['libs'] 51 | } 52 | } 53 | 54 | lintOptions { 55 | abortOnError false 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Demo/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Demo/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip 7 | -------------------------------------------------------------------------------- /Demo/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /Demo/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /Demo/android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /Demo/android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /Demo/android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /Demo/android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://download.qt.io/ministro/android/qt5/qt-5.7 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Demo/images/icon/android/feature_graphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/feature_graphic.png -------------------------------------------------------------------------------- /Demo/images/icon/android/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Demo/images/icon/android/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /Demo/images/icon/android/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Demo/images/icon/android/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Demo/images/icon/android/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Demo/images/icon/android/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Demo/images/icon/android/playstore-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/Demo/images/icon/android/playstore-icon.png -------------------------------------------------------------------------------- /Demo/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // Local 6 | #include "src/QMLManager.h" 7 | #include "src/ScreenHelper.h" 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | QGuiApplication app(argc, argv); 12 | 13 | QQmlApplicationEngine engine; 14 | 15 | ScreenHelper screenHelper; 16 | engine.rootContext()->setContextProperty("SH", &screenHelper); 17 | 18 | #if defined(QT_DEBUG) && defined(_WIN32) 19 | QMLManager manager(&engine); 20 | manager.setMainQMLFile("file:///E:/Development/SourceTree/GitHub/QML-Loaders/Demo/qml/main.qml"); 21 | engine.rootContext()->setContextProperty("QM", &manager); 22 | engine.rootContext()->setContextProperty("QML_DEBUG", true); 23 | engine.load(QUrl(QStringLiteral("file:///E:/Development/SourceTree/GitHub/QML-Loaders/Demo/qml/main.qml"))); 24 | #else 25 | engine.rootContext()->setContextProperty("QM", nullptr); 26 | engine.rootContext()->setContextProperty("QML_DEBUG", false); 27 | engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); 28 | #endif // QT_DEBUG 29 | 30 | return app.exec(); 31 | } 32 | -------------------------------------------------------------------------------- /Demo/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qml/main.qml 4 | qml/Loaders/SharinganLoader.qml 5 | qml/Loaders/PulseLoader.qml 6 | qml/Loaders/LineSpinner.qml 7 | qml/Loaders/FishSpinner.qml 8 | qml/Loaders/BlockLoader.qml 9 | qml/Loaders/RectangleLoader.qml 10 | qml/DemoCard.qml 11 | qml/DemoCardList.qml 12 | qml/Loaders/ClockSpinner.qml 13 | 14 | 15 | -------------------------------------------------------------------------------- /Demo/qml/DemoCard.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Rectangle { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property alias title: lbTitle.text 8 | property var loaderComponent: undefined 9 | readonly property bool opened: root.state === "open" 10 | 11 | // ----- Private Properties ----- // 12 | 13 | property int _height: 0 14 | 15 | id: root 16 | radius: SH.dp(7) 17 | clip: true 18 | states: [ 19 | State { 20 | name: "open" 21 | PropertyChanges { target: root; height: root._height + loader.item.height } 22 | PropertyChanges { target: lbTitle; opacity: 0 } 23 | PropertyChanges { target: loader; opacity: 1 } 24 | } 25 | ] 26 | transitions: [ 27 | Transition { 28 | from: "*"; to: "open" 29 | 30 | NumberAnimation { target: root; property: "height"; duration: 300; easing.type: Easing.OutBack } 31 | NumberAnimation { target: loader; property: "opacity"; duration: 300; easing.type: Easing.OutBack } 32 | NumberAnimation { target: lbTitle; property: "opacity"; duration: 300; easing.type: Easing.OutBack } 33 | }, 34 | Transition { 35 | from: "open"; to: "*" 36 | 37 | NumberAnimation { target: root; property: "height"; duration: 300; easing.type: Easing.InBack } 38 | NumberAnimation { target: loader; property: "opacity"; duration: 300; easing.type: Easing.InBack } 39 | NumberAnimation { target: lbTitle; property: "opacity"; duration: 300; easing.type: Easing.InBack } 40 | } 41 | ] 42 | 43 | Component.onCompleted: { 44 | root._height = root.height; 45 | } 46 | 47 | Text { 48 | id: lbTitle 49 | color: "white" 50 | font { 51 | pixelSize: SH.dp(15) 52 | } 53 | anchors { 54 | top: parent.top 55 | left: parent.left 56 | topMargin: SH.dp(10) 57 | leftMargin: SH.dp(10) 58 | } 59 | } 60 | 61 | Loader { 62 | id: loader 63 | anchors.centerIn: parent 64 | opacity: 0 65 | visible: !(opacity === 0) 66 | } 67 | 68 | MouseArea { 69 | anchors.fill: parent 70 | onClicked: { 71 | if (loader.sourceComponent === null) { 72 | loader.sourceComponent = root.loaderComponent; 73 | } 74 | 75 | root.state = root.state === "open" ? "" : "open"; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Demo/qml/DemoCardList.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import "Loaders" 3 | 4 | ListView { 5 | 6 | // ----- Private Properties ----- // 7 | 8 | property var _colors: ["#FF4CA7", "#ED87E7", "#FF716D", "#52CBE5"] 9 | property var _components: [ 10 | {"component": sharinganComponent, "title": "Sharingan Loader"}, 11 | {"component": pulseThree, "title": "Pulse Loader"}, 12 | {"component": pulseFour, "title": "Pulse Loader 4 Bars"}, 13 | {"component": pulseFive, "title": "Pulse Loader 5 Bars"}, 14 | {"component": classicLoader, "title": "Classic Loader"}, 15 | {"component": lineLoader, "title": "Line Loader"}, 16 | {"component": fishSpinner, "title": "Fish Spinner"}, 17 | {"component": fishSpinnerDouble, "title": "Double Fish Spinner"}, 18 | {"component": blockLoader, "title": "Block Loader"}, 19 | {"component": rectLoader, "title": "Rectangle Loader"}, 20 | {"component": clockLoader, "title": "Clock Spinner"} 21 | ] 22 | 23 | id: root 24 | model: _components.length 25 | spacing: SH.dp(10) 26 | delegate: Component { 27 | DemoCard { 28 | width: parent.width 29 | height: SH.dp(60) 30 | title: root._components[index].title 31 | color: root._colors[root.getRandomInt(1, root._colors.length) - 1] 32 | loaderComponent: root._components[index].component 33 | } 34 | } 35 | clip: true 36 | 37 | 38 | // ----- Components ----- // 39 | 40 | Component { 41 | id: sharinganComponent 42 | SharinganLoader { radius: SH.dp(15) } 43 | } 44 | Component { 45 | id: pulseThree 46 | PulseLoader { width: barCount * SH.dp(10); height: SH.dp(30); barCount: 3; spacing: SH.dp(2) } 47 | } 48 | Component { 49 | id: pulseFour 50 | PulseLoader { width: barCount * SH.dp(10); height: SH.dp(30); barCount: 4; spacing: SH.dp(2) } 51 | } 52 | Component { 53 | id: pulseFive 54 | PulseLoader { width: barCount * SH.dp(10); height: SH.dp(30); barCount: 5; spacing: SH.dp(2) } 55 | } 56 | 57 | Component { 58 | id: classicLoader 59 | SharinganLoader { radius: SH.dp(15); useCircle: true } 60 | } 61 | Component { 62 | id: lineLoader 63 | LineSpinner { width: SH.dp(40); height: width; lineThickness: SH.dp(2) } 64 | } 65 | Component { 66 | id: fishSpinner 67 | FishSpinner { radius: SH.dp(25) } 68 | } 69 | Component { 70 | id: fishSpinnerDouble 71 | FishSpinner { radius: SH.dp(25); useDouble: true } 72 | } 73 | 74 | Component { 75 | id: blockLoader 76 | BlockLoader { width: SH.dp(50); height: SH.dp(20) } 77 | } 78 | Component { 79 | id: rectLoader 80 | RectangleLoader { width: SH.dp(50); height: SH.dp(50) } 81 | } 82 | Component { 83 | id: clockLoader 84 | ClockSpinner { width: SH.dp(50); height: SH.dp(50); turnClockwise: false } 85 | } 86 | 87 | // ----- Private Functions ----- // 88 | 89 | /** 90 | * Returns a random integer between min (inclusive) and max (inclusive) 91 | * Using Math.round() will give you a non-uniform distribution! 92 | */ 93 | function getRandomInt(min, max) { 94 | return Math.floor(Math.random() * (max - min + 1)) + min; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/BlockLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | /** 4 | * The design is taken from here: https://dribbble.com/shots/3250272-Animated-Loader-Principle-Freebie 5 | **/ 6 | Item { 7 | 8 | // ----- Public Properties ----- // 9 | 10 | property int spacing: 2 11 | property int horizontalBlockCount: 4 12 | property int verticalBlockCount: 3 13 | 14 | id: root 15 | 16 | Repeater { 17 | id: repeater 18 | model: root.horizontalBlockCount 19 | delegate: Component { 20 | Column { 21 | // ----- Private Properties ----- // 22 | property int _columnIndex: index 23 | 24 | id: column 25 | spacing: root.spacing 26 | x: root._getRectSize().width * index + ((index - 1) * root.spacing) 27 | 28 | Repeater { 29 | // ----- Private Properties ----- // 30 | property alias _columnIndex: column._columnIndex 31 | 32 | id: blockRepeater 33 | model: root.verticalBlockCount 34 | delegate: Component { 35 | Rectangle { 36 | id: rect 37 | width: root._getRectSize().width 38 | height: root._getRectSize().height 39 | radius: 2 40 | smooth: true 41 | transformOrigin: Item.BottomRight 42 | 43 | SequentialAnimation { 44 | id: rotationAnimation 45 | loops: Animation.Infinite 46 | 47 | RotationAnimation { 48 | target: rect 49 | duration: 1000 50 | from: 0 51 | to: 90 52 | easing.type: Easing.InOutQuint 53 | } 54 | 55 | PauseAnimation { duration: blockRepeater._columnIndex * 300 + 300 * blockRepeater._columnIndex } 56 | 57 | RotationAnimation { 58 | target: rect 59 | duration: 1000 60 | from: 90 61 | to: 0 62 | easing.type: Easing.InOutQuint 63 | } 64 | 65 | PauseAnimation { duration: (blockRepeater.model - blockRepeater._columnIndex) * 300 + 300 * (blockRepeater.model - blockRepeater._columnIndex) } 66 | } 67 | 68 | function startAnimation() { 69 | if (rotationAnimation.running === false) { 70 | rotationAnimation.start(); 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | // ----- Public Functions ----- // 78 | 79 | function startAnimation() { 80 | var count = blockRepeater.model; 81 | for (var index = 0; index < count; index++) { 82 | blockRepeater.itemAt(index).startAnimation(); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | Timer { 90 | // ----- Private Properties ----- // 91 | property int _blockIndex: root.horizontalBlockCount - 1 92 | 93 | interval: 300 94 | repeat: true 95 | onTriggered: { 96 | if (_blockIndex === -1) { 97 | stop(); 98 | } 99 | else { 100 | repeater.itemAt(_blockIndex).startAnimation(); 101 | _blockIndex--; 102 | } 103 | } 104 | Component.onCompleted: start() 105 | } 106 | 107 | // ----- Private Functions ----- // 108 | 109 | function _getRectSize() { 110 | var w = root.width / root.horizontalBlockCount; 111 | return Qt.size(w, w); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/ClockSpinner.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int lineThickness: 2 8 | property color color: "white" 9 | property alias running: rotationAnimation.paused 10 | 11 | property bool turnClockwise: true 12 | 13 | id: root 14 | 15 | Rectangle { 16 | id: line 17 | color: root.color 18 | width: root.lineThickness 19 | height: root.width / 2 20 | x: root.width / 2 21 | y: root.height / 2 22 | transformOrigin: Item.Top 23 | rotation: 180 24 | antialiasing: true 25 | } 26 | 27 | Rectangle { 28 | id: hourLine 29 | color: root.color 30 | width: root.lineThickness 31 | height: root.width / 3 32 | x: root.width / 2 33 | y: root.height / 2 34 | transformOrigin: Item.Top 35 | rotation: 180 36 | antialiasing: true 37 | } 38 | 39 | NumberAnimation { 40 | id: rotationAnimation 41 | target: line 42 | property: "rotation" 43 | duration: 500 44 | from: 180 * (root.turnClockwise ? 1 : -1) 45 | to: 540 * (root.turnClockwise ? 1 : -1) 46 | running: true 47 | easing.type: Easing.Linear 48 | loops: Animation.Infinite 49 | } 50 | 51 | NumberAnimation { 52 | id: hourAnimation 53 | target: hourLine 54 | property: "rotation" 55 | duration: 6000 56 | from: 180 * (root.turnClockwise ? 1 : -1) 57 | to: 540 * (root.turnClockwise ? 1 : -1) 58 | running: rotationAnimation.running 59 | paused: rotationAnimation.paused 60 | easing.type: Easing.Linear 61 | loops: Animation.Infinite 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/FishSpinner.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Rectangle { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int radius: 25 8 | property bool useDouble: false 9 | 10 | // ----- Private Properties ----- // 11 | 12 | property int _innerRadius: radius * 0.7 13 | property int _circleRadius: (radius - _innerRadius) * 0.5 14 | 15 | id: root 16 | width: radius * 2 17 | height: radius * 2 18 | color: "transparent" 19 | 20 | Repeater { 21 | id: repeater 22 | model: root.useDouble ? 10 : 4 23 | delegate: Component { 24 | Rectangle { 25 | // ----- Private Properties ----- // 26 | property int _currentAngle: _getStartAngle() 27 | 28 | id: rect 29 | width: _getWidth() 30 | height: width 31 | radius: width 32 | transformOrigin: Item.Center 33 | x: root._getPosOnCircle(_currentAngle).x 34 | y: root._getPosOnCircle(_currentAngle).y 35 | antialiasing: true 36 | 37 | SequentialAnimation { 38 | id: anim 39 | loops: Animation.Infinite 40 | 41 | NumberAnimation { 42 | target: rect 43 | property: "_currentAngle" 44 | duration: root.useDouble ? 1800 : 1000 45 | from: rect._getStartAngle() 46 | to: 360 + rect._getStartAngle() 47 | easing.type: Easing.OutQuad 48 | } 49 | 50 | PauseAnimation { duration: 500 } 51 | } 52 | 53 | // ----- Public Functions ----- // 54 | 55 | function playAnimation() { 56 | if (anim.running == false) { 57 | anim.start(); 58 | } 59 | } 60 | 61 | // ----- Private Functions ----- // 62 | 63 | function _getStartAngle() { 64 | var ang = 90; 65 | if (root.useDouble) { 66 | ang = index < 5 ? 90 : 270; 67 | } 68 | 69 | return ang; 70 | } 71 | 72 | function _getWidth() { 73 | var w = (root._circleRadius) * 0.5 * (repeater.model - index); 74 | if (root.useDouble) { 75 | w = (root._circleRadius) * 0.5 * ((repeater.model / 2) - Math.abs(repeater.model / 2 - index)) 76 | } 77 | 78 | return w; 79 | } 80 | } 81 | } 82 | } 83 | 84 | Timer { 85 | // ----- Private Properties ----- // 86 | property int _circleIndex: 0 87 | 88 | interval: 100 89 | repeat: true 90 | onTriggered: { 91 | var maxIndex = root.useDouble ? repeater.model / 2 : repeater.model; 92 | if (_circleIndex === maxIndex) { 93 | stop(); 94 | } 95 | else { 96 | repeater.itemAt(_circleIndex).playAnimation(); 97 | if (root.useDouble) { 98 | repeater.itemAt(repeater.model - _circleIndex - 1).playAnimation(); 99 | } 100 | 101 | _circleIndex++; 102 | } 103 | } 104 | Component.onCompleted: start() 105 | } 106 | 107 | // ----- Private Functions ----- // 108 | 109 | function _toRadian(degree) { 110 | return (degree * 3.14159265) / 180.0; 111 | } 112 | 113 | function _getPosOnCircle(angleInDegree) { 114 | var centerX = root.width / 2, centerY = root.height / 2; 115 | var posX = 0, posY = 0; 116 | 117 | posX = centerX + root._innerRadius * Math.cos(_toRadian(angleInDegree)); 118 | posY = centerY - root._innerRadius * Math.sin(_toRadian(angleInDegree)); 119 | return Qt.point(posX, posY); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/LineSpinner.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int lineThickness: 2 8 | property alias color: line.color 9 | 10 | id: root 11 | Component.onCompleted: rotationAnimation.start() 12 | 13 | Rectangle { 14 | id: line 15 | width: root.width / 2 16 | height: root.lineThickness 17 | x: root.width / 2 18 | y: root.height / 2 19 | transformOrigin: Item.Left 20 | antialiasing: true 21 | } 22 | 23 | NumberAnimation { 24 | id: rotationAnimation 25 | target: line 26 | property: "rotation" 27 | duration: 1500 28 | from: 0 29 | to: 360 30 | easing.type: Easing.OutExpo 31 | loops: Animation.Infinite 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/PulseLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property alias barCount: repeater.model 8 | property color color: "white" 9 | property int spacing: 5 10 | 11 | id: root 12 | 13 | Repeater { 14 | id: repeater 15 | delegate: Component { 16 | Rectangle { 17 | width: (root.width / root.barCount) - root.spacing 18 | height: root.height 19 | x: index * width + root.spacing * index 20 | transform: Scale { 21 | id: rectScale 22 | origin { 23 | x: width / 2 24 | y: height / 2 25 | } 26 | } 27 | transformOrigin: Item.Center 28 | color: root.color 29 | 30 | SequentialAnimation { 31 | id: anim 32 | loops: Animation.Infinite 33 | 34 | NumberAnimation { target: rectScale; property: "yScale"; from: 1; to: 1.5; duration: 300 } 35 | NumberAnimation { target: rectScale; property: "yScale"; from: 1.5; to: 1; duration: 300 } 36 | PauseAnimation { duration: root.barCount * 150 } 37 | } 38 | 39 | function playAnimation() { 40 | if (anim.running == false) { 41 | anim.start(); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | Timer { 49 | // ----- Private Properties ----- // 50 | property int _barIndex: 0 51 | 52 | interval: 80 53 | repeat: true 54 | onTriggered: { 55 | if (_barIndex === root.barCount) { 56 | stop(); 57 | } 58 | else { 59 | repeater.itemAt(_barIndex).playAnimation(); 60 | _barIndex++; 61 | } 62 | } 63 | Component.onCompleted: start() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/RectangleLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | /** 4 | * Design by Enes Özgör: ens.ninja 5 | **/ 6 | Item { 7 | 8 | // ----- Public Properties ----- // 9 | 10 | property alias color: rect.color 11 | 12 | id: root 13 | 14 | Rectangle { 15 | id: rect 16 | width: root.width / 2 17 | height: root.height / 2 18 | transformOrigin: Item.BottomRight 19 | x: 0 20 | y: 0 21 | transform: Scale { 22 | id: transformScale 23 | origin { 24 | x: rect.width 25 | y: rect.height 26 | } 27 | } 28 | 29 | SequentialAnimation { 30 | running: true 31 | loops: Animation.Infinite 32 | 33 | // Top right 34 | ParallelAnimation { 35 | NumberAnimation { 36 | target: transformScale; property: "xScale"; from: 1; to: -1; duration: 500; easing.type: Easing.OutQuint 37 | } 38 | 39 | SequentialAnimation { 40 | NumberAnimation { 41 | target: transformScale; property: "yScale"; from: 1; to: 1.4; duration: 250; easing.type: Easing.OutQuart 42 | } 43 | 44 | NumberAnimation { 45 | target: transformScale; property: "yScale"; from: 1.4; to: 1; duration: 250; easing.type: Easing.OutQuart 46 | } 47 | } 48 | } 49 | 50 | // Bottom right 51 | ParallelAnimation { 52 | NumberAnimation { 53 | target: transformScale; property: "yScale"; from: 1; to: -1; duration: 500; easing.type: Easing.OutQuint 54 | } 55 | 56 | SequentialAnimation { 57 | NumberAnimation { 58 | target: transformScale; property: "xScale"; from: -1; to: -1.4; duration: 250; easing.type: Easing.OutQuart 59 | } 60 | 61 | NumberAnimation { 62 | target: transformScale; property: "xScale"; from: -1.4; to: -1; duration: 250; easing.type: Easing.OutQuart 63 | } 64 | } 65 | } 66 | 67 | // Bottom left 68 | ParallelAnimation { 69 | NumberAnimation { 70 | target: transformScale; property: "xScale"; from: -1; to: 1; duration: 500; easing.type: Easing.OutQuint 71 | } 72 | 73 | SequentialAnimation { 74 | NumberAnimation { 75 | target: transformScale; property: "yScale"; from: -1; to: -1.4; duration: 250; easing.type: Easing.OutQuart 76 | } 77 | 78 | NumberAnimation { 79 | target: transformScale; property: "yScale"; from: -1.4; to: -1; duration: 250; easing.type: Easing.OutQuart 80 | } 81 | } 82 | } 83 | 84 | // Top left 85 | ParallelAnimation { 86 | NumberAnimation { 87 | target: transformScale; property: "yScale"; from: -1; to: 1; duration: 500; easing.type: Easing.OutQuint 88 | } 89 | 90 | SequentialAnimation { 91 | NumberAnimation { 92 | target: transformScale; property: "xScale"; from: 1; to: 1.4; duration: 250; easing.type: Easing.OutQuart 93 | } 94 | 95 | NumberAnimation { 96 | target: transformScale; property: "xScale"; from: 1.4; to: 1; duration: 250; easing.type: Easing.OutQuart 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Demo/qml/Loaders/SharinganLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int radius: 25 8 | property color color: "#FAFAFA" 9 | property bool useCircle: false 10 | 11 | // ----- Private Properties ----- // 12 | 13 | property int _innerRadius: radius * 0.7 14 | property int _currentIndex: 0 15 | 16 | id: root 17 | width: radius * 2 18 | height: radius * 2 19 | Component.onCompleted: timer.start() 20 | 21 | Repeater { 22 | id: repeater 23 | model: 8 24 | delegate: Component { 25 | Rectangle { 26 | // ----- Private Properties ----- // 27 | property int _rotation: (360 / repeater.model) * index 28 | property int _maxIndex: root._currentIndex + 1 29 | property int _minIndex: root._currentIndex - 1 30 | 31 | width: root.useCircle ? (root.radius - root._innerRadius) * 2 : root.width - (root._innerRadius * 2) 32 | height: root.useCircle ? width : width * 0.5 33 | x: _getPosOnCircle(_rotation).x 34 | y: _getPosOnCircle(_rotation).y 35 | radius: root.useCircle ? width : 0 36 | color: root.color 37 | opacity: (index >= _minIndex && index <= _maxIndex) || (index === 0 && root._currentIndex + 1 > 7) ? 1 : 0.3 38 | transform: Rotation { 39 | angle: 360 - _rotation 40 | origin { 41 | x: 0 42 | y: height / 2 43 | } 44 | } 45 | transformOrigin: index >= repeater.model / 2 ? Item.Center : Item.Center 46 | 47 | Behavior on opacity { NumberAnimation { duration: 200 } } 48 | } 49 | } 50 | } 51 | 52 | Timer { 53 | id: timer 54 | interval: 80 55 | repeat: true 56 | onTriggered: { 57 | if (root._currentIndex === 7) { 58 | root._currentIndex = 0; 59 | } 60 | else { 61 | root._currentIndex++; 62 | } 63 | } 64 | } 65 | 66 | // ----- Private Functions ----- // 67 | 68 | function _toRadian(degree) { 69 | return (degree * 3.14159265) / 180.0; 70 | } 71 | 72 | function _getPosOnCircle(angleInDegree) { 73 | var centerX = root.width / 2, centerY = root.height / 2; 74 | var posX = 0, posY = 0; 75 | 76 | posX = centerX + root._innerRadius * Math.cos(_toRadian(angleInDegree)); 77 | posY = centerY - root._innerRadius * Math.sin(_toRadian(angleInDegree)); 78 | return Qt.point(posX, posY); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Demo/qml/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Window 2.2 3 | 4 | Window { 5 | id: mainWindow 6 | visible: true 7 | width: 320 8 | height: 480 9 | title: qsTr("QML Loaders Demo") 10 | color: "#FDFAFB" 11 | Component.onCompleted: { 12 | if (QML_DEBUG) { 13 | QM.setWindow(mainWindow) 14 | } 15 | } 16 | 17 | Text { 18 | text: "Refresh" 19 | anchors { 20 | left: parent.left 21 | top: parent.top 22 | } 23 | font.pointSize: 13 24 | visible: QML_DEBUG 25 | 26 | MouseArea { 27 | anchors.fill: parent 28 | onClicked: { 29 | QM.reload(); 30 | } 31 | } 32 | } 33 | 34 | DemoCardList { 35 | anchors { 36 | fill: parent 37 | margins: SH.dp(25) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Demo/src/QMLManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | // STD 8 | #include 9 | 10 | /** 11 | * @brief The QMLManager is a helper class to reload QML on runtime. To use it, pass the QQmlApplicationEngine pointer and call the reload function when you need. 12 | * For more information about runtime reloading go here -> http://www.slideshare.net/ICSinc/how-best-to-realize-a-runtime-reload-of-qml 13 | * @code 14 | * // in main.cpp 15 | * QMLManager manager(&engine); 16 | * manager.setMainQMLFile("file:///E:/Development/Playground/Live-QML/qml/main.qml"); 17 | * engine.rootContext()->setContextProperty("QM", &manager); 18 | * @endcode 19 | * 20 | * Pass the `QQuickWindow` to `QMLManager`, then use QM.relad() to reload at runtime! 21 | * @code 22 | * Window { 23 | * id: mainWindow 24 | * Component.onCompleted: QM.setWindow(mainWindow) 25 | * 26 | * MouseArea { 27 | * anchors.fill: parent 28 | * onClicked: { 29 | * QM.reload(); 30 | * } 31 | * } 32 | * } 33 | * @endcode 34 | */ 35 | class QMLManager : public QObject 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | explicit QMLManager(QQmlApplicationEngine *engine, QObject *parent = 0) 41 | : QObject(parent) 42 | , m_Engine(engine) 43 | , m_Window(nullptr) 44 | { 45 | 46 | } 47 | 48 | Q_INVOKABLE void reload(float delay = 0.f) 49 | { 50 | if (delay == 0.f) { 51 | reloadCache(); 52 | } 53 | else { 54 | QTimer::singleShot(delay * 1000, this, &QMLManager::reloadCache); 55 | } 56 | } 57 | 58 | Q_INVOKABLE void setWindow(QQuickWindow *window) 59 | { 60 | m_Window = window; 61 | } 62 | 63 | Q_INVOKABLE QString MainQMLFile() const 64 | { 65 | return m_MainQMLFile; 66 | } 67 | 68 | Q_INVOKABLE void setMainQMLFile(const QString &file) 69 | { 70 | m_MainQMLFile = file; 71 | } 72 | 73 | private: 74 | QQmlApplicationEngine *m_Engine; 75 | QQuickWindow *m_Window; 76 | QString m_MainQMLFile; 77 | 78 | private: 79 | void reloadCache() 80 | { 81 | if (m_MainQMLFile.length() == 0) { 82 | qDebug() << "m_MainQMLFile is empty."; 83 | return; 84 | } 85 | 86 | if (m_Window) { 87 | m_Window->close(); 88 | } 89 | 90 | m_Engine->clearComponentCache(); 91 | m_Engine->load(QUrl(m_MainQMLFile)); 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /Demo/src/ScreenHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "ScreenHelper.h" 2 | // Qt 3 | #include 4 | #include 5 | 6 | ScreenHelper::ScreenHelper(QObject *parent) 7 | : QObject(parent) 8 | , m_DPI(QGuiApplication::primaryScreen()->physicalDotsPerInch()) 9 | { 10 | 11 | } 12 | 13 | qreal ScreenHelper::dp(const qreal &size) 14 | { 15 | #ifdef _WIN32 16 | return qRound(size * (m_DPI / 90.0)); 17 | #else 18 | return qRound(size * (m_DPI / 160.0)); 19 | #endif // _WIN32 20 | } 21 | -------------------------------------------------------------------------------- /Demo/src/ScreenHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class ScreenHelper : public QObject 5 | { 6 | Q_OBJECT 7 | 8 | public: 9 | explicit ScreenHelper(QObject *parent = 0); 10 | 11 | Q_INVOKABLE qreal dp(const qreal &size); 12 | 13 | private: 14 | const qreal m_DPI; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /Loaders/BlockLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | /** 4 | * The design is taken from here: https://dribbble.com/shots/3250272-Animated-Loader-Principle-Freebie 5 | **/ 6 | Item { 7 | 8 | // ----- Public Properties ----- // 9 | 10 | property int spacing: 2 11 | property int horizontalBlockCount: 4 12 | property int verticalBlockCount: 3 13 | 14 | id: root 15 | 16 | Repeater { 17 | id: repeater 18 | model: root.horizontalBlockCount 19 | delegate: Component { 20 | Column { 21 | // ----- Private Properties ----- // 22 | property int _columnIndex: index 23 | 24 | id: column 25 | spacing: root.spacing 26 | x: root._getRectSize().width * index + ((index - 1) * root.spacing) 27 | 28 | Repeater { 29 | // ----- Private Properties ----- // 30 | property alias _columnIndex: column._columnIndex 31 | 32 | id: blockRepeater 33 | model: root.verticalBlockCount 34 | delegate: Component { 35 | Rectangle { 36 | id: rect 37 | width: root._getRectSize().width 38 | height: root._getRectSize().height 39 | radius: 2 40 | smooth: true 41 | transformOrigin: Item.BottomRight 42 | 43 | SequentialAnimation { 44 | id: rotationAnimation 45 | loops: Animation.Infinite 46 | 47 | RotationAnimation { 48 | target: rect 49 | duration: 1000 50 | from: 0 51 | to: 90 52 | easing.type: Easing.InOutQuint 53 | } 54 | 55 | PauseAnimation { duration: blockRepeater._columnIndex * 300 + 300 * blockRepeater._columnIndex } 56 | 57 | RotationAnimation { 58 | target: rect 59 | duration: 1000 60 | from: 90 61 | to: 0 62 | easing.type: Easing.InOutQuint 63 | } 64 | 65 | PauseAnimation { duration: (blockRepeater.model - blockRepeater._columnIndex) * 300 + 300 * (blockRepeater.model - blockRepeater._columnIndex) } 66 | } 67 | 68 | function startAnimation() { 69 | if (rotationAnimation.running === false) { 70 | rotationAnimation.start(); 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | // ----- Public Functions ----- // 78 | 79 | function startAnimation() { 80 | var count = blockRepeater.model; 81 | for (var index = 0; index < count; index++) { 82 | blockRepeater.itemAt(index).startAnimation(); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | Timer { 90 | // ----- Private Properties ----- // 91 | property int _blockIndex: root.horizontalBlockCount - 1 92 | 93 | interval: 300 94 | repeat: true 95 | onTriggered: { 96 | if (_blockIndex === -1) { 97 | stop(); 98 | } 99 | else { 100 | repeater.itemAt(_blockIndex).startAnimation(); 101 | _blockIndex--; 102 | } 103 | } 104 | Component.onCompleted: start() 105 | } 106 | 107 | // ----- Private Functions ----- // 108 | 109 | function _getRectSize() { 110 | var w = root.width / root.horizontalBlockCount; 111 | return Qt.size(w, w); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Loaders/ClockSpinner.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int lineThickness: 2 8 | property color color: "white" 9 | property alias running: rotationAnimation.paused 10 | 11 | property bool turnClockwise: true 12 | 13 | id: root 14 | 15 | Rectangle { 16 | id: line 17 | color: root.color 18 | width: root.lineThickness 19 | height: root.width / 2 20 | x: root.width / 2 21 | y: root.height / 2 22 | transformOrigin: Item.Top 23 | rotation: 180 24 | antialiasing: true 25 | } 26 | 27 | Rectangle { 28 | id: hourLine 29 | color: root.color 30 | width: root.lineThickness 31 | height: root.width / 3 32 | x: root.width / 2 33 | y: root.height / 2 34 | transformOrigin: Item.Top 35 | rotation: 180 36 | antialiasing: true 37 | } 38 | 39 | NumberAnimation { 40 | id: rotationAnimation 41 | target: line 42 | property: "rotation" 43 | duration: 500 44 | from: 180 * (root.turnClockwise ? 1 : -1) 45 | to: 540 * (root.turnClockwise ? 1 : -1) 46 | running: true 47 | easing.type: Easing.Linear 48 | loops: Animation.Infinite 49 | } 50 | 51 | NumberAnimation { 52 | id: hourAnimation 53 | target: hourLine 54 | property: "rotation" 55 | duration: 6000 56 | from: 180 * (root.turnClockwise ? 1 : -1) 57 | to: 540 * (root.turnClockwise ? 1 : -1) 58 | running: rotationAnimation.running 59 | paused: rotationAnimation.paused 60 | easing.type: Easing.Linear 61 | loops: Animation.Infinite 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Loaders/FishSpinner.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int radius: 25 8 | property bool useDouble: false 9 | property bool running: true 10 | 11 | property color color: "white" 12 | 13 | // ----- Private Properties ----- // 14 | 15 | property int _innerRadius: radius * 0.7 16 | property int _circleRadius: (radius - _innerRadius) * 0.5 17 | 18 | id: root 19 | width: radius * 2 20 | height: radius * 2 21 | onRunningChanged: { 22 | if (running === false) { 23 | for (var i = 0; i < repeater.model; i++) { 24 | if (repeater.itemAt(i)) { 25 | repeater.itemAt(i).stopAnimation(); 26 | } 27 | } 28 | } 29 | else { 30 | for (var i = 0; i < repeater.model; i++) { 31 | if (repeater.itemAt(i)) { 32 | repeater.itemAt(i).playAnimation(); 33 | } 34 | } 35 | } 36 | } 37 | 38 | Repeater { 39 | id: repeater 40 | model: root.useDouble ? 10 : 4 41 | delegate: Component { 42 | Rectangle { 43 | // ----- Private Properties ----- // 44 | property int _currentAngle: _getStartAngle() 45 | 46 | id: rect 47 | width: _getWidth() 48 | height: width 49 | radius: width 50 | color: root.color 51 | transformOrigin: Item.Center 52 | x: root._getPosOnCircle(_currentAngle).x 53 | y: root._getPosOnCircle(_currentAngle).y 54 | antialiasing: true 55 | 56 | SequentialAnimation { 57 | id: anim 58 | loops: Animation.Infinite 59 | 60 | NumberAnimation { 61 | target: rect 62 | property: "_currentAngle" 63 | duration: root.useDouble ? 1800 : 1000 64 | from: rect._getStartAngle() 65 | to: 360 + rect._getStartAngle() 66 | easing.type: Easing.OutQuad 67 | } 68 | 69 | PauseAnimation { duration: 500 } 70 | } 71 | 72 | // ----- Public Functions ----- // 73 | 74 | function playAnimation() { 75 | if (anim.running == false) { 76 | anim.start(); 77 | } 78 | else if (anim.paused) { 79 | anim.resume(); 80 | } 81 | } 82 | 83 | function stopAnimation() { 84 | if (anim.running) { 85 | anim.pause(); 86 | } 87 | } 88 | 89 | // ----- Private Functions ----- // 90 | 91 | function _getStartAngle() { 92 | var ang = 90; 93 | if (root.useDouble) { 94 | ang = index < 5 ? 90 : 270; 95 | } 96 | 97 | return ang; 98 | } 99 | 100 | function _getWidth() { 101 | var w = (root._circleRadius) * 0.5 * (repeater.model - index); 102 | if (root.useDouble) { 103 | w = (root._circleRadius) * 0.5 * ((repeater.model / 2) - Math.abs(repeater.model / 2 - index)) 104 | } 105 | 106 | return w; 107 | } 108 | } 109 | } 110 | } 111 | 112 | Timer { 113 | // ----- Private Properties ----- // 114 | property int _circleIndex: 0 115 | 116 | id: timer 117 | interval: 100 118 | repeat: true 119 | running: true 120 | onTriggered: { 121 | var maxIndex = root.useDouble ? repeater.model / 2 : repeater.model; 122 | if (_circleIndex === maxIndex) { 123 | stop(); 124 | _circleIndex = 0; 125 | } 126 | else { 127 | repeater.itemAt(_circleIndex).playAnimation(); 128 | if (root.useDouble) { 129 | repeater.itemAt(repeater.model - _circleIndex - 1).playAnimation(); 130 | } 131 | 132 | _circleIndex++; 133 | } 134 | } 135 | } 136 | 137 | // ----- Private Functions ----- // 138 | 139 | function _toRadian(degree) { 140 | return (degree * 3.14159265) / 180.0; 141 | } 142 | 143 | function _getPosOnCircle(angleInDegree) { 144 | var centerX = root.width / 2, centerY = root.height / 2; 145 | var posX = 0, posY = 0; 146 | 147 | posX = centerX + root._innerRadius * Math.cos(_toRadian(angleInDegree)); 148 | posY = centerY - root._innerRadius * Math.sin(_toRadian(angleInDegree)); 149 | return Qt.point(posX, posY); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Loaders/LineSpinner.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int lineThickness: 2 8 | property alias color: line.color 9 | 10 | id: root 11 | Component.onCompleted: rotationAnimation.start() 12 | 13 | Rectangle { 14 | id: line 15 | width: root.width / 2 16 | height: root.lineThickness 17 | x: root.width / 2 18 | y: root.height / 2 19 | transformOrigin: Item.Left 20 | antialiasing: true 21 | } 22 | 23 | NumberAnimation { 24 | id: rotationAnimation 25 | target: line 26 | property: "rotation" 27 | duration: 1500 28 | from: 0 29 | to: 360 30 | easing.type: Easing.OutExpo 31 | loops: Animation.Infinite 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Loaders/PulseLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property alias barCount: repeater.model 8 | property color color: "white" 9 | property int spacing: 5 10 | 11 | property bool running: true 12 | 13 | id: root 14 | onRunningChanged: { 15 | if (barCount !== repeater.count || timer._barIndex <= barCount - 1) { 16 | return; 17 | } 18 | 19 | for (var barIndex = 0; barIndex < barCount; barIndex++) { 20 | if (running) { 21 | if (repeater.itemAt(barIndex)) { 22 | repeater.itemAt(barIndex).playAnimation(); 23 | } 24 | } 25 | else { 26 | if (repeater.itemAt(barIndex)) { 27 | repeater.itemAt(barIndex).pauseAnimation(); 28 | } 29 | } 30 | } 31 | } 32 | 33 | Repeater { 34 | id: repeater 35 | delegate: Component { 36 | Rectangle { 37 | width: (root.width / root.barCount) - root.spacing 38 | height: root.height 39 | x: index * width + root.spacing * index 40 | transform: Scale { 41 | id: rectScale 42 | origin { 43 | x: width / 2 44 | y: height / 2 45 | } 46 | } 47 | transformOrigin: Item.Center 48 | color: root.color 49 | 50 | SequentialAnimation { 51 | id: anim 52 | loops: Animation.Infinite 53 | 54 | NumberAnimation { target: rectScale; property: "yScale"; from: 1; to: 1.5; duration: 300 } 55 | NumberAnimation { target: rectScale; property: "yScale"; from: 1.5; to: 1; duration: 300 } 56 | PauseAnimation { duration: root.barCount * 150 } 57 | } 58 | 59 | function playAnimation() { 60 | if (anim.running == false) { 61 | anim.running = true; 62 | } 63 | 64 | if (anim.paused) { 65 | anim.paused = false; 66 | } 67 | } 68 | 69 | function pauseAnimation() { 70 | if (anim.running) { 71 | anim.paused = true; 72 | } 73 | } 74 | } 75 | } 76 | } 77 | 78 | Timer { 79 | // ----- Private Properties ----- // 80 | property int _barIndex: 0 81 | 82 | id: timer 83 | interval: 80 84 | repeat: true 85 | onTriggered: { 86 | if (_barIndex === root.barCount) { 87 | stop(); 88 | } 89 | else { 90 | repeater.itemAt(_barIndex).playAnimation(); 91 | if (root.running === false) { 92 | repeater.itemAt(_barIndex).pauseAnimation(); 93 | } 94 | 95 | _barIndex++; 96 | } 97 | } 98 | Component.onCompleted: start() 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Loaders/RectangleLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | /** 4 | * Design by Enes Özgör: ens.ninja 5 | **/ 6 | Item { 7 | 8 | // ----- Public Properties ----- // 9 | 10 | property alias color: rect.color 11 | 12 | id: root 13 | 14 | Rectangle { 15 | id: rect 16 | width: root.width / 2 17 | height: root.height / 2 18 | transformOrigin: Item.BottomRight 19 | x: 0 20 | y: 0 21 | transform: Scale { 22 | id: transformScale 23 | origin { 24 | x: rect.width 25 | y: rect.height 26 | } 27 | } 28 | 29 | SequentialAnimation { 30 | running: true 31 | loops: Animation.Infinite 32 | 33 | // Top right 34 | ParallelAnimation { 35 | NumberAnimation { 36 | target: transformScale; property: "xScale"; from: 1; to: -1; duration: 500; easing.type: Easing.OutQuint 37 | } 38 | 39 | SequentialAnimation { 40 | NumberAnimation { 41 | target: transformScale; property: "yScale"; from: 1; to: 1.4; duration: 250; easing.type: Easing.OutQuart 42 | } 43 | 44 | NumberAnimation { 45 | target: transformScale; property: "yScale"; from: 1.4; to: 1; duration: 250; easing.type: Easing.OutQuart 46 | } 47 | } 48 | } 49 | 50 | // Bottom right 51 | ParallelAnimation { 52 | NumberAnimation { 53 | target: transformScale; property: "yScale"; from: 1; to: -1; duration: 500; easing.type: Easing.OutQuint 54 | } 55 | 56 | SequentialAnimation { 57 | NumberAnimation { 58 | target: transformScale; property: "xScale"; from: -1; to: -1.4; duration: 250; easing.type: Easing.OutQuart 59 | } 60 | 61 | NumberAnimation { 62 | target: transformScale; property: "xScale"; from: -1.4; to: -1; duration: 250; easing.type: Easing.OutQuart 63 | } 64 | } 65 | } 66 | 67 | // Bottom left 68 | ParallelAnimation { 69 | NumberAnimation { 70 | target: transformScale; property: "xScale"; from: -1; to: 1; duration: 500; easing.type: Easing.OutQuint 71 | } 72 | 73 | SequentialAnimation { 74 | NumberAnimation { 75 | target: transformScale; property: "yScale"; from: -1; to: -1.4; duration: 250; easing.type: Easing.OutQuart 76 | } 77 | 78 | NumberAnimation { 79 | target: transformScale; property: "yScale"; from: -1.4; to: -1; duration: 250; easing.type: Easing.OutQuart 80 | } 81 | } 82 | } 83 | 84 | // Top left 85 | ParallelAnimation { 86 | NumberAnimation { 87 | target: transformScale; property: "yScale"; from: -1; to: 1; duration: 500; easing.type: Easing.OutQuint 88 | } 89 | 90 | SequentialAnimation { 91 | NumberAnimation { 92 | target: transformScale; property: "xScale"; from: 1; to: 1.4; duration: 250; easing.type: Easing.OutQuart 93 | } 94 | 95 | NumberAnimation { 96 | target: transformScale; property: "xScale"; from: 1.4; to: 1; duration: 250; easing.type: Easing.OutQuart 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Loaders/SharinganLoader.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | 5 | // ----- Public Properties ----- // 6 | 7 | property int radius: 25 8 | property color color: "#FAFAFA" 9 | property bool useCircle: false 10 | 11 | property alias running: timer.running 12 | 13 | // ----- Private Properties ----- // 14 | 15 | property int _innerRadius: radius * 0.7 16 | property int _currentIndex: 0 17 | 18 | id: root 19 | width: radius * 2 20 | height: radius * 2 21 | 22 | Repeater { 23 | id: repeater 24 | model: 8 25 | delegate: Component { 26 | Rectangle { 27 | // ----- Private Properties ----- // 28 | property int _rotation: (360 / repeater.model) * index 29 | property int _maxIndex: root._currentIndex + 1 30 | property int _minIndex: root._currentIndex - 1 31 | 32 | width: root.useCircle ? (root.radius - root._innerRadius) * 2 : root.width - (root._innerRadius * 2) 33 | height: root.useCircle ? width : width * 0.5 34 | x: _getPosOnCircle(_rotation).x 35 | y: _getPosOnCircle(_rotation).y 36 | radius: root.useCircle ? width : 0 37 | color: root.color 38 | opacity: (index >= _minIndex && index <= _maxIndex) || (index === 0 && root._currentIndex + 1 > 7) ? 1 : 0.3 39 | transform: Rotation { 40 | angle: 360 - _rotation 41 | origin { 42 | x: 0 43 | y: height / 2 44 | } 45 | } 46 | transformOrigin: index >= repeater.model / 2 ? Item.Center : Item.Center 47 | 48 | Behavior on opacity { NumberAnimation { duration: 200 } } 49 | } 50 | } 51 | } 52 | 53 | Timer { 54 | id: timer 55 | interval: 80 56 | repeat: true 57 | running: true 58 | onTriggered: { 59 | if (root._currentIndex === 7) { 60 | root._currentIndex = 0; 61 | } 62 | else { 63 | root._currentIndex++; 64 | } 65 | } 66 | } 67 | 68 | // ----- Private Functions ----- // 69 | 70 | function _toRadian(degree) { 71 | return (degree * 3.14159265) / 180.0; 72 | } 73 | 74 | function _getPosOnCircle(angleInDegree) { 75 | var centerX = root.width / 2, centerY = root.height / 2; 76 | var posX = 0, posY = 0; 77 | 78 | posX = centerX + root._innerRadius * Math.cos(_toRadian(angleInDegree)); 79 | posY = centerY - root._innerRadius * Math.sin(_toRadian(angleInDegree)); 80 | return Qt.point(posX, posY); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QML-Loaders 2 | 3 | Beautiful and smooth loading indicator implementations in QML. 4 | Many of the designs were taken from [here](https://github.com/nntuyen/mkloader). 5 | There are/will be also other designs taken from various places. 6 | 7 | ![image](demo.gif) 8 | 9 | # Supported Types 10 | 11 | - Sharingan 12 | - BlockLoader 13 | - FishSpinner 14 | - DoubleFishSpiner 15 | - PulseLoader 16 | - LineSpinner 17 | - RectangleLoader (Concept by [Enes Özgör](https://github.com/enszgr)) 18 | - ClockSpinner (Implementation by [@majidkamali1370](https://github.com/majidkamali1370)) 19 | 20 | # Demo 21 | 22 | You can find the demo app [here](https://play.google.com/store/apps/details?id=org.zmc.qml_loading). 23 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Furkanzmc/QML-Loaders/08cb9e0d8a8c4c73aa79c82158a7649c4efb3a4e/demo.gif --------------------------------------------------------------------------------