├── .gitignore ├── .idea └── runConfigurations │ └── main_dart.xml ├── .metadata ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── mono0926 │ │ │ │ └── animations │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── apple_lock.flr ├── love.png └── love_gray.png ├── deploy_web.sh ├── docs ├── .last_build_id ├── assets │ ├── AssetManifest.json │ ├── FontManifest.json │ ├── NOTICES │ ├── assets │ │ ├── apple_lock.flr │ │ ├── love.png │ │ └── love_gray.png │ ├── fonts │ │ ├── MaterialIcons-Regular.otf │ │ └── NothingYouCouldDo.ttf │ └── packages │ │ └── cupertino_icons │ │ └── assets │ │ └── CupertinoIcons.ttf ├── favicon.png ├── flutter_service_worker.js ├── icons │ ├── Icon-192.png │ └── Icon-512.png ├── index.html ├── main.dart.js ├── manifest.json └── version.json ├── firebase ├── .firebaserc ├── .gitignore └── firebase.json ├── fonts └── NothingYouCouldDo.ttf ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── flutter_export_environment.sh ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── app.dart ├── main.dart ├── pages │ ├── custom │ │ ├── animated_builder_page.dart │ │ ├── animated_switcher_page.dart │ │ ├── animated_widget_page.dart │ │ ├── animation_controller_set_state_enhanced2_page.dart │ │ ├── animation_controller_set_state_enhanced_page.dart │ │ ├── animation_controller_set_state_page.dart │ │ ├── custom_page.dart │ │ ├── implicitly_animated_widget_page.dart │ │ ├── tween_animation_builder_page.dart │ │ └── widget │ │ │ ├── ghost_fade_tween.dart │ │ │ └── switch_string_tween.dart │ ├── flare │ │ ├── apple_lock_page.dart │ │ └── flare_page.dart │ ├── flight_search │ │ ├── README.md │ │ ├── air_asia_bar.dart │ │ ├── animated_dot.dart │ │ ├── animated_plane_icon.dart │ │ ├── content_card.dart │ │ ├── fade_route.dart │ │ ├── flight_search_page.dart │ │ ├── flight_stop.dart │ │ ├── flight_stop_card.dart │ │ ├── flight_stop_ticker.dart │ │ ├── multicity_input.dart │ │ ├── price_tab.dart │ │ ├── rounded_button.dart │ │ ├── ticker_page.dart │ │ └── ticket_card.dart │ ├── home │ │ └── home_page.dart │ ├── implicitly_animated │ │ ├── animated_align.dart │ │ ├── animated_container.dart │ │ ├── animated_cross_fade.dart │ │ ├── animated_default_text_style.dart │ │ ├── animated_icon.dart │ │ ├── animated_list.dart │ │ ├── animated_modal_barrier.dart │ │ ├── animated_opacity.dart │ │ ├── animated_padding.dart │ │ ├── animated_physical_model.dart │ │ ├── animated_positioned.dart │ │ ├── animated_positioned_directional.dart │ │ ├── animated_size_page.dart │ │ ├── animated_switcher_page.dart │ │ ├── animated_theme_page.dart │ │ ├── fade_in_image_page.dart │ │ ├── hero_page.dart │ │ └── implicitly_animated_page.dart │ └── transition │ │ ├── align_transition_page.dart │ │ ├── decorated_box_transition_page.dart │ │ ├── default_text_style_transition_page.dart │ │ ├── fade_transition_page.dart │ │ ├── positioned_transition_page.dart │ │ ├── relative_positioned_transition_page.dart │ │ ├── rotation_transition_page.dart │ │ ├── scale_transition_page.dart │ │ ├── size_transition_page.dart │ │ ├── slide_transition_page.dart │ │ └── transition_page.dart ├── util │ ├── logger.dart │ └── util.dart └── widget │ ├── animation_object.dart │ ├── app_list_tile.dart │ ├── app_scaffold.dart │ └── widget.dart ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app_icon_1024.png │ │ ├── app_icon_128.png │ │ ├── app_icon_16.png │ │ ├── app_icon_256.png │ │ ├── app_icon_32.png │ │ ├── app_icon_512.png │ │ └── app_icon_64.png │ ├── Base.lproj │ └── MainMenu.xib │ ├── Configs │ ├── AppInfo.xcconfig │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── res └── values │ └── strings_en.arb ├── test └── widget_test.dart └── web ├── favicon.png ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/* 17 | !.idea/runConfigurations/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Web related 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 45 | 46 | vendor/ 47 | 48 | **/fastlane/report.xml 49 | -------------------------------------------------------------------------------- /.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Masayuki Ono 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Animation Example 2 | 3 | - [x] Implicitly Animated Widgets (Inherited form [ImplicitlyAnimatedWidget](https://docs.flutter.io/flutter/widgets/ImplicitlyAnimatedWidget-class.html)) 4 | - [x] Transition Widgets 5 | - [x] Explicit Widgets 6 | - [AnimatedWidget](https://docs.flutter.io/flutter/widgets/AnimatedWidget-class.html) 7 | - [AnimatedBuilder](https://docs.flutter.io/flutter/widgets/AnimatedBuilder-class.html) 8 | - [ImplicitlyAnimatedWidget](https://docs.flutter.io/flutter/widgets/ImplicitlyAnimatedWidget-class.html) 9 | 10 | 11 | ## Articles 12 | 13 | - [Flutter のお手軽にアニメーションを扱える Animated 系 Widget をすべて紹介](https://medium.com/flutter-jp/implicit-animation-b9d4b7358c28) 14 | - [FlutterのTransition系アニメーションWidgetをすべて紹介](https://medium.com/flutter-jp/implicit-animation-b9d4b7358c28) 15 | - [“The Boring Flutter Development Show” で取り上げられたアニメーションを様々な方法で書きながら解説](https://medium.com/flutter-jp/custom-animation-c87e9d55b03b) 16 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # https://pub.dev/packages/pedantic_mono 2 | include: package:pedantic_mono/analysis_options.yaml 3 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.mono0926.animations" 47 | minSdkVersion 16 48 | targetSdkVersion 30 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/mono0926/animations/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mono0926.animations 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/apple_lock.flr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/assets/apple_lock.flr -------------------------------------------------------------------------------- /assets/love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/assets/love.png -------------------------------------------------------------------------------- /assets/love_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/assets/love_gray.png -------------------------------------------------------------------------------- /deploy_web.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | flutter build web 4 | rm -rf firebase/public/animation 5 | mv build/web firebase/public/animation 6 | cd firebase 7 | firebase deploy --only hosting:animation 8 | -------------------------------------------------------------------------------- /docs/.last_build_id: -------------------------------------------------------------------------------- 1 | 75db79b7f0256732a78385f710902af9 -------------------------------------------------------------------------------- /docs/assets/AssetManifest.json: -------------------------------------------------------------------------------- 1 | {"assets/apple_lock.flr":["assets/apple_lock.flr"],"assets/love.png":["assets/love.png"],"assets/love_gray.png":["assets/love_gray.png"],"fonts/NothingYouCouldDo.ttf":["fonts/NothingYouCouldDo.ttf"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"]} -------------------------------------------------------------------------------- /docs/assets/FontManifest.json: -------------------------------------------------------------------------------- 1 | [{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]},{"family":"NothingYouCouldDo","fonts":[{"asset":"fonts/NothingYouCouldDo.ttf"}]},{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}] -------------------------------------------------------------------------------- /docs/assets/assets/apple_lock.flr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/assets/assets/apple_lock.flr -------------------------------------------------------------------------------- /docs/assets/assets/love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/assets/assets/love.png -------------------------------------------------------------------------------- /docs/assets/assets/love_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/assets/assets/love_gray.png -------------------------------------------------------------------------------- /docs/assets/fonts/MaterialIcons-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/assets/fonts/MaterialIcons-Regular.otf -------------------------------------------------------------------------------- /docs/assets/fonts/NothingYouCouldDo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/assets/fonts/NothingYouCouldDo.ttf -------------------------------------------------------------------------------- /docs/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/favicon.png -------------------------------------------------------------------------------- /docs/flutter_service_worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const MANIFEST = 'flutter-app-manifest'; 3 | const TEMP = 'flutter-temp-cache'; 4 | const CACHE_NAME = 'flutter-app-cache'; 5 | const RESOURCES = { 6 | "version.json": "f2a7be411659caece6901acd54b706d3", 7 | "index.html": "d0c2e544c50aa7bf00f70e7c0783c154", 8 | "/": "d0c2e544c50aa7bf00f70e7c0783c154", 9 | "main.dart.js": "6dcbeb6a3d567e4969c058cd5cf856d6", 10 | "favicon.png": "5dcef449791fa27946b3d35ad8803796", 11 | "icons/Icon-192.png": "ac9a721a12bbc803b44f645561ecb1e1", 12 | "icons/Icon-512.png": "96e752610906ba2a93c65f8abe1645f1", 13 | "manifest.json": "785b06c3e8c6ba5d4c04ee9ac2a3ae5e", 14 | "assets/AssetManifest.json": "3391632d06375c0d794dee6cafc6c232", 15 | "assets/NOTICES": "7f9e46a2c4e7e8759f2ffc96fb7a102b", 16 | "assets/FontManifest.json": "a4df2cc5008d99c0be44f6c46cecf41c", 17 | "assets/packages/cupertino_icons/assets/CupertinoIcons.ttf": "6d342eb68f170c97609e9da345464e5e", 18 | "assets/fonts/NothingYouCouldDo.ttf": "928b116194fd8f799c4b8c58ce8aa734", 19 | "assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1", 20 | "assets/assets/love_gray.png": "2781e2665297e3b208cdd340cb836398", 21 | "assets/assets/apple_lock.flr": "a8d0626cbab91ac731f3d2551c138357", 22 | "assets/assets/love.png": "3091c01fc119a68bd7f1d20f9e1e92d8" 23 | }; 24 | 25 | // The application shell files that are downloaded before a service worker can 26 | // start. 27 | const CORE = [ 28 | "/", 29 | "main.dart.js", 30 | "index.html", 31 | "assets/NOTICES", 32 | "assets/AssetManifest.json", 33 | "assets/FontManifest.json"]; 34 | // During install, the TEMP cache is populated with the application shell files. 35 | self.addEventListener("install", (event) => { 36 | self.skipWaiting(); 37 | return event.waitUntil( 38 | caches.open(TEMP).then((cache) => { 39 | return cache.addAll( 40 | CORE.map((value) => new Request(value, {'cache': 'reload'}))); 41 | }) 42 | ); 43 | }); 44 | 45 | // During activate, the cache is populated with the temp files downloaded in 46 | // install. If this service worker is upgrading from one with a saved 47 | // MANIFEST, then use this to retain unchanged resource files. 48 | self.addEventListener("activate", function(event) { 49 | return event.waitUntil(async function() { 50 | try { 51 | var contentCache = await caches.open(CACHE_NAME); 52 | var tempCache = await caches.open(TEMP); 53 | var manifestCache = await caches.open(MANIFEST); 54 | var manifest = await manifestCache.match('manifest'); 55 | // When there is no prior manifest, clear the entire cache. 56 | if (!manifest) { 57 | await caches.delete(CACHE_NAME); 58 | contentCache = await caches.open(CACHE_NAME); 59 | for (var request of await tempCache.keys()) { 60 | var response = await tempCache.match(request); 61 | await contentCache.put(request, response); 62 | } 63 | await caches.delete(TEMP); 64 | // Save the manifest to make future upgrades efficient. 65 | await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES))); 66 | return; 67 | } 68 | var oldManifest = await manifest.json(); 69 | var origin = self.location.origin; 70 | for (var request of await contentCache.keys()) { 71 | var key = request.url.substring(origin.length + 1); 72 | if (key == "") { 73 | key = "/"; 74 | } 75 | // If a resource from the old manifest is not in the new cache, or if 76 | // the MD5 sum has changed, delete it. Otherwise the resource is left 77 | // in the cache and can be reused by the new service worker. 78 | if (!RESOURCES[key] || RESOURCES[key] != oldManifest[key]) { 79 | await contentCache.delete(request); 80 | } 81 | } 82 | // Populate the cache with the app shell TEMP files, potentially overwriting 83 | // cache files preserved above. 84 | for (var request of await tempCache.keys()) { 85 | var response = await tempCache.match(request); 86 | await contentCache.put(request, response); 87 | } 88 | await caches.delete(TEMP); 89 | // Save the manifest to make future upgrades efficient. 90 | await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES))); 91 | return; 92 | } catch (err) { 93 | // On an unhandled exception the state of the cache cannot be guaranteed. 94 | console.error('Failed to upgrade service worker: ' + err); 95 | await caches.delete(CACHE_NAME); 96 | await caches.delete(TEMP); 97 | await caches.delete(MANIFEST); 98 | } 99 | }()); 100 | }); 101 | 102 | // The fetch handler redirects requests for RESOURCE files to the service 103 | // worker cache. 104 | self.addEventListener("fetch", (event) => { 105 | if (event.request.method !== 'GET') { 106 | return; 107 | } 108 | var origin = self.location.origin; 109 | var key = event.request.url.substring(origin.length + 1); 110 | // Redirect URLs to the index.html 111 | if (key.indexOf('?v=') != -1) { 112 | key = key.split('?v=')[0]; 113 | } 114 | if (event.request.url == origin || event.request.url.startsWith(origin + '/#') || key == '') { 115 | key = '/'; 116 | } 117 | // If the URL is not the RESOURCE list then return to signal that the 118 | // browser should take over. 119 | if (!RESOURCES[key]) { 120 | return; 121 | } 122 | // If the URL is the index.html, perform an online-first request. 123 | if (key == '/') { 124 | return onlineFirst(event); 125 | } 126 | event.respondWith(caches.open(CACHE_NAME) 127 | .then((cache) => { 128 | return cache.match(event.request).then((response) => { 129 | // Either respond with the cached resource, or perform a fetch and 130 | // lazily populate the cache. 131 | return response || fetch(event.request).then((response) => { 132 | cache.put(event.request, response.clone()); 133 | return response; 134 | }); 135 | }) 136 | }) 137 | ); 138 | }); 139 | 140 | self.addEventListener('message', (event) => { 141 | // SkipWaiting can be used to immediately activate a waiting service worker. 142 | // This will also require a page refresh triggered by the main worker. 143 | if (event.data === 'skipWaiting') { 144 | self.skipWaiting(); 145 | return; 146 | } 147 | if (event.data === 'downloadOffline') { 148 | downloadOffline(); 149 | return; 150 | } 151 | }); 152 | 153 | // Download offline will check the RESOURCES for all files not in the cache 154 | // and populate them. 155 | async function downloadOffline() { 156 | var resources = []; 157 | var contentCache = await caches.open(CACHE_NAME); 158 | var currentContent = {}; 159 | for (var request of await contentCache.keys()) { 160 | var key = request.url.substring(origin.length + 1); 161 | if (key == "") { 162 | key = "/"; 163 | } 164 | currentContent[key] = true; 165 | } 166 | for (var resourceKey of Object.keys(RESOURCES)) { 167 | if (!currentContent[resourceKey]) { 168 | resources.push(resourceKey); 169 | } 170 | } 171 | return contentCache.addAll(resources); 172 | } 173 | 174 | // Attempt to download the resource online before falling back to 175 | // the offline cache. 176 | function onlineFirst(event) { 177 | return event.respondWith( 178 | fetch(event.request).then((response) => { 179 | return caches.open(CACHE_NAME).then((cache) => { 180 | cache.put(event.request, response.clone()); 181 | return response; 182 | }); 183 | }).catch((error) => { 184 | return caches.open(CACHE_NAME).then((cache) => { 185 | return cache.match(event.request).then((response) => { 186 | if (response != null) { 187 | return response; 188 | } 189 | throw error; 190 | }); 191 | }); 192 | }) 193 | ); 194 | } 195 | -------------------------------------------------------------------------------- /docs/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/icons/Icon-192.png -------------------------------------------------------------------------------- /docs/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/docs/icons/Icon-512.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | animations 27 | 28 | 29 | 30 | 33 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /docs/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "animations", 3 | "short_name": "animations", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /docs/version.json: -------------------------------------------------------------------------------- 1 | {"app_name":"animations_app","version":"1.1.0","build_number":null} -------------------------------------------------------------------------------- /firebase/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "mono-firebase" 4 | }, 5 | "targets": { 6 | "mono-firebase": { 7 | "hosting": { 8 | "animation": [ 9 | "animation-mono" 10 | ] 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /firebase/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | firebase-debug.log* 8 | firebase-debug.*.log* 9 | 10 | # Firebase cache 11 | .firebase/ 12 | 13 | # Firebase config 14 | 15 | # Uncomment this if you'd like others to create their own Firebase project. 16 | # For a team working on the same Firebase project(s), it is recommended to leave 17 | # it commented so all members can deploy to the same project(s) in .firebaserc. 18 | # .firebaserc 19 | 20 | # Runtime data 21 | pids 22 | *.pid 23 | *.seed 24 | *.pid.lock 25 | 26 | # Directory for instrumented libs generated by jscoverage/JSCover 27 | lib-cov 28 | 29 | # Coverage directory used by tools like istanbul 30 | coverage 31 | 32 | # nyc test coverage 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 36 | .grunt 37 | 38 | # Bower dependency directory (https://bower.io/) 39 | bower_components 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (http://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directories 48 | node_modules/ 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # Yarn Integrity file 63 | .yarn-integrity 64 | 65 | # dotenv environment variables file 66 | .env 67 | 68 | public/ 69 | -------------------------------------------------------------------------------- /firebase/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": [ 3 | { 4 | "target": "animation", 5 | "public": "public/animation", 6 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], 7 | "rewrites": [ 8 | { 9 | "source": "**", 10 | "destination": "/index.html" 11 | } 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /fonts/NothingYouCouldDo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/fonts/NothingYouCouldDo.ttf -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/mono/fvm/versions/beta" 4 | export "FLUTTER_APPLICATION_PATH=/Users/mono/Git/flutter-animations" 5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true" 6 | export "FLUTTER_TARGET=lib/main.dart" 7 | export "FLUTTER_BUILD_DIR=build" 8 | export "FLUTTER_BUILD_NAME=1.1.0" 9 | export "FLUTTER_BUILD_NUMBER=1.1.0" 10 | export "DART_OBFUSCATION=false" 11 | export "TRACK_WIDGET_CREATION=true" 12 | export "TREE_SHAKE_ICONS=false" 13 | export "PACKAGE_CONFIG=.dart_tool/package_config.json" 14 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | pods_ary = [] 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) { |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | pods_ary.push({:name => podname, :path => podpath}); 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | } 32 | return pods_ary 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | 38 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 39 | # referring to absolute paths on developers' machines. 40 | system('rm -rf .symlinks') 41 | system('mkdir -p .symlinks/plugins') 42 | 43 | # Flutter Pods 44 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 45 | if generated_xcode_build_settings.empty? 46 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." 47 | end 48 | generated_xcode_build_settings.map { |p| 49 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 50 | symlink = File.join('.symlinks', 'flutter') 51 | File.symlink(File.dirname(p[:path]), symlink) 52 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 53 | end 54 | } 55 | 56 | # Plugin Pods 57 | plugin_pods = parse_KV_file('../.flutter-plugins') 58 | plugin_pods.map { |p| 59 | symlink = File.join('.symlinks', 'plugins', p[:name]) 60 | File.symlink(p[:path], symlink) 61 | pod p[:name], :path => File.join(symlink, 'ios') 62 | } 63 | end 64 | 65 | post_install do |installer| 66 | installer.pods_project.targets.each do |target| 67 | target.build_configurations.each do |config| 68 | config.build_settings['ENABLE_BITCODE'] = 'NO' 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | animations 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/app.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | // TODO(mono): ナビゲーションバー右にソース見られるボタンを置きたい(他のアプリを参考にする) 5 | void main() => runApp(const App()); 6 | -------------------------------------------------------------------------------- /lib/pages/custom/animated_builder_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/widget/ghost_fade_tween.dart'; 2 | import 'package:animations_app/pages/custom/widget/switch_string_tween.dart'; 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AnimatedBuilderPage extends StatefulWidget { 7 | const AnimatedBuilderPage({super.key}); 8 | 9 | static const routeName = 'AnimatedBuilderPage'; 10 | 11 | @override 12 | State createState() => _AnimatedBuilderPageState(); 13 | } 14 | 15 | class _AnimatedBuilderPageState extends State 16 | with SingleTickerProviderStateMixin { 17 | static const _texts = [ 18 | 'First', 19 | 'Second', 20 | 'Third', 21 | ]; 22 | static const _colors = [ 23 | Colors.black, 24 | Colors.blue, 25 | Colors.red, 26 | ]; 27 | var _index = 0; 28 | String get _currentText => _texts[_index % 3]; 29 | Color get _currentColor => _colors[_index % 3]; 30 | 31 | late final AnimationController _animation = AnimationController( 32 | vsync: this, 33 | duration: const Duration(milliseconds: 1000), 34 | ); 35 | late GhostFadeTween _colorTween = GhostFadeTween( 36 | begin: _currentColor, 37 | end: _currentColor, 38 | ); 39 | late SwitchStringTween _stringTween = SwitchStringTween( 40 | begin: _currentText, 41 | end: _currentText, 42 | ); 43 | 44 | @override 45 | void dispose() { 46 | _animation.dispose(); 47 | super.dispose(); 48 | } 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return AppScaffold( 53 | title: 'AnimatedBuilder', 54 | floatingActionButton: FloatingActionButton( 55 | onPressed: () { 56 | setState(() { 57 | _index++; 58 | _colorTween = GhostFadeTween( 59 | begin: _colorTween.end, 60 | end: _currentColor, 61 | ); 62 | _stringTween = SwitchStringTween( 63 | begin: _stringTween.end, 64 | end: _currentText, 65 | ); 66 | }); 67 | _animation.forward(from: 0); 68 | }, 69 | child: const Icon(Icons.refresh), 70 | ), 71 | child: Center( 72 | child: AnimatedBuilder( 73 | animation: _animation, 74 | builder: (context, child) { 75 | // 一般的にchildは利用するべきだが今回は不要 76 | return Text( 77 | _stringTween.evaluate(_animation), 78 | style: Theme.of(context) 79 | .textTheme 80 | .headline6! 81 | .copyWith(color: _colorTween.evaluate(_animation)), 82 | ); 83 | }, 84 | ), 85 | ), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/pages/custom/animated_switcher_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedSwitcher2Page extends StatefulWidget { 5 | const AnimatedSwitcher2Page({super.key}); 6 | 7 | static const routeName = 'AnimatedSwitcher2Page'; 8 | 9 | @override 10 | State createState() => _AnimatedSwitcher2PageState(); 11 | } 12 | 13 | class _AnimatedSwitcher2PageState extends State { 14 | static const _texts = [ 15 | 'First', 16 | 'Second', 17 | 'Third', 18 | ]; 19 | static const _colors = [ 20 | Colors.black, 21 | Colors.blue, 22 | Colors.red, 23 | ]; 24 | var _index = 0; 25 | String get _currentText => _texts[_index % 3]; 26 | Color get _currentColor => _colors[_index % 3]; 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return AppScaffold( 31 | title: 'AnimatedSwitcher', 32 | floatingActionButton: FloatingActionButton( 33 | onPressed: () { 34 | setState(() { 35 | _index++; 36 | }); 37 | }, 38 | child: const Icon(Icons.refresh), 39 | ), 40 | child: Center( 41 | child: AnimatedSwitcher( 42 | duration: const Duration(milliseconds: 1000), 43 | transitionBuilder: (child, animation) { 44 | return FadeTransition( 45 | opacity: 46 | animation.drive(CurveTween(curve: const Interval(0.5, 1))), 47 | child: child, 48 | ); 49 | }, 50 | child: Text( 51 | _currentText, 52 | key: ValueKey(_currentText), 53 | style: Theme.of(context) 54 | .textTheme 55 | .headline6! 56 | .copyWith(color: _currentColor), 57 | ), 58 | ), 59 | ), 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/pages/custom/animated_widget_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/widget/ghost_fade_tween.dart'; 2 | import 'package:animations_app/pages/custom/widget/switch_string_tween.dart'; 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AnimatedWidgetPage extends StatefulWidget { 7 | const AnimatedWidgetPage({super.key}); 8 | 9 | static const routeName = 'AnimatedWidgetPage'; 10 | 11 | @override 12 | State createState() => _AnimatedWidgetPageState(); 13 | } 14 | 15 | class _AnimatedWidgetPageState extends State 16 | with SingleTickerProviderStateMixin { 17 | static const _texts = [ 18 | 'First', 19 | 'Second', 20 | 'Third', 21 | ]; 22 | static const _colors = [ 23 | Colors.black, 24 | Colors.blue, 25 | Colors.red, 26 | ]; 27 | var _index = 0; 28 | String get _currentText => _texts[_index % 3]; 29 | Color get _currentColor => _colors[_index % 3]; 30 | 31 | late final AnimationController _animation = AnimationController( 32 | vsync: this, 33 | duration: const Duration(milliseconds: 1000), 34 | ); 35 | late GhostFadeTween _colorTween = GhostFadeTween( 36 | begin: _currentColor, 37 | end: _currentColor, 38 | ); 39 | late SwitchStringTween _stringTween = SwitchStringTween( 40 | begin: _currentText, 41 | end: _currentText, 42 | ); 43 | 44 | @override 45 | void dispose() { 46 | _animation.dispose(); 47 | super.dispose(); 48 | } 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return AppScaffold( 53 | title: 'AnimatedWidget', 54 | floatingActionButton: FloatingActionButton( 55 | onPressed: () { 56 | setState(() { 57 | _index++; 58 | _colorTween = GhostFadeTween( 59 | begin: _colorTween.end, 60 | end: _currentColor, 61 | ); 62 | _stringTween = SwitchStringTween( 63 | begin: _stringTween.end, 64 | end: _currentText, 65 | ); 66 | }); 67 | _animation.forward(from: 0); 68 | }, 69 | child: const Icon(Icons.refresh), 70 | ), 71 | child: Center( 72 | child: _TextStyleColorTransition( 73 | animation: _animation.drive(_colorTween), 74 | style: Theme.of(context).textTheme.headline6!, 75 | child: _StringTransition(animation: _animation.drive(_stringTween)), 76 | ), 77 | ), 78 | ); 79 | } 80 | } 81 | 82 | class _TextStyleColorTransition extends AnimatedWidget { 83 | const _TextStyleColorTransition({ 84 | required this.child, 85 | required this.style, 86 | required Animation animation, 87 | }) : super( 88 | listenable: animation, 89 | ); 90 | 91 | final Widget child; 92 | final TextStyle style; 93 | 94 | @override 95 | Widget build(BuildContext context) { 96 | final animation = listenable as Animation; 97 | return DefaultTextStyle( 98 | style: style.copyWith(color: animation.value), 99 | child: child, 100 | ); 101 | } 102 | } 103 | 104 | class _StringTransition extends AnimatedWidget { 105 | const _StringTransition({ 106 | required Animation animation, 107 | }) : super( 108 | listenable: animation, 109 | ); 110 | 111 | @override 112 | Widget build(BuildContext context) { 113 | final animation = listenable as Animation; 114 | return Text(animation.value); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/pages/custom/animation_controller_set_state_enhanced2_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/widget/ghost_fade_tween.dart'; 2 | import 'package:animations_app/pages/custom/widget/switch_string_tween.dart'; 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AnimationControllerSetStateEnhanced2Page extends StatefulWidget { 7 | const AnimationControllerSetStateEnhanced2Page({super.key}); 8 | 9 | static const routeName = 'AnimationControllerSetStateEnhanced2'; 10 | 11 | @override 12 | State createState() => 13 | _AnimationControllerSetStateEnhanced2PageState(); 14 | } 15 | 16 | class _AnimationControllerSetStateEnhanced2PageState 17 | extends State 18 | with SingleTickerProviderStateMixin { 19 | static const _texts = [ 20 | 'First', 21 | 'Second', 22 | 'Third', 23 | ]; 24 | static const _colors = [ 25 | Colors.black, 26 | Colors.blue, 27 | Colors.red, 28 | ]; 29 | var _index = 0; 30 | String get _currentText => _texts[_index % 3]; 31 | Color get _currentColor => _colors[_index % 3]; 32 | 33 | late GhostFadeTween _colorTween = GhostFadeTween( 34 | begin: _currentColor, 35 | end: _currentColor, 36 | ); 37 | late SwitchStringTween _stringTween = SwitchStringTween( 38 | begin: _currentText, 39 | end: _currentText, 40 | ); 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return AppScaffold( 45 | title: 'AnimationController - SetState (Enhanced)', 46 | floatingActionButton: FloatingActionButton( 47 | onPressed: () { 48 | setState(() { 49 | _index++; 50 | _colorTween = GhostFadeTween( 51 | begin: _colorTween.end, 52 | end: _currentColor, 53 | ); 54 | _stringTween = SwitchStringTween( 55 | begin: _stringTween.end, 56 | end: _currentText, 57 | ); 58 | }); 59 | }, 60 | child: const Icon(Icons.refresh), 61 | ), 62 | child: Center( 63 | child: _MyAnimatedWidget( 64 | stringTween: _stringTween, 65 | colorTween: _colorTween, 66 | ), 67 | ), 68 | ); 69 | } 70 | } 71 | 72 | class _MyAnimatedWidget extends StatefulWidget { 73 | const _MyAnimatedWidget({ 74 | required this.stringTween, 75 | required this.colorTween, 76 | }); 77 | 78 | final SwitchStringTween stringTween; 79 | final GhostFadeTween colorTween; 80 | 81 | @override 82 | State<_MyAnimatedWidget> createState() => __MyAnimatedWidgetState(); 83 | } 84 | 85 | class __MyAnimatedWidgetState extends State<_MyAnimatedWidget> 86 | with SingleTickerProviderStateMixin { 87 | late final AnimationController _animation = AnimationController( 88 | vsync: this, 89 | duration: const Duration(milliseconds: 1000), 90 | )..addListener(() { 91 | setState(() {}); 92 | }); 93 | 94 | @override 95 | void dispose() { 96 | _animation.dispose(); 97 | super.dispose(); 98 | } 99 | 100 | @override 101 | void didUpdateWidget(_MyAnimatedWidget oldWidget) { 102 | super.didUpdateWidget(oldWidget); 103 | if (oldWidget.colorTween != widget.colorTween && 104 | oldWidget.stringTween != widget.stringTween) { 105 | _animation.forward(from: 0); 106 | } 107 | } 108 | 109 | @override 110 | Widget build(BuildContext context) { 111 | return Text( 112 | widget.stringTween.evaluate(_animation), 113 | style: Theme.of(context).textTheme.headline6!.copyWith( 114 | color: widget.colorTween.evaluate(_animation), 115 | ), 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/pages/custom/animation_controller_set_state_enhanced_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/widget/ghost_fade_tween.dart'; 2 | import 'package:animations_app/pages/custom/widget/switch_string_tween.dart'; 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AnimationControllerSetStateEnhancedPage extends StatefulWidget { 7 | const AnimationControllerSetStateEnhancedPage({super.key}); 8 | 9 | static const routeName = 'AnimationControllerSetStateEnhanced'; 10 | 11 | @override 12 | State createState() => 13 | _AnimationControllerSetStateEnhancedPageState(); 14 | } 15 | 16 | class _AnimationControllerSetStateEnhancedPageState 17 | extends State 18 | with SingleTickerProviderStateMixin { 19 | static const _texts = [ 20 | 'First', 21 | 'Second', 22 | 'Third', 23 | ]; 24 | static const _colors = [ 25 | Colors.black, 26 | Colors.blue, 27 | Colors.red, 28 | ]; 29 | var _index = 0; 30 | String get _currentText => _texts[_index % 3]; 31 | Color get _currentColor => _colors[_index % 3]; 32 | 33 | late final AnimationController _animation = AnimationController( 34 | vsync: this, 35 | duration: const Duration(milliseconds: 1000), 36 | )..addListener(() { 37 | setState(() {}); 38 | }); 39 | late GhostFadeTween _colorTween = GhostFadeTween( 40 | begin: _currentColor, 41 | end: _currentColor, 42 | ); 43 | late SwitchStringTween _stringTween = SwitchStringTween( 44 | begin: _currentText, 45 | end: _currentText, 46 | ); 47 | 48 | @override 49 | void dispose() { 50 | _animation.dispose(); 51 | super.dispose(); 52 | } 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | return AppScaffold( 57 | title: 'AnimationController - SetState (Enhanced)', 58 | floatingActionButton: FloatingActionButton( 59 | onPressed: () { 60 | setState(() { 61 | _index++; 62 | _colorTween = GhostFadeTween( 63 | begin: _colorTween.end, 64 | end: _currentColor, 65 | ); 66 | _stringTween = SwitchStringTween( 67 | begin: _stringTween.end, 68 | end: _currentText, 69 | ); 70 | }); 71 | _animation.forward(from: 0); 72 | }, 73 | child: const Icon(Icons.refresh), 74 | ), 75 | child: Center( 76 | child: Text( 77 | _stringTween.evaluate(_animation), 78 | style: Theme.of(context).textTheme.headline6!.copyWith( 79 | color: _colorTween.evaluate(_animation), 80 | ), 81 | ), 82 | ), 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/pages/custom/animation_controller_set_state_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimationControllerSetStatePage extends StatefulWidget { 5 | const AnimationControllerSetStatePage({super.key}); 6 | 7 | static const routeName = 'AnimationControllerSetState'; 8 | 9 | @override 10 | State createState() => 11 | _AnimationControllerSetStatePageState(); 12 | } 13 | 14 | class _AnimationControllerSetStatePageState 15 | extends State 16 | with SingleTickerProviderStateMixin { 17 | static const _texts = [ 18 | 'First', 19 | 'Second', 20 | 'Third', 21 | ]; 22 | static const _colors = [ 23 | Colors.black, 24 | Colors.blue, 25 | Colors.red, 26 | ]; 27 | var _index = 0; 28 | String get _currentText => _texts[_index % 3]; 29 | Color get _currentColor => _colors[_index % 3]; 30 | 31 | late final AnimationController _animation = AnimationController( 32 | vsync: this, 33 | duration: const Duration(milliseconds: 1000), 34 | )..addListener(() { 35 | setState(() {}); 36 | }); 37 | late ColorTween _colorTween = ColorTween( 38 | begin: _currentColor, 39 | end: _currentColor, 40 | ); 41 | 42 | @override 43 | void dispose() { 44 | _animation.dispose(); 45 | super.dispose(); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return AppScaffold( 51 | title: 'AnimationController - SetState', 52 | floatingActionButton: FloatingActionButton( 53 | onPressed: () { 54 | setState(() { 55 | _index++; 56 | _colorTween = ColorTween( 57 | begin: _colorTween.end, 58 | end: _currentColor, 59 | ); 60 | }); 61 | _animation.forward(from: 0); 62 | }, 63 | child: const Icon(Icons.refresh), 64 | ), 65 | child: Center( 66 | child: Text( 67 | _currentText, 68 | style: Theme.of(context).textTheme.headline6!.copyWith( 69 | color: _colorTween.evaluate(_animation), 70 | ), 71 | ), 72 | ), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/pages/custom/custom_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/animated_builder_page.dart'; 2 | import 'package:animations_app/pages/custom/animated_switcher_page.dart'; 3 | import 'package:animations_app/pages/custom/animated_widget_page.dart'; 4 | import 'package:animations_app/pages/custom/animation_controller_set_state_enhanced2_page.dart'; 5 | import 'package:animations_app/pages/custom/animation_controller_set_state_enhanced_page.dart'; 6 | import 'package:animations_app/pages/custom/animation_controller_set_state_page.dart'; 7 | import 'package:animations_app/pages/custom/implicitly_animated_widget_page.dart'; 8 | import 'package:animations_app/widget/app_list_tile.dart'; 9 | import 'package:animations_app/widget/app_scaffold.dart'; 10 | import 'package:flutter/material.dart'; 11 | 12 | import 'tween_animation_builder_page.dart'; 13 | 14 | class CustomPage extends StatelessWidget { 15 | const CustomPage({super.key}); 16 | 17 | static const routeName = 'Custom'; 18 | @override 19 | Widget build(BuildContext context) { 20 | return AppScaffold( 21 | title: 'Custom', 22 | child: ListView( 23 | children: const [ 24 | AppListTile( 25 | title: 'AnimationController - SetState', 26 | nextRouteName: AnimationControllerSetStatePage.routeName, 27 | ), 28 | AppListTile( 29 | title: 'AnimationController - SetState (Enhanced)', 30 | nextRouteName: AnimationControllerSetStateEnhancedPage.routeName, 31 | ), 32 | AppListTile( 33 | title: 'AnimationController - SetState (Enhanced2)', 34 | nextRouteName: AnimationControllerSetStateEnhanced2Page.routeName, 35 | ), 36 | AppListTile( 37 | title: 'AnimatedWidget', 38 | nextRouteName: AnimatedWidgetPage.routeName, 39 | ), 40 | AppListTile( 41 | title: 'AnimatedBuilder', 42 | nextRouteName: AnimatedBuilderPage.routeName, 43 | ), 44 | AppListTile( 45 | title: 'AnimatedSwitcher', 46 | nextRouteName: AnimatedSwitcher2Page.routeName, 47 | ), 48 | AppListTile( 49 | title: 'ImplicitlyAnimatedWidget', 50 | nextRouteName: ImplicitlyAnimatedWidgetPage.routeName, 51 | ), 52 | AppListTile( 53 | title: 'TweenAnimationBuilder', 54 | nextRouteName: TweenAnimationBuilderPage.routeName, 55 | ), 56 | ], 57 | ), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/pages/custom/implicitly_animated_widget_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/widget/ghost_fade_tween.dart'; 2 | import 'package:animations_app/pages/custom/widget/switch_string_tween.dart'; 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class ImplicitlyAnimatedWidgetPage extends StatefulWidget { 7 | const ImplicitlyAnimatedWidgetPage({super.key}); 8 | 9 | static const routeName = 'ImplicitlyAnimatedWidgetPage'; 10 | 11 | @override 12 | State createState() => 13 | _ImplicitlyAnimatedWidgetPageState(); 14 | } 15 | 16 | class _ImplicitlyAnimatedWidgetPageState 17 | extends State { 18 | static const _texts = [ 19 | 'First', 20 | 'Second', 21 | 'Third', 22 | ]; 23 | static const _colors = [ 24 | Colors.black, 25 | Colors.blue, 26 | Colors.red, 27 | ]; 28 | var _index = 0; 29 | String get _currentText => _texts[_index % 3]; 30 | Color get _currentColor => _colors[_index % 3]; 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return AppScaffold( 35 | title: 'ImplicitlyAnimatedWidget', 36 | floatingActionButton: FloatingActionButton( 37 | onPressed: () { 38 | setState(() { 39 | _index++; 40 | }); 41 | }, 42 | child: const Icon(Icons.refresh), 43 | ), 44 | child: Center( 45 | child: Headline( 46 | targetColor: _currentColor, 47 | targetString: _currentText, 48 | ), 49 | ), 50 | ); 51 | } 52 | } 53 | 54 | class Headline extends ImplicitlyAnimatedWidget { 55 | const Headline({ 56 | super.key, 57 | required this.targetColor, 58 | required this.targetString, 59 | }) : super( 60 | duration: const Duration(milliseconds: 1000), 61 | ); 62 | 63 | final Color targetColor; 64 | final String targetString; 65 | 66 | @override 67 | AnimatedWidgetBaseState createState() => _HeadlineState(); 68 | } 69 | 70 | class _HeadlineState extends AnimatedWidgetBaseState { 71 | GhostFadeTween? _colorTween; 72 | SwitchStringTween? _stringTween; 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | return Text( 77 | _stringTween!.evaluate(animation), 78 | style: Theme.of(context) 79 | .textTheme 80 | .headline6! 81 | .copyWith(color: _colorTween!.evaluate(animation)), 82 | ); 83 | } 84 | 85 | @override 86 | void forEachTween(TweenVisitor visitor) { 87 | _colorTween = visitor( 88 | _colorTween, 89 | widget.targetColor, 90 | (dynamic color) => GhostFadeTween(begin: color as Color), 91 | ) as GhostFadeTween?; 92 | 93 | _stringTween = visitor( 94 | _stringTween, 95 | widget.targetString, 96 | (dynamic string) => SwitchStringTween(begin: string as String), 97 | ) as SwitchStringTween?; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/pages/custom/tween_animation_builder_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class TweenAnimationBuilderPage extends StatefulWidget { 5 | const TweenAnimationBuilderPage({super.key}); 6 | 7 | static const routeName = 'TweenAnimationBuilderPage'; 8 | 9 | @override 10 | State createState() => 11 | _TweenAnimationBuilderPageState(); 12 | } 13 | 14 | class _TweenAnimationBuilderPageState extends State { 15 | static const _texts = [ 16 | 'First', 17 | 'Second', 18 | 'Third', 19 | ]; 20 | static const _colors = [ 21 | Colors.black, 22 | Colors.blue, 23 | Colors.red, 24 | ]; 25 | var _index = 0; 26 | ColoredLabel get _coloredLabel => ColoredLabel( 27 | label: _texts[_index % 3], 28 | color: _colors[_index % 3], 29 | ); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return AppScaffold( 34 | title: 'TweenAnimationBuilder', 35 | floatingActionButton: FloatingActionButton( 36 | onPressed: () { 37 | setState(() { 38 | _index++; 39 | }); 40 | }, 41 | child: const Icon(Icons.refresh), 42 | ), 43 | child: Center( 44 | child: TweenAnimationBuilder( 45 | tween: ColoredLabelTween(begin: _coloredLabel, end: _coloredLabel), 46 | duration: const Duration(milliseconds: 1000), 47 | builder: (context, coloredLabel, child) { 48 | return Text( 49 | coloredLabel.label, 50 | style: Theme.of(context) 51 | .textTheme 52 | .headline6! 53 | .copyWith(color: coloredLabel.color), 54 | ); 55 | }, 56 | ), 57 | ), 58 | ); 59 | } 60 | } 61 | 62 | class ColoredLabelTween extends Tween { 63 | ColoredLabelTween({ 64 | super.begin, 65 | super.end, 66 | }); 67 | final _middleColor = Colors.transparent; 68 | 69 | @override 70 | ColoredLabel lerp(double t) => ColoredLabel( 71 | label: t < 0.5 ? begin!.label : end!.label, 72 | color: t < 0.5 73 | ? Color.lerp(begin!.color, _middleColor, t * 2)! 74 | : Color.lerp(_middleColor, end!.color, (t - 0.5) * 2)!, 75 | ); 76 | } 77 | 78 | class ColoredLabel { 79 | ColoredLabel({ 80 | required this.label, 81 | required this.color, 82 | }); 83 | 84 | final String label; 85 | final Color color; 86 | 87 | @override 88 | int get hashCode => Object.hash(label, color); 89 | 90 | @override 91 | bool operator ==(Object other) => 92 | identical(this, other) || 93 | other is ColoredLabel && 94 | runtimeType == other.runtimeType && 95 | label == other.label && 96 | color == other.color; 97 | } 98 | -------------------------------------------------------------------------------- /lib/pages/custom/widget/ghost_fade_tween.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class GhostFadeTween extends Tween { 4 | GhostFadeTween({ 5 | super.begin, 6 | super.end, 7 | }); 8 | final middle = Colors.transparent; 9 | 10 | @override 11 | Color lerp(double t) { 12 | return t < 0.5 13 | ? Color.lerp(begin, middle, t * 2)! 14 | : Color.lerp(middle, end, (t - 0.5) * 2)!; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/pages/custom/widget/switch_string_tween.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SwitchStringTween extends Tween { 4 | SwitchStringTween({ 5 | super.begin, 6 | super.end, 7 | }); 8 | 9 | @override 10 | String lerp(double t) => t < 0.5 ? begin! : end!; 11 | } 12 | -------------------------------------------------------------------------------- /lib/pages/flare/apple_lock_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/widget.dart'; 2 | import 'package:flare_flutter/flare_actor.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class AppleLockPage extends StatefulWidget { 6 | const AppleLockPage({super.key}); 7 | 8 | static const routeName = 'AppleLock'; 9 | @override 10 | State createState() => _AppleLockPageState(); 11 | } 12 | 13 | class _AppleLockPageState extends State { 14 | var _isLocked = false; 15 | @override 16 | Widget build(BuildContext context) { 17 | return AppScaffold( 18 | title: 'Flare Example ', 19 | child: ColoredBox( 20 | color: Colors.black, 21 | child: Center( 22 | child: Column( 23 | mainAxisAlignment: MainAxisAlignment.center, 24 | children: [ 25 | SizedBox( 26 | width: 300, 27 | height: 300, 28 | child: _isLocked 29 | ? const FlareActor( 30 | 'assets/apple_lock.flr', 31 | animation: 'Untitled', 32 | ) 33 | : null, 34 | ), 35 | const SizedBox(height: 16), 36 | ElevatedButton( 37 | onPressed: () { 38 | setState(() => _isLocked = !_isLocked); 39 | }, 40 | child: const Text('LOCK'), 41 | ) 42 | ], 43 | ), 44 | ), 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/pages/flare/flare_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/flare/apple_lock_page.dart'; 2 | import 'package:animations_app/widget/app_list_tile.dart'; 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class FlarePage extends StatelessWidget { 7 | const FlarePage({super.key}); 8 | 9 | static const routeName = 'Flare'; 10 | @override 11 | Widget build(BuildContext context) { 12 | return AppScaffold( 13 | title: 'Flare', 14 | child: ListView( 15 | children: const [ 16 | AppListTile( 17 | title: 'Apple Lock', 18 | nextRouteName: AppleLockPage.routeName, 19 | ), 20 | ], 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/pages/flight_search/README.md: -------------------------------------------------------------------------------- 1 | # Flight Search (Advanced Example) 2 | 3 | ## Credits 4 | 5 | This sample is re-written from this sample: 6 | 7 | - [UI Challenge - Flight Search | Marcin Szałek - Blog](https://marcinszalek.pl/flutter/ui-challenge-flight-search/) 8 | - [MarcinusX/flutter_ui_challenge_flight_search: An advanced UI design implemented in Flutter](https://github.com/MarcinusX/flutter_ui_challenge_flight_search) 9 | - [LICENSE](https://github.com/MarcinusX/flutter_ui_challenge_flight_search/blob/master/LICENSE) 10 | -------------------------------------------------------------------------------- /lib/pages/flight_search/air_asia_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AirAsiaBar extends StatelessWidget { 4 | const AirAsiaBar({ 5 | super.key, 6 | required this.height, 7 | this.leading, 8 | }); 9 | 10 | final double height; 11 | final Widget? leading; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Stack( 16 | children: [ 17 | _buildBackground(context), 18 | _buildAppBar(context), 19 | ], 20 | ); 21 | } 22 | 23 | Widget _buildBackground(BuildContext context) { 24 | return Container( 25 | decoration: BoxDecoration( 26 | gradient: LinearGradient( 27 | begin: Alignment.topCenter, 28 | end: Alignment.bottomCenter, 29 | colors: [ 30 | Theme.of(context).primaryColor, 31 | const Color(0xFFE64C85), 32 | ], 33 | ), 34 | ), 35 | height: height, 36 | ); 37 | } 38 | 39 | Widget _buildAppBar(BuildContext context) { 40 | return AppBar( 41 | leading: leading, 42 | backgroundColor: Colors.transparent, 43 | elevation: 0, 44 | centerTitle: true, 45 | title: const Text( 46 | 'AirAsia', 47 | style: TextStyle( 48 | fontFamily: 'NothingYouCouldDo', 49 | fontWeight: FontWeight.bold, 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/pages/flight_search/animated_dot.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedDot extends AnimatedWidget { 4 | const AnimatedDot({ 5 | super.key, 6 | required Animation animation, 7 | required this.color, 8 | }) : super( 9 | listenable: animation, 10 | ); 11 | 12 | final Color color; 13 | static const double size = 24; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | final animation = super.listenable as Animation; 18 | return Positioned( 19 | top: animation.value, 20 | child: Container( 21 | height: 24, 22 | width: 24, 23 | decoration: BoxDecoration( 24 | color: Colors.white, 25 | shape: BoxShape.circle, 26 | border: Border.all( 27 | color: const Color(0xFFDDDDDD), 28 | ), 29 | ), 30 | child: Container( 31 | margin: const EdgeInsets.all(4), 32 | decoration: BoxDecoration( 33 | color: color, 34 | shape: BoxShape.circle, 35 | ), 36 | ), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/pages/flight_search/animated_plane_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedPlaneIcon extends StatelessWidget { 4 | const AnimatedPlaneIcon({ 5 | super.key, 6 | required this.size, 7 | required this.scaleAnimation, 8 | }); 9 | 10 | final double size; 11 | final Animation scaleAnimation; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ScaleTransition( 16 | alignment: Alignment.bottomCenter, 17 | scale: scaleAnimation, 18 | child: Icon( 19 | Icons.airplanemode_active, 20 | color: Theme.of(context).primaryColor, 21 | size: 36, 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/pages/flight_search/content_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/flight_search/multicity_input.dart'; 2 | import 'package:animations_app/pages/flight_search/price_tab.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class ContentCard extends StatelessWidget { 6 | const ContentCard({ 7 | super.key, 8 | required this.showInput, 9 | required this.onCompleted, 10 | }); 11 | 12 | final bool showInput; 13 | final void Function() onCompleted; 14 | 15 | static const _tabs = [ 16 | Tab(text: 'Flight'), 17 | Tab(text: 'Train'), 18 | Tab(text: 'Bus'), 19 | ]; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Card( 24 | elevation: 4, 25 | margin: const EdgeInsets.all(8), 26 | child: DefaultTabController( 27 | length: _tabs.length, 28 | child: Column( 29 | children: [ 30 | _buildTabBar(), 31 | Expanded( 32 | child: TabBarView( 33 | children: _tabs.map((_) => _buildTabContent()).toList(), 34 | ), 35 | ), 36 | ], 37 | ), 38 | ), 39 | ); 40 | } 41 | 42 | Widget _buildTabBar() { 43 | return Stack( 44 | children: [ 45 | Positioned.fill( 46 | top: null, 47 | child: Container( 48 | height: 2, 49 | color: const Color(0xFFEEEEEE), 50 | ), 51 | ), 52 | const TabBar( 53 | tabs: _tabs, 54 | labelColor: Colors.black, 55 | unselectedLabelColor: Colors.grey, 56 | ), 57 | ], 58 | ); 59 | } 60 | 61 | Widget _buildTabContent() { 62 | return AnimatedSwitcher( 63 | duration: const Duration(milliseconds: 200), 64 | child: SizedBox.expand( 65 | child: showInput 66 | ? const SingleChildScrollView( 67 | physics: AlwaysScrollableScrollPhysics(), 68 | child: MulticityInput(), 69 | ) 70 | : PriceTab(onCompleted: onCompleted), 71 | ), 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/pages/flight_search/fade_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FadeRoute extends MaterialPageRoute { 4 | FadeRoute({ 5 | required super.builder, 6 | }) : super( 7 | fullscreenDialog: true, 8 | ); 9 | 10 | @override 11 | Duration get transitionDuration => const Duration(milliseconds: 100); 12 | 13 | @override 14 | Widget buildTransitions( 15 | BuildContext context, 16 | Animation animation, 17 | Animation secondaryAnimation, 18 | Widget child, 19 | ) { 20 | if (settings.name == '/') { 21 | return child; 22 | } 23 | return FadeTransition( 24 | opacity: animation, 25 | child: child, 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/pages/flight_search/flight_search_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/app.dart'; 2 | import 'package:animations_app/pages/flight_search/air_asia_bar.dart'; 3 | import 'package:animations_app/pages/flight_search/content_card.dart'; 4 | import 'package:animations_app/pages/flight_search/fade_route.dart'; 5 | import 'package:animations_app/pages/flight_search/rounded_button.dart'; 6 | import 'package:animations_app/pages/flight_search/ticker_page.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:keyboard_visibility/keyboard_visibility.dart'; 9 | 10 | enum FlightSearchMode { normal, plane, done } 11 | 12 | class FlightSearchPage extends StatefulWidget { 13 | const FlightSearchPage({super.key}); 14 | 15 | static const routeName = 'FlightSearchPage'; 16 | 17 | @override 18 | State createState() => _FlightSearchPageState(); 19 | } 20 | 21 | class _FlightSearchPageState extends State { 22 | var _mode = FlightSearchMode.normal; 23 | var _isKeyboardVisible = false; 24 | var _selectedButtonIndex = 2; 25 | final _keyboardVisibilityNotification = KeyboardVisibilityNotification(); 26 | late final int _keyboardVisibilityNotificationSubscription; 27 | 28 | @override 29 | void initState() { 30 | super.initState(); 31 | _keyboardVisibilityNotificationSubscription = 32 | _keyboardVisibilityNotification.addNewListener( 33 | onChange: (visible) { 34 | setState(() { 35 | _isKeyboardVisible = visible; 36 | }); 37 | }, 38 | ); 39 | } 40 | 41 | @override 42 | void dispose() { 43 | _keyboardVisibilityNotification 44 | .removeListener(_keyboardVisibilityNotificationSubscription); 45 | super.dispose(); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | final top = MediaQuery.of(context).padding.top; 51 | return Scaffold( 52 | body: Stack( 53 | children: [ 54 | AirAsiaBar( 55 | height: top + 200, 56 | leading: IconButton( 57 | icon: const BackButtonIcon(), 58 | tooltip: MaterialLocalizations.of(context).backButtonTooltip, 59 | onPressed: () { 60 | rootNavigatorKey.currentState!.pop(); 61 | }, 62 | ), 63 | ), 64 | Padding( 65 | padding: EdgeInsets.only(top: top + 40.0), 66 | child: Column( 67 | children: [ 68 | _buildButtonsRow(), 69 | Expanded( 70 | child: ContentCard( 71 | onCompleted: () { 72 | setState(() { 73 | _mode = FlightSearchMode.done; 74 | }); 75 | }, 76 | showInput: _mode == FlightSearchMode.normal, 77 | ), 78 | ), 79 | ], 80 | ), 81 | ), 82 | ], 83 | ), 84 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 85 | floatingActionButton: _buildFab(), 86 | ); 87 | } 88 | 89 | Widget? _buildFab() { 90 | if (_isKeyboardVisible) { 91 | return null; 92 | } 93 | switch (_mode) { 94 | case FlightSearchMode.normal: 95 | return FloatingActionButton( 96 | onPressed: () { 97 | setState(() { 98 | _mode = FlightSearchMode.plane; 99 | }); 100 | }, 101 | child: const Icon( 102 | Icons.timeline, 103 | size: 36, 104 | ), 105 | ); 106 | case FlightSearchMode.plane: 107 | return null; 108 | case FlightSearchMode.done: 109 | return FloatingActionButton( 110 | onPressed: () { 111 | Navigator.of(context).push( 112 | FadeRoute(builder: (context) => const TicketsPage()), 113 | ); 114 | }, 115 | child: const Icon( 116 | Icons.check, 117 | size: 36, 118 | ), 119 | ); 120 | } 121 | } 122 | 123 | Widget _buildButtonsRow() { 124 | return Padding( 125 | padding: const EdgeInsets.all(8), 126 | child: Row( 127 | children: [ 128 | RoundedButton( 129 | text: 'ONE WAY', 130 | selected: _selectedButtonIndex == 0, 131 | onPressed: () { 132 | setState(() => _selectedButtonIndex = 0); 133 | }, 134 | ), 135 | RoundedButton( 136 | text: 'ROUND', 137 | selected: _selectedButtonIndex == 1, 138 | onPressed: () { 139 | setState(() => _selectedButtonIndex = 1); 140 | }, 141 | ), 142 | RoundedButton( 143 | text: 'MULTICITY', 144 | selected: _selectedButtonIndex == 2, 145 | onPressed: () { 146 | setState(() => _selectedButtonIndex = 2); 147 | }, 148 | ), 149 | ], 150 | ), 151 | ); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /lib/pages/flight_search/flight_stop.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | @immutable 4 | class FlightStop { 5 | const FlightStop({ 6 | required this.from, 7 | required this.to, 8 | required this.date, 9 | required this.duration, 10 | required this.price, 11 | required this.fromToTime, 12 | }); 13 | 14 | final String from; 15 | final String to; 16 | final String date; 17 | final String duration; 18 | final String price; 19 | final String fromToTime; 20 | } 21 | -------------------------------------------------------------------------------- /lib/pages/flight_search/flight_stop_ticker.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | @immutable 4 | class FlightStopTicket { 5 | const FlightStopTicket({ 6 | required this.from, 7 | required this.fromShort, 8 | required this.to, 9 | required this.toShort, 10 | required this.flightNumber, 11 | }); 12 | final String from; 13 | final String fromShort; 14 | final String to; 15 | final String toShort; 16 | final String flightNumber; 17 | } 18 | -------------------------------------------------------------------------------- /lib/pages/flight_search/multicity_input.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MulticityInput extends StatefulWidget { 4 | const MulticityInput({super.key}); 5 | 6 | static const double _rightMargin = 64; 7 | static const double _rowSpace = 8; 8 | static const rowSpaceBox = SizedBox(height: _rowSpace); 9 | 10 | @override 11 | State createState() => _MulticityInputState(); 12 | } 13 | 14 | class _MulticityInputState extends State { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Padding( 18 | padding: const EdgeInsets.all(16), 19 | child: Column( 20 | children: [ 21 | _buildFrom(), 22 | MulticityInput.rowSpaceBox, 23 | _buildTo1(), 24 | MulticityInput.rowSpaceBox, 25 | _buildTo2(), 26 | MulticityInput.rowSpaceBox, 27 | _buildPassengers(), 28 | MulticityInput.rowSpaceBox, 29 | _buildDateRow(), 30 | ], 31 | ), 32 | ); 33 | } 34 | 35 | Widget _buildFrom() { 36 | return Padding( 37 | padding: const EdgeInsets.only(right: MulticityInput._rightMargin), 38 | child: _buildTextField( 39 | icon: Icons.flight_takeoff, 40 | labelText: 'From', 41 | ), 42 | ); 43 | } 44 | 45 | Widget _buildTo1() { 46 | return Padding( 47 | padding: const EdgeInsets.only(right: MulticityInput._rightMargin), 48 | child: _buildTextField( 49 | icon: Icons.flight_land, 50 | labelText: 'To', 51 | ), 52 | ); 53 | } 54 | 55 | Row _buildTo2() { 56 | return Row( 57 | children: [ 58 | Expanded( 59 | child: _buildTextField( 60 | icon: Icons.flight_land, 61 | labelText: 'To', 62 | ), 63 | ), 64 | SizedBox( 65 | width: MulticityInput._rightMargin, 66 | child: IconButton( 67 | onPressed: () {}, 68 | icon: const Icon( 69 | Icons.add_circle_outline, 70 | color: Colors.grey, 71 | ), 72 | ), 73 | ), 74 | ], 75 | ); 76 | } 77 | 78 | Widget _buildPassengers() { 79 | return Padding( 80 | padding: const EdgeInsets.only(right: MulticityInput._rightMargin), 81 | child: _buildTextField( 82 | icon: Icons.person, 83 | labelText: 'Passengers', 84 | ), 85 | ); 86 | } 87 | 88 | Row _buildDateRow() { 89 | return Row( 90 | children: [ 91 | Expanded( 92 | child: _buildTextField( 93 | icon: Icons.date_range, 94 | labelText: 'Departure', 95 | ), 96 | ), 97 | Expanded( 98 | child: _buildTextField( 99 | labelText: 'Arrival', 100 | ), 101 | ), 102 | ], 103 | ); 104 | } 105 | 106 | TextFormField _buildTextField({ 107 | required String labelText, 108 | IconData? icon, 109 | }) { 110 | return TextFormField( 111 | decoration: InputDecoration( 112 | icon: Icon( 113 | icon, 114 | color: Theme.of(context).primaryColor, 115 | ), 116 | labelText: labelText, 117 | ), 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/pages/flight_search/price_tab.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/flight_search/animated_dot.dart'; 2 | import 'package:animations_app/pages/flight_search/animated_plane_icon.dart'; 3 | import 'package:animations_app/pages/flight_search/flight_stop.dart'; 4 | import 'package:animations_app/pages/flight_search/flight_stop_card.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | class PriceTab extends StatefulWidget { 8 | const PriceTab({ 9 | super.key, 10 | required this.onCompleted, 11 | }); 12 | 13 | final void Function() onCompleted; 14 | 15 | @override 16 | State createState() => _PriceTabState(); 17 | } 18 | 19 | class _PriceTabState extends State with TickerProviderStateMixin { 20 | late final AnimationController _planeSizeController = AnimationController( 21 | vsync: this, 22 | duration: const Duration(milliseconds: 340), 23 | ); 24 | late final AnimationController _planeTravelController = AnimationController( 25 | vsync: this, 26 | duration: const Duration(milliseconds: 400), 27 | ); 28 | late final AnimationController _dotsAnimationController = AnimationController( 29 | vsync: this, 30 | duration: const Duration(milliseconds: 500), 31 | ); 32 | late final Animation _planeScaleAnimation = _planeSizeController 33 | .drive( 34 | CurveTween(curve: Curves.easeOut), 35 | ) 36 | .drive( 37 | Tween( 38 | begin: 5 / 3, 39 | end: 1, 40 | ), 41 | ); 42 | 43 | static const double _initialPlanePaddingBottom = 16; 44 | static const double _minPlanePaddingTop = 16; 45 | static const double _planeSize = 36; 46 | static const double _cardHeight = 80; 47 | static const _flightStops = [ 48 | FlightStop( 49 | from: 'JFK', 50 | to: 'ORY', 51 | date: 'JUN 05', 52 | duration: '6h 25m', 53 | price: '\$851', 54 | fromToTime: '9:26 am - 3:43 pm', 55 | ), 56 | FlightStop( 57 | from: 'MRG', 58 | to: 'FTB', 59 | date: 'JUN 20', 60 | duration: '6h 25m', 61 | price: '\$532', 62 | fromToTime: '9:26 am - 3:43 pm', 63 | ), 64 | FlightStop( 65 | from: 'ERT', 66 | to: 'TVS', 67 | date: 'JUN 20', 68 | duration: '6h 25m', 69 | price: '\$718', 70 | fromToTime: '9:26 am - 3:43 pm', 71 | ), 72 | FlightStop( 73 | from: 'KKR', 74 | to: 'RTY', 75 | date: 'JUN 20', 76 | duration: '6h 25m', 77 | price: '\$663', 78 | fromToTime: '9:26 am - 3:43 pm', 79 | ), 80 | ]; 81 | final _stopKeys = 82 | _flightStops.map((s) => GlobalKey()).toList(); 83 | 84 | @override 85 | void initState() { 86 | super.initState(); 87 | 88 | _forwardAnimation(); 89 | } 90 | 91 | Future _forwardAnimation() async { 92 | await _planeSizeController.forward(); 93 | // ignore: unawaited_futures 94 | Future.delayed(const Duration(milliseconds: 500)) 95 | .then((_) => _planeTravelController.forward()); 96 | // ignore: unawaited_futures 97 | Future.delayed(const Duration(milliseconds: 700)).then((_) async { 98 | await _dotsAnimationController.forward(); 99 | await _animateFlightStopCards(); 100 | }); 101 | } 102 | 103 | Future _animateFlightStopCards() async { 104 | for (final stopKey in _stopKeys) { 105 | await Future.delayed(const Duration(milliseconds: 250)); 106 | // ignore: unawaited_futures 107 | stopKey.currentState?.runAnimation(); 108 | } 109 | await Future.delayed(const Duration(milliseconds: 100)); 110 | widget.onCompleted(); 111 | } 112 | 113 | @override 114 | void dispose() { 115 | _planeSizeController.dispose(); 116 | _planeTravelController.dispose(); 117 | _dotsAnimationController.dispose(); 118 | super.dispose(); 119 | } 120 | 121 | @override 122 | Widget build(BuildContext context) { 123 | return LayoutBuilder( 124 | builder: (context, constraints) { 125 | final flightStopTweenMap = _flightStops.asMap().map((index, stop) { 126 | const minMarginTop = 127 | _minPlanePaddingTop + _planeSize + (0.8 * _cardHeight); 128 | final finalMarginTop = index * (0.8 * _cardHeight) + minMarginTop; 129 | return MapEntry( 130 | stop, 131 | Tween( 132 | begin: constraints.maxHeight, 133 | end: finalMarginTop, 134 | ), 135 | ); 136 | }); 137 | return Stack( 138 | alignment: Alignment.center, 139 | children: [ 140 | _buildPlane(constraints: constraints), 141 | ..._flightStops.map( 142 | (stop) => _buildStopCard( 143 | stop: stop, 144 | tween: flightStopTweenMap[stop]!, 145 | ), 146 | ), 147 | ..._flightStops.map( 148 | (stop) => _mapFlightStopToDot( 149 | stop: stop, 150 | tween: flightStopTweenMap[stop]!, 151 | ), 152 | ), 153 | ], 154 | ); 155 | }, 156 | ); 157 | } 158 | 159 | Widget _buildPlane({ 160 | required BoxConstraints constraints, 161 | }) { 162 | final beginTop = 163 | constraints.maxHeight - (_initialPlanePaddingBottom + _planeSize); 164 | final planeTravelAnimation = _planeTravelController 165 | .drive(CurveTween(curve: Curves.fastOutSlowIn)) 166 | .drive( 167 | Tween( 168 | begin: beginTop, 169 | end: _minPlanePaddingTop, 170 | ), 171 | ); 172 | return AnimatedBuilder( 173 | animation: planeTravelAnimation, 174 | builder: (context, child) => Positioned( 175 | top: planeTravelAnimation.value, 176 | child: child!, 177 | ), 178 | child: Column( 179 | children: [ 180 | AnimatedPlaneIcon( 181 | size: _planeSize, 182 | scaleAnimation: _planeScaleAnimation, 183 | ), 184 | Container( 185 | width: 2, 186 | height: _flightStops.length * _cardHeight * 0.8, 187 | color: const Color.fromARGB(255, 200, 200, 200), 188 | ) 189 | ], 190 | ), 191 | ); 192 | } 193 | 194 | Widget _mapFlightStopToDot({ 195 | required FlightStop stop, 196 | required Tween tween, 197 | }) { 198 | final index = _flightStops.indexOf(stop); 199 | final start = 0.2 * _flightStops.indexOf(stop); 200 | final animation = _dotsAnimationController 201 | .drive( 202 | CurveTween( 203 | curve: Interval( 204 | start, 205 | start + 0.4, 206 | curve: Curves.easeOut, 207 | ), 208 | ), 209 | ) 210 | .drive(tween); 211 | 212 | final isStartOrEnd = index == 0 || index == _flightStops.length - 1; 213 | final color = isStartOrEnd ? Theme.of(context).primaryColor : Colors.green; 214 | return AnimatedDot( 215 | animation: animation, 216 | color: color, 217 | ); 218 | } 219 | 220 | Widget _buildStopCard({ 221 | required FlightStop stop, 222 | required Tween tween, 223 | }) { 224 | final index = _flightStops.indexOf(stop); 225 | final topMargin = 226 | tween.end! - 0.5 * (FlightStopCard.height - AnimatedDot.size); 227 | final isLeft = index.isOdd; 228 | return Align( 229 | alignment: Alignment.topCenter, 230 | child: Padding( 231 | padding: EdgeInsets.only(top: topMargin), 232 | child: Row( 233 | crossAxisAlignment: CrossAxisAlignment.start, 234 | children: [ 235 | isLeft ? Container() : Expanded(child: Container()), 236 | Expanded( 237 | child: FlightStopCard( 238 | key: _stopKeys[index], 239 | flightStop: stop, 240 | isLeft: isLeft, 241 | ), 242 | ), 243 | !isLeft ? Container() : Expanded(child: Container()), 244 | ], 245 | ), 246 | ), 247 | ); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /lib/pages/flight_search/rounded_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RoundedButton extends StatelessWidget { 4 | const RoundedButton({ 5 | super.key, 6 | required this.text, 7 | this.selected = false, 8 | this.onPressed, 9 | }); 10 | 11 | final String text; 12 | final bool selected; 13 | final GestureTapCallback? onPressed; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Expanded( 18 | child: Padding( 19 | padding: const EdgeInsets.all(4), 20 | child: AnimatedCrossFade( 21 | firstChild: _buildSelectedButton(context), 22 | secondChild: _buildUnselectedButton(), 23 | crossFadeState: 24 | selected ? CrossFadeState.showFirst : CrossFadeState.showSecond, 25 | duration: const Duration(milliseconds: 200), 26 | ), 27 | ), 28 | ); 29 | } 30 | 31 | Widget _buildUnselectedButton() { 32 | const color = Colors.white; 33 | return TextButton( 34 | style: TextButton.styleFrom( 35 | side: const BorderSide(color: color), 36 | primary: Colors.white, 37 | onSurface: color, 38 | shape: const StadiumBorder(), 39 | ), 40 | onPressed: onPressed, 41 | child: Center(child: Text(text)), 42 | ); 43 | } 44 | 45 | Widget _buildSelectedButton(BuildContext context) { 46 | final textColor = Theme.of(context).primaryColor; 47 | return ElevatedButton( 48 | style: ElevatedButton.styleFrom( 49 | elevation: 0, 50 | primary: Colors.white, 51 | onPrimary: textColor, 52 | shape: const StadiumBorder(), 53 | ), 54 | onPressed: onPressed ?? () {}, 55 | child: Center(child: Text(text)), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/pages/flight_search/ticker_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/app.dart'; 2 | import 'package:animations_app/pages/flight_search/air_asia_bar.dart'; 3 | import 'package:animations_app/pages/flight_search/flight_stop_ticker.dart'; 4 | import 'package:animations_app/pages/flight_search/ticket_card.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | class TicketsPage extends StatefulWidget { 8 | const TicketsPage({super.key}); 9 | 10 | @override 11 | State createState() => _TicketsPageState(); 12 | } 13 | 14 | class _TicketsPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | static const stops = [ 17 | FlightStopTicket( 18 | from: 'Sahara', 19 | fromShort: 'SHE', 20 | to: 'Macao', 21 | toShort: 'MAC', 22 | flightNumber: 'SE2341', 23 | ), 24 | FlightStopTicket( 25 | from: 'Macao', 26 | fromShort: 'MAC', 27 | to: 'Cape Verde', 28 | toShort: 'CAP', 29 | flightNumber: 'KU2342', 30 | ), 31 | FlightStopTicket( 32 | from: 'Cape Verde', 33 | fromShort: 'CAP', 34 | to: 'Ireland', 35 | toShort: 'IRE', 36 | flightNumber: 'KR3452', 37 | ), 38 | FlightStopTicket( 39 | from: 'Ireland', 40 | fromShort: 'IRE', 41 | to: 'Sahara', 42 | toShort: 'SHE', 43 | flightNumber: 'MR4321', 44 | ), 45 | ]; 46 | late final AnimationController _cardEntranceAnimationController = 47 | AnimationController( 48 | vsync: this, 49 | duration: const Duration(milliseconds: 1100), 50 | ); 51 | late final Map> _ticketAnimations = 52 | stops.asMap().map((index, stop) { 53 | final start = index * 0.1; 54 | return MapEntry( 55 | stop, 56 | _cardEntranceAnimationController 57 | .drive( 58 | CurveTween( 59 | curve: Interval( 60 | start, 61 | start + 0.6, 62 | curve: Curves.decelerate, 63 | ), 64 | ), 65 | ) 66 | .drive( 67 | Tween(begin: 800, end: 0), 68 | ), 69 | ); 70 | }); 71 | 72 | @override 73 | void initState() { 74 | super.initState(); 75 | 76 | _runAnimation(); 77 | } 78 | 79 | Future _runAnimation() async { 80 | await _cardEntranceAnimationController.forward(); 81 | setState(() {}); 82 | } 83 | 84 | @override 85 | void dispose() { 86 | _cardEntranceAnimationController.dispose(); 87 | super.dispose(); 88 | } 89 | 90 | @override 91 | Widget build(BuildContext context) { 92 | return Scaffold( 93 | body: Stack( 94 | children: [ 95 | const AirAsiaBar( 96 | height: 180, 97 | ), 98 | Positioned.fill( 99 | top: MediaQuery.of(context).padding.top + 64, 100 | child: SingleChildScrollView( 101 | child: Column( 102 | children: _buildTickets().toList(), 103 | ), 104 | ), 105 | ) 106 | ], 107 | ), 108 | floatingActionButton: _buildFab(), 109 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, 110 | ); 111 | } 112 | 113 | Iterable _buildTickets() { 114 | return stops.map( 115 | (stop) { 116 | final animation = _ticketAnimations[stop]!; 117 | return AnimatedBuilder( 118 | animation: animation, 119 | builder: (context, child) => Transform.translate( 120 | offset: Offset(0, animation.value), 121 | child: child, 122 | ), 123 | child: Padding( 124 | padding: const EdgeInsets.symmetric( 125 | vertical: 4, 126 | horizontal: 8, 127 | ), 128 | child: TicketCard(stop: stop), 129 | ), 130 | ); 131 | }, 132 | ); 133 | } 134 | 135 | Widget? _buildFab() { 136 | if (_cardEntranceAnimationController.status != AnimationStatus.completed) { 137 | return null; 138 | } 139 | return FloatingActionButton( 140 | onPressed: () => rootNavigatorKey.currentState!.pop(), 141 | child: const Icon(Icons.fingerprint), 142 | ); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /lib/pages/flight_search/ticket_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/flight_search/flight_stop_ticker.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class TicketCard extends StatelessWidget { 5 | const TicketCard({ 6 | super.key, 7 | required this.stop, 8 | }); 9 | 10 | final FlightStopTicket stop; 11 | static const airportNameStyle = TextStyle( 12 | fontSize: 16, 13 | fontWeight: FontWeight.w600, 14 | ); 15 | static const airportShortNameStyle = TextStyle( 16 | fontSize: 36, 17 | fontWeight: FontWeight.w200, 18 | ); 19 | static const flightNumberStyle = TextStyle( 20 | fontSize: 12, 21 | fontWeight: FontWeight.w500, 22 | ); 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return ClipPath( 27 | clipper: TicketClipper(radius: 10), 28 | child: Material( 29 | elevation: 4, 30 | shadowColor: const Color(0x30E5E5E5), 31 | color: Colors.transparent, 32 | child: ClipPath( 33 | clipper: TicketClipper(radius: 12), 34 | child: Card( 35 | elevation: 0, 36 | margin: const EdgeInsets.all(2), 37 | child: _buildCardContent(context), 38 | ), 39 | ), 40 | ), 41 | ); 42 | } 43 | 44 | Widget _buildCardContent(BuildContext context) { 45 | return SizedBox( 46 | height: 104, 47 | child: Row( 48 | children: [ 49 | Expanded( 50 | child: _buildLocation( 51 | name: stop.from, 52 | nameShort: stop.fromShort, 53 | ), 54 | ), 55 | _buildFlightNumber(context), 56 | Expanded( 57 | child: _buildLocation( 58 | name: stop.to, 59 | nameShort: stop.toShort, 60 | ), 61 | ), 62 | ], 63 | ), 64 | ); 65 | } 66 | 67 | Widget _buildFlightNumber(BuildContext context) { 68 | return Column( 69 | mainAxisAlignment: MainAxisAlignment.center, 70 | children: [ 71 | Padding( 72 | padding: const EdgeInsets.only(bottom: 8), 73 | child: Icon( 74 | Icons.airplanemode_active, 75 | color: Theme.of(context).primaryColor, 76 | ), 77 | ), 78 | Text( 79 | stop.flightNumber, 80 | style: flightNumberStyle, 81 | ), 82 | ], 83 | ); 84 | } 85 | 86 | Widget _buildLocation({ 87 | required String name, 88 | required String nameShort, 89 | }) { 90 | return Column( 91 | mainAxisAlignment: MainAxisAlignment.center, 92 | children: [ 93 | Padding( 94 | padding: const EdgeInsets.only(bottom: 8), 95 | child: Text( 96 | name, 97 | style: airportNameStyle, 98 | ), 99 | ), 100 | Text( 101 | nameShort, 102 | style: airportShortNameStyle, 103 | ), 104 | ], 105 | ); 106 | } 107 | } 108 | 109 | class TicketClipper extends CustomClipper { 110 | TicketClipper({ 111 | required this.radius, 112 | }); 113 | 114 | final double radius; 115 | 116 | @override 117 | Path getClip(Size size) { 118 | return Path() 119 | ..lineTo(0, size.height) 120 | ..lineTo(size.width, size.height) 121 | ..lineTo(size.width, 0) 122 | ..addOval(Rect.fromCircle( 123 | center: Offset(0, size.height / 2), 124 | radius: radius, 125 | ),) 126 | ..addOval(Rect.fromCircle( 127 | center: Offset(size.width, size.height / 2), 128 | radius: radius, 129 | ),); 130 | } 131 | 132 | @override 133 | bool shouldReclip(TicketClipper oldClipper) => oldClipper.radius != radius; 134 | } 135 | -------------------------------------------------------------------------------- /lib/pages/home/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/custom/custom_page.dart'; 2 | import 'package:animations_app/pages/flare/flare_page.dart'; 3 | import 'package:animations_app/pages/flight_search/flight_search_page.dart'; 4 | import 'package:animations_app/pages/implicitly_animated/implicitly_animated_page.dart'; 5 | import 'package:animations_app/pages/transition/transition_page.dart'; 6 | import 'package:animations_app/widget/app_list_tile.dart'; 7 | import 'package:animations_app/widget/app_scaffold.dart'; 8 | import 'package:flutter/material.dart'; 9 | 10 | class HomePage extends StatelessWidget { 11 | const HomePage({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return AppScaffold( 16 | title: 'Animation', 17 | child: ListView( 18 | children: const [ 19 | AppListTile( 20 | title: 'ImplicitlyAnimated', 21 | nextRouteName: ImplicitlyAnimatedPage.routeName, 22 | ), 23 | AppListTile( 24 | title: 'Transition', 25 | nextRouteName: TransitionPage.routeName, 26 | ), 27 | AppListTile( 28 | title: 'Flight Search (Advanced Example)', 29 | nextRouteName: FlightSearchPage.routeName, 30 | ), 31 | AppListTile( 32 | title: 'Custom', 33 | nextRouteName: CustomPage.routeName, 34 | ), 35 | AppListTile( 36 | title: 'Flare', 37 | nextRouteName: FlarePage.routeName, 38 | ), 39 | ], 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_align.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/animation_object.dart'; 2 | import 'package:animations_app/widget/app_scaffold.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class AnimatedAlignPage extends StatefulWidget { 6 | const AnimatedAlignPage({super.key}); 7 | 8 | static const routeName = 'animatedAlign'; 9 | 10 | @override 11 | State createState() => _AnimatedAlignPageState(); 12 | } 13 | 14 | class _AnimatedAlignPageState extends State { 15 | static const _alignments = [ 16 | Alignment.topLeft, 17 | Alignment.topRight, 18 | Alignment.bottomRight, 19 | Alignment.bottomLeft, 20 | ]; 21 | 22 | var _index = 0; 23 | AlignmentGeometry get _alignment => _alignments[_index % _alignments.length]; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return AppScaffold( 28 | title: 'AnimatedAlign', 29 | floatingActionButton: FloatingActionButton( 30 | onPressed: () { 31 | setState(() { 32 | _index++; 33 | }); 34 | }, 35 | child: const Icon(Icons.refresh), 36 | ), 37 | child: AnimatedAlign( 38 | alignment: _alignment, 39 | duration: const Duration(milliseconds: 500), 40 | curve: Curves.easeInOut, 41 | child: const AnimationObject(), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/animation_object.dart'; 2 | import 'package:animations_app/widget/app_scaffold.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class AnimatedContainerPage extends StatefulWidget { 6 | const AnimatedContainerPage({super.key}); 7 | 8 | static const routeName = 'animatedContainer'; 9 | 10 | @override 11 | State createState() => _AnimatedContainerPageState(); 12 | } 13 | 14 | class _AnimatedContainerPageState extends State { 15 | static const _alignments = [ 16 | Alignment.topLeft, 17 | Alignment.topRight, 18 | Alignment.bottomRight, 19 | Alignment.bottomLeft, 20 | ]; 21 | static const _colors = [ 22 | Colors.red, 23 | Colors.green, 24 | Colors.blue, 25 | Colors.yellow, 26 | ]; 27 | 28 | var _index = 0; 29 | AlignmentGeometry get _alignment => _alignments[_index % _alignments.length]; 30 | Color get _color => _colors[_index % _colors.length]; 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return AppScaffold( 35 | title: 'AnimatedContainer', 36 | floatingActionButton: FloatingActionButton( 37 | onPressed: () { 38 | setState(() { 39 | _index++; 40 | }); 41 | }, 42 | child: const Icon(Icons.refresh), 43 | ), 44 | child: AnimatedContainer( 45 | alignment: _alignment, 46 | color: _color, 47 | margin: EdgeInsets.all(20 * ((3 - _index).toDouble() % 4)), 48 | padding: EdgeInsets.all(20 * (_index.toDouble() % 4)), 49 | duration: const Duration(milliseconds: 500), 50 | curve: Curves.easeInOut, 51 | child: const AnimationObject(), 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_cross_fade.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | // MEMO: ImplicitlyAnimatedWidgetの派生クラスではない 5 | class AnimatedCrossFadePage extends StatefulWidget { 6 | const AnimatedCrossFadePage({super.key}); 7 | 8 | static const routeName = 'animatedCrossFade'; 9 | 10 | @override 11 | State createState() => _AnimatedCrossFadePageState(); 12 | } 13 | 14 | class _AnimatedCrossFadePageState extends State { 15 | var _showFirst = true; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return AppScaffold( 20 | title: 'AnimatedCrossFade', 21 | floatingActionButton: FloatingActionButton( 22 | onPressed: () { 23 | setState(() { 24 | _showFirst = !_showFirst; 25 | }); 26 | }, 27 | child: const Icon(Icons.refresh), 28 | ), 29 | child: Center( 30 | child: AnimatedCrossFade( 31 | firstChild: Image.asset('assets/love.png'), 32 | secondChild: Image.asset('assets/love_gray.png'), 33 | duration: const Duration(milliseconds: 500), 34 | crossFadeState: 35 | _showFirst ? CrossFadeState.showFirst : CrossFadeState.showSecond, 36 | ), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_default_text_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedDefaultTextStylePage extends StatefulWidget { 5 | const AnimatedDefaultTextStylePage({super.key}); 6 | 7 | static const routeName = 'AnimatedDefaultTextStyle'; 8 | 9 | @override 10 | State createState() => 11 | _AnimatedDefaultTextStylePageState(); 12 | } 13 | 14 | class _AnimatedDefaultTextStylePageState 15 | extends State { 16 | var _index = 0; 17 | TextStyle get _textStyle { 18 | switch (_index % 4) { 19 | case 0: 20 | return Theme.of(context) 21 | .textTheme 22 | .headline4! 23 | .copyWith(color: Colors.red); 24 | case 1: 25 | return Theme.of(context) 26 | .textTheme 27 | .headline3! 28 | .copyWith(color: Colors.green); 29 | case 2: 30 | return Theme.of(context) 31 | .textTheme 32 | .headline2! 33 | .copyWith(color: Colors.blue); 34 | case 3: 35 | return Theme.of(context) 36 | .textTheme 37 | .headline1! 38 | .copyWith(color: Colors.orange); 39 | } 40 | assert(false); 41 | return const TextStyle(); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return AppScaffold( 47 | title: 'AnimatedDefaultTextStyle', 48 | floatingActionButton: FloatingActionButton( 49 | onPressed: () { 50 | setState(() { 51 | _index++; 52 | }); 53 | }, 54 | child: const Icon(Icons.refresh), 55 | ), 56 | child: Center( 57 | child: AnimatedDefaultTextStyle( 58 | duration: const Duration(milliseconds: 500), 59 | curve: Curves.easeInOut, 60 | style: _textStyle, 61 | child: const Text('Flutter'), 62 | ), 63 | ), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | // MEMO: ImplicitlyAnimatedWidgetの派生クラスではない 5 | class AnimatedIconPage extends StatefulWidget { 6 | const AnimatedIconPage({super.key}); 7 | 8 | static const routeName = 'AnimatedIcon'; 9 | 10 | @override 11 | State createState() => _AnimatedIconPageState(); 12 | } 13 | 14 | class _AnimatedIconPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 500), 19 | ); 20 | var _playButtonEnabled = true; 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | Future _play() async { 29 | setState(() { 30 | _playButtonEnabled = false; 31 | }); 32 | await _animationController.forward(from: 0); 33 | await Future.delayed(const Duration(seconds: 2)); 34 | await _animationController.reverse(); 35 | setState(() { 36 | _playButtonEnabled = true; 37 | }); 38 | } 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | return AppScaffold( 43 | title: 'AnimatedIcon', 44 | floatingActionButton: _playButtonEnabled 45 | ? FloatingActionButton( 46 | onPressed: _play, 47 | child: const Icon(Icons.play_arrow), 48 | ) 49 | : null, 50 | child: Center( 51 | child: Row( 52 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 53 | children: [ 54 | _buildAnimatedIcon(AnimatedIcons.add_event, label: 'add_event'), 55 | _buildAnimatedIcon(AnimatedIcons.pause_play, label: 'pause_play'), 56 | _buildAnimatedIcon(AnimatedIcons.close_menu, label: 'close_menu'), 57 | _buildAnimatedIcon( 58 | AnimatedIcons.ellipsis_search, 59 | label: 'ellipsis_search', 60 | ), 61 | ], 62 | ), 63 | ), 64 | ); 65 | } 66 | 67 | Widget _buildAnimatedIcon(AnimatedIconData icon, {required String label}) { 68 | return Column( 69 | mainAxisAlignment: MainAxisAlignment.center, 70 | children: [ 71 | AnimatedIcon( 72 | icon: icon, 73 | progress: _animationController, 74 | ), 75 | const SizedBox(height: 8), 76 | Text(label) 77 | ], 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_list.dart: -------------------------------------------------------------------------------- 1 | // TODO(mono): ちょっと面倒で未実装 2 | // 別サンプル: https://github.com/TaskShare/taskshare-flutter/blob/master/lib/screens/task/list/task_list.dart 3 | import 'package:animations_app/widget/app_scaffold.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AnimatedListPage extends StatefulWidget { 7 | const AnimatedListPage({super.key}); 8 | 9 | static const routeName = 'AnimatedList'; 10 | 11 | @override 12 | State createState() => _AnimatedListPageState(); 13 | } 14 | 15 | class _AnimatedListPageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return AppScaffold( 19 | title: 'AnimatedList(WIP)', 20 | floatingActionButton: FloatingActionButton( 21 | onPressed: () {}, 22 | child: const Icon(Icons.refresh), 23 | ), 24 | child: Container(), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_modal_barrier.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedModalBarrierPage extends StatefulWidget { 5 | const AnimatedModalBarrierPage({super.key}); 6 | 7 | static const routeName = 'AnimatedModalBarrier'; 8 | 9 | @override 10 | State createState() { 11 | return _AnimatedModalBarrierPageState(); 12 | } 13 | } 14 | 15 | class _AnimatedModalBarrierPageState extends State { 16 | var _dismissible = false; 17 | @override 18 | Widget build(BuildContext context) { 19 | return AppScaffold( 20 | title: 'AnimatedModalBarrier', 21 | child: Center( 22 | child: Column( 23 | mainAxisAlignment: MainAxisAlignment.center, 24 | children: [ 25 | ElevatedButton( 26 | onPressed: () { 27 | Navigator.of(context).push( 28 | MyPageRoute( 29 | page: _ModalPage(), 30 | dismissible: _dismissible, 31 | ), 32 | ); 33 | }, 34 | child: const Text('Open Modal View'), 35 | ), 36 | Row( 37 | mainAxisAlignment: MainAxisAlignment.center, 38 | children: [ 39 | const Text('dismissible'), 40 | Switch( 41 | onChanged: (value) { 42 | setState(() { 43 | _dismissible = value; 44 | }); 45 | }, 46 | value: _dismissible, 47 | ), 48 | ], 49 | ), 50 | ], 51 | ), 52 | ), 53 | ); 54 | } 55 | } 56 | 57 | class MyPageRoute extends TransitionRoute { 58 | MyPageRoute({ 59 | required this.page, 60 | required this.dismissible, 61 | }); 62 | 63 | final Widget page; 64 | final bool dismissible; 65 | 66 | @override 67 | Iterable createOverlayEntries() { 68 | return [ 69 | OverlayEntry(builder: _buildModalBarrier), 70 | OverlayEntry(builder: (context) => Center(child: page)) 71 | ]; 72 | } 73 | 74 | @override 75 | bool get opaque => false; 76 | 77 | @override 78 | Duration get transitionDuration => const Duration(milliseconds: 500); 79 | 80 | Widget _buildModalBarrier(BuildContext context) { 81 | final animation = this.animation!; 82 | return IgnorePointer( 83 | // changedInternalState is called when this updates 84 | ignoring: animation.status == AnimationStatus.reverse || 85 | // dismissed is possible when doing a manual pop gesture 86 | animation.status == AnimationStatus.dismissed, 87 | child: AnimatedModalBarrier( 88 | color: animation.drive( 89 | ColorTween( 90 | begin: Colors.transparent, 91 | end: Colors.black.withAlpha(80), 92 | ), 93 | ), 94 | dismissible: dismissible, 95 | ), 96 | ); 97 | } 98 | } 99 | 100 | class _ModalPage extends StatelessWidget { 101 | @override 102 | Widget build(BuildContext context) { 103 | return Card( 104 | child: Padding( 105 | padding: const EdgeInsets.all(16), 106 | child: Column( 107 | mainAxisSize: MainAxisSize.min, 108 | children: [ 109 | const Text('( ´・‿・`)'), 110 | const SizedBox(height: 8), 111 | ElevatedButton( 112 | onPressed: () { 113 | Navigator.of(context).pop(); 114 | }, 115 | child: const Text('Close'), 116 | ) 117 | ], 118 | ), 119 | ), 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_opacity.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedOpacityPage extends StatefulWidget { 5 | const AnimatedOpacityPage({super.key}); 6 | 7 | static const routeName = 'animatedOpacity'; 8 | 9 | @override 10 | State createState() => _AnimatedOpacityPageState(); 11 | } 12 | 13 | class _AnimatedOpacityPageState extends State { 14 | var _opaque = true; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return AppScaffold( 19 | title: 'AnimatedOpacity', 20 | floatingActionButton: FloatingActionButton( 21 | onPressed: () { 22 | setState(() { 23 | _opaque = !_opaque; 24 | }); 25 | }, 26 | child: const Icon(Icons.refresh), 27 | ), 28 | child: Center( 29 | child: AnimatedOpacity( 30 | duration: const Duration(milliseconds: 500), 31 | opacity: _opaque ? 1 : 0.3, 32 | child: Image.asset('assets/love.png'), 33 | ), 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_padding.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedPaddingPage extends StatefulWidget { 5 | const AnimatedPaddingPage({super.key}); 6 | 7 | static const routeName = 'animatedPadding'; 8 | 9 | @override 10 | State createState() => _AnimatedPaddingPageState(); 11 | } 12 | 13 | class _AnimatedPaddingPageState extends State { 14 | var _hasPadding = false; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return AppScaffold( 19 | title: 'AnimatedPadding', 20 | floatingActionButton: FloatingActionButton( 21 | onPressed: () { 22 | setState(() { 23 | _hasPadding = !_hasPadding; 24 | }); 25 | }, 26 | child: const Icon(Icons.refresh), 27 | ), 28 | child: Center( 29 | child: AnimatedPadding( 30 | duration: const Duration(milliseconds: 500), 31 | padding: EdgeInsets.all(_hasPadding ? 64 : 0), 32 | child: Image.asset('assets/love.png'), 33 | ), 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_physical_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedPhysicalModelPage extends StatefulWidget { 5 | const AnimatedPhysicalModelPage({super.key}); 6 | 7 | static const routeName = 'animatedPhysicalModel'; 8 | 9 | @override 10 | State createState() => 11 | _AnimatedPhysicalModelPageState(); 12 | } 13 | 14 | class _AnimatedPhysicalModelPageState extends State { 15 | var _hasElevation = false; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return AppScaffold( 20 | title: 'AnimatedPhysicalModel', 21 | floatingActionButton: FloatingActionButton( 22 | onPressed: () { 23 | setState(() { 24 | _hasElevation = !_hasElevation; 25 | }); 26 | }, 27 | child: const Icon(Icons.refresh), 28 | ), 29 | child: Center( 30 | child: Padding( 31 | padding: const EdgeInsets.all(32), 32 | child: AnimatedPhysicalModel( 33 | color: Colors.purple, 34 | shadowColor: Colors.black, 35 | shape: BoxShape.rectangle, 36 | duration: const Duration(milliseconds: 500), 37 | elevation: _hasElevation ? 16 : 0, 38 | child: Padding( 39 | padding: const EdgeInsets.all(8), 40 | child: Image.asset('assets/love.png'), 41 | ), 42 | ), 43 | ), 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_positioned.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedPositionedPage extends StatefulWidget { 5 | const AnimatedPositionedPage({super.key}); 6 | 7 | static const routeName = 'animatedPositioned'; 8 | 9 | @override 10 | State createState() => _AnimatedPositionedPageState(); 11 | } 12 | 13 | class _AnimatedPositionedPageState extends State { 14 | var _shrinked = true; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return AppScaffold( 19 | title: 'AnimatedPositioned', 20 | floatingActionButton: FloatingActionButton( 21 | onPressed: () { 22 | setState(() { 23 | _shrinked = !_shrinked; 24 | }); 25 | }, 26 | child: const Icon(Icons.refresh), 27 | ), 28 | child: Center( 29 | child: Stack( 30 | children: [ 31 | Image.asset('assets/love_gray.png'), 32 | // nullと数値指定の変化のアニメーションには非対応なので注意 33 | AnimatedPositioned( 34 | top: 0, 35 | left: 0, 36 | width: _shrinked ? 50 : 300, 37 | duration: const Duration(milliseconds: 500), 38 | curve: Curves.easeInOut, 39 | child: Image.asset('assets/love.png'), 40 | ), 41 | ], 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_positioned_directional.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedPositionedDirectionalPage extends StatefulWidget { 5 | const AnimatedPositionedDirectionalPage({super.key}); 6 | 7 | static const routeName = 'animatedPositionedDirectional'; 8 | 9 | @override 10 | State createState() => 11 | _AnimatedPositionedDirectionalPageState(); 12 | } 13 | 14 | class _AnimatedPositionedDirectionalPageState 15 | extends State { 16 | var _shrinked = true; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return AppScaffold( 21 | title: 'AnimatedPositionedDirectional', 22 | floatingActionButton: FloatingActionButton( 23 | onPressed: () { 24 | setState(() { 25 | _shrinked = !_shrinked; 26 | }); 27 | }, 28 | child: const Icon(Icons.refresh), 29 | ), 30 | child: Center( 31 | child: Stack( 32 | children: [ 33 | Image.asset('assets/love_gray.png'), 34 | // nullと数値指定の変化のアニメーションには非対応なので注意 35 | Directionality( 36 | textDirection: TextDirection.rtl, 37 | child: AnimatedPositionedDirectional( 38 | top: 0, 39 | start: 0, 40 | width: _shrinked ? 50 : 300, 41 | duration: const Duration(milliseconds: 500), 42 | curve: Curves.easeInOut, 43 | child: Image.asset('assets/love.png'), 44 | ), 45 | ), 46 | ], 47 | ), 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_size_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | // MEMO: ImplicitlyAnimatedWidgetの派生クラスではない 5 | /// See: https://medium.com/flutter-community/flutter-working-with-animatedsize-35253ff8f16a 6 | class AnimatedSizePage extends StatefulWidget { 7 | const AnimatedSizePage({super.key}); 8 | 9 | static const routeName = 'animatedSize'; 10 | 11 | @override 12 | State createState() => _AnimatedSizePageState(); 13 | } 14 | 15 | class _AnimatedSizePageState extends State { 16 | var _isSmall = true; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return AppScaffold( 21 | title: 'AnimatedSize', 22 | floatingActionButton: FloatingActionButton( 23 | onPressed: () { 24 | setState(() { 25 | _isSmall = !_isSmall; 26 | }); 27 | }, 28 | child: const Icon(Icons.refresh), 29 | ), 30 | child: Center( 31 | child: AnimatedSize( 32 | duration: const Duration(milliseconds: 500), 33 | child: SizedBox( 34 | width: _isSmall ? 100 : 200, 35 | height: _isSmall ? 100 : 200, 36 | child: Image.asset('assets/love.png'), 37 | ), 38 | ), 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_switcher_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | // MEMO: ImplicitlyAnimatedWidgetの派生クラスではない 5 | /// See: https://medium.com/flutter-community/what-do-you-know-about-aniamtedswitcher-53cc3a4bebb8 6 | class AnimatedSwitcherPage extends StatefulWidget { 7 | const AnimatedSwitcherPage({super.key}); 8 | 9 | static const routeName = 'animatedSwitcher'; 10 | 11 | @override 12 | State createState() => _AnimatedSwitcherPageState(); 13 | } 14 | 15 | class _AnimatedSwitcherPageState extends State { 16 | var _isDefaultImage = true; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return AppScaffold( 21 | title: 'AnimatedSwitcher', 22 | floatingActionButton: FloatingActionButton( 23 | onPressed: () { 24 | setState(() { 25 | _isDefaultImage = !_isDefaultImage; 26 | }); 27 | }, 28 | child: const Icon(Icons.refresh), 29 | ), 30 | child: Center( 31 | child: AnimatedSwitcher( 32 | duration: const Duration(milliseconds: 500), 33 | child: Image.asset( 34 | 'assets/love${_isDefaultImage ? '' : '_gray'}.png', 35 | key: UniqueKey(), 36 | ), 37 | ), 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/animated_theme_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AnimatedThemePage extends StatefulWidget { 5 | const AnimatedThemePage({super.key}); 6 | 7 | static const routeName = 'animatedTheme'; 8 | 9 | @override 10 | State createState() => _AnimatedThemePageState(); 11 | } 12 | 13 | class _AnimatedThemePageState extends State { 14 | var _isLightTheme = true; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return AppScaffold( 19 | title: 'AnimatedTheme', 20 | floatingActionButton: FloatingActionButton( 21 | onPressed: () { 22 | setState(() { 23 | _isLightTheme = !_isLightTheme; 24 | }); 25 | }, 26 | child: const Icon(Icons.refresh), 27 | ), 28 | child: Center( 29 | child: AnimatedTheme( 30 | data: _isLightTheme ? ThemeData.light() : ThemeData.dark(), 31 | duration: const Duration(milliseconds: 500), 32 | child: const Card( 33 | child: Padding( 34 | padding: EdgeInsets.all(16), 35 | child: Text( 36 | 'hello', 37 | style: TextStyle(fontSize: 24), 38 | ), 39 | ), 40 | ), 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/fade_in_image_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/app_scaffold.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:transparent_image/transparent_image.dart'; 4 | 5 | class FadeInImagePage extends StatefulWidget { 6 | const FadeInImagePage({super.key}); 7 | 8 | static const routeName = 'FadeInImage'; 9 | 10 | @override 11 | State createState() => _FadeInImagePageState(); 12 | } 13 | 14 | class _FadeInImagePageState extends State { 15 | var _index = 0; 16 | @override 17 | Widget build(BuildContext context) { 18 | return AppScaffold( 19 | title: 'FadeInImage', 20 | floatingActionButton: FloatingActionButton( 21 | onPressed: () { 22 | setState(() => _index++); 23 | }, 24 | child: const Icon(Icons.refresh), 25 | ), 26 | child: _index.isEven 27 | ? Stack( 28 | children: [ 29 | const Center(child: CircularProgressIndicator()), 30 | Center( 31 | child: FadeInImage.memoryNetwork( 32 | placeholder: kTransparentImage, 33 | image: 'https://picsum.photos/400?image=$_index', 34 | fadeInCurve: Curves.easeInOut, 35 | ), 36 | /* 37 | child: FadeInImage.assetNetwork( 38 | placeholder: 'assets/love_gray.png', 39 | image: 'https://picsum.photos/400?image=$index', 40 | fadeInCurve: Curves.easeInOut, 41 | ), 42 | */ 43 | ), 44 | ], 45 | ) 46 | : const Center( 47 | child: Text('Press button one more.'), 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/hero_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/widget/widget.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | const _heroTagImage = 'image'; 5 | const _heroTagText = 'text'; 6 | final _image = Image.asset('assets/love.png'); 7 | const _text = 'I am a dog 🐶'; 8 | 9 | class HeroPage extends StatelessWidget { 10 | const HeroPage({super.key}); 11 | 12 | static const routeName = 'Hero'; 13 | @override 14 | Widget build(BuildContext context) { 15 | return AppScaffold( 16 | title: 'Hero', 17 | child: InkWell( 18 | onTap: () => Navigator.of(context).push( 19 | MaterialPageRoute(builder: (context) => const DetailScreen()), 20 | ), 21 | child: SizedBox( 22 | height: 60, 23 | child: Row( 24 | children: [ 25 | Hero( 26 | tag: _heroTagImage, 27 | child: _image, 28 | ), 29 | const SizedBox(width: 16), 30 | const Hero( 31 | tag: _heroTagText, 32 | child: Material( 33 | color: Colors.transparent, 34 | child: Text(_text), 35 | ), 36 | ), 37 | ], 38 | ), 39 | ), 40 | ), 41 | ); 42 | } 43 | } 44 | 45 | class DetailScreen extends StatelessWidget { 46 | const DetailScreen({super.key}); 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return AppScaffold( 51 | title: 'Detail', 52 | child: Column( 53 | children: [ 54 | Hero( 55 | tag: _heroTagImage, 56 | child: _image, 57 | ), 58 | const SizedBox(height: 16), 59 | const Hero( 60 | tag: _heroTagText, 61 | child: Material( 62 | color: Colors.transparent, 63 | child: Text( 64 | _text, 65 | style: TextStyle(fontSize: 32), 66 | ), 67 | ), 68 | ), 69 | ], 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/pages/implicitly_animated/implicitly_animated_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/implicitly_animated/animated_align.dart'; 2 | import 'package:animations_app/pages/implicitly_animated/animated_container.dart'; 3 | import 'package:animations_app/pages/implicitly_animated/animated_cross_fade.dart'; 4 | import 'package:animations_app/pages/implicitly_animated/animated_default_text_style.dart'; 5 | import 'package:animations_app/pages/implicitly_animated/animated_icon.dart'; 6 | import 'package:animations_app/pages/implicitly_animated/animated_list.dart'; 7 | import 'package:animations_app/pages/implicitly_animated/animated_modal_barrier.dart'; 8 | import 'package:animations_app/pages/implicitly_animated/animated_opacity.dart'; 9 | import 'package:animations_app/pages/implicitly_animated/animated_padding.dart'; 10 | import 'package:animations_app/pages/implicitly_animated/animated_physical_model.dart'; 11 | import 'package:animations_app/pages/implicitly_animated/animated_positioned.dart'; 12 | import 'package:animations_app/pages/implicitly_animated/animated_positioned_directional.dart'; 13 | import 'package:animations_app/pages/implicitly_animated/animated_size_page.dart'; 14 | import 'package:animations_app/pages/implicitly_animated/animated_switcher_page.dart'; 15 | import 'package:animations_app/pages/implicitly_animated/animated_theme_page.dart'; 16 | import 'package:animations_app/pages/implicitly_animated/fade_in_image_page.dart'; 17 | import 'package:animations_app/pages/implicitly_animated/hero_page.dart'; 18 | import 'package:animations_app/widget/app_list_tile.dart'; 19 | import 'package:animations_app/widget/app_scaffold.dart'; 20 | import 'package:flutter/material.dart'; 21 | 22 | /// Examples of [ImplicitlyAnimatedWidget] 23 | class ImplicitlyAnimatedPage extends StatelessWidget { 24 | const ImplicitlyAnimatedPage({super.key}); 25 | 26 | static const routeName = 'implicitlyAnimated'; 27 | @override 28 | Widget build(BuildContext context) { 29 | return AppScaffold( 30 | title: 'Animated', 31 | child: ListView( 32 | children: const [ 33 | AppListTile( 34 | title: 'AnimatedAlign', 35 | nextRouteName: AnimatedAlignPage.routeName, 36 | ), 37 | AppListTile( 38 | title: 'AnimatedContainer', 39 | nextRouteName: AnimatedContainerPage.routeName, 40 | ), 41 | AppListTile( 42 | title: 'AnimatedCrossFade', 43 | nextRouteName: AnimatedCrossFadePage.routeName, 44 | ), 45 | AppListTile( 46 | title: 'AnimatedDefaultTextStyle', 47 | nextRouteName: AnimatedDefaultTextStylePage.routeName, 48 | ), 49 | AppListTile( 50 | title: 'AnimatedIcon', 51 | nextRouteName: AnimatedIconPage.routeName, 52 | ), 53 | AppListTile( 54 | title: 'AnimatedList', 55 | nextRouteName: AnimatedListPage.routeName, 56 | ), 57 | AppListTile( 58 | title: 'AnimatedModalBarrier', 59 | nextRouteName: AnimatedModalBarrierPage.routeName, 60 | ), 61 | AppListTile( 62 | title: 'AnimatedOpacity', 63 | nextRouteName: AnimatedOpacityPage.routeName, 64 | ), 65 | AppListTile( 66 | title: 'AnimatedPadding', 67 | nextRouteName: AnimatedPaddingPage.routeName, 68 | ), 69 | AppListTile( 70 | title: 'AnimatedPhysicalModel', 71 | nextRouteName: AnimatedPhysicalModelPage.routeName, 72 | ), 73 | AppListTile( 74 | title: 'AnimatedPositioned', 75 | nextRouteName: AnimatedPositionedPage.routeName, 76 | ), 77 | AppListTile( 78 | title: 'AnimatedPositionedDirectional', 79 | nextRouteName: AnimatedPositionedDirectionalPage.routeName, 80 | ), 81 | AppListTile( 82 | title: 'AnimatedTheme', 83 | nextRouteName: AnimatedThemePage.routeName, 84 | ), 85 | AppListTile( 86 | title: 'AnimatedSwitcher', 87 | nextRouteName: AnimatedSwitcherPage.routeName, 88 | ), 89 | AppListTile( 90 | title: 'AnimatedSize', 91 | nextRouteName: AnimatedSizePage.routeName, 92 | ), 93 | AppListTile( 94 | title: 'Hero', 95 | nextRouteName: HeroPage.routeName, 96 | ), 97 | AppListTile( 98 | title: 'FadeInImage', 99 | nextRouteName: FadeInImagePage.routeName, 100 | ), 101 | ], 102 | ), 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/pages/transition/align_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class AlignTransitionPage extends StatefulWidget { 6 | const AlignTransitionPage({super.key}); 7 | 8 | static const routeName = 'AlignTransition'; 9 | 10 | @override 11 | State createState() => _AlignTransitionPageState(); 12 | } 13 | 14 | class _AlignTransitionPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 500), 19 | ); 20 | var _isMoved = false; 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return AppScaffold( 31 | title: 'AlignTransition', 32 | floatingActionButton: FloatingActionButton( 33 | onPressed: () { 34 | if (_isMoved) { 35 | _animationController.reverse(); 36 | } else { 37 | _animationController.forward(); 38 | } 39 | _isMoved = !_isMoved; 40 | }, 41 | child: const Icon(Icons.refresh), 42 | ), 43 | child: Stack( 44 | children: [ 45 | AlignTransition( 46 | alignment: _animationController 47 | .drive( 48 | CurveTween( 49 | curve: const Interval(0.4, 1, curve: Curves.fastOutSlowIn), 50 | ), 51 | ) 52 | .drive( 53 | AlignmentTween( 54 | begin: Alignment.topLeft, 55 | end: Alignment.bottomRight, 56 | ), 57 | ), 58 | child: Image.asset( 59 | 'assets/love_gray.png', 60 | width: 200, 61 | ), 62 | ), 63 | AlignTransition( 64 | alignment: _animationController 65 | .drive( 66 | CurveTween( 67 | curve: const Interval(0, 0.6, curve: Curves.fastOutSlowIn), 68 | ), 69 | ) 70 | .drive( 71 | AlignmentTween( 72 | begin: Alignment.topLeft, 73 | end: Alignment.bottomRight, 74 | ), 75 | ), 76 | child: Image.asset( 77 | 'assets/love.png', 78 | width: 200, 79 | ), 80 | ), 81 | ], 82 | ), 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/pages/transition/decorated_box_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class DecoratedBoxTransitionPage extends StatefulWidget { 6 | const DecoratedBoxTransitionPage({super.key}); 7 | 8 | static const routeName = 'DecoratedBoxTransition'; 9 | 10 | @override 11 | State createState() => 12 | _DecoratedBoxTransitionPageState(); 13 | } 14 | 15 | class _DecoratedBoxTransitionPageState extends State 16 | with SingleTickerProviderStateMixin { 17 | late final AnimationController _animationController = AnimationController( 18 | vsync: this, 19 | duration: const Duration(milliseconds: 500), 20 | ); 21 | var _isScaledUp = false; 22 | 23 | @override 24 | void dispose() { 25 | _animationController.dispose(); 26 | super.dispose(); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return AppScaffold( 32 | title: 'DecoratedBoxTransition', 33 | floatingActionButton: FloatingActionButton( 34 | onPressed: () { 35 | if (_isScaledUp) { 36 | _animationController.reverse(); 37 | } else { 38 | _animationController.forward(); 39 | } 40 | _isScaledUp = !_isScaledUp; 41 | }, 42 | child: const Icon(Icons.refresh), 43 | ), 44 | child: Center( 45 | child: DecoratedBoxTransition( 46 | decoration: _animationController 47 | .drive( 48 | CurveTween(curve: Curves.fastOutSlowIn), 49 | ) 50 | .drive( 51 | DecorationTween( 52 | begin: const FlutterLogoDecoration( 53 | style: FlutterLogoStyle.horizontal, 54 | ), 55 | end: const FlutterLogoDecoration( 56 | style: FlutterLogoStyle.stacked, 57 | ), 58 | ), 59 | ), 60 | child: const SizedBox( 61 | width: 200, 62 | height: 200, 63 | ), 64 | ), 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/pages/transition/default_text_style_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class DefaultTextStyleTransitionPage extends StatefulWidget { 6 | const DefaultTextStyleTransitionPage({super.key}); 7 | 8 | static const routeName = 'DefaultTextStyleTransition'; 9 | 10 | @override 11 | State createState() => 12 | _DefaultTextStyleTransitionPageState(); 13 | } 14 | 15 | class _DefaultTextStyleTransitionPageState 16 | extends State 17 | with SingleTickerProviderStateMixin { 18 | late final AnimationController _animationController = AnimationController( 19 | vsync: this, 20 | duration: const Duration(milliseconds: 500), 21 | ); 22 | var _isScaledUp = false; 23 | 24 | @override 25 | void dispose() { 26 | _animationController.dispose(); 27 | super.dispose(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return AppScaffold( 33 | title: 'DefaultTextStyleTransition', 34 | floatingActionButton: FloatingActionButton( 35 | onPressed: () { 36 | if (_isScaledUp) { 37 | _animationController.reverse(); 38 | } else { 39 | _animationController.forward(); 40 | } 41 | _isScaledUp = !_isScaledUp; 42 | }, 43 | child: const Icon(Icons.refresh), 44 | ), 45 | child: DefaultTextStyleTransition( 46 | style: _animationController 47 | .drive( 48 | CurveTween(curve: Curves.fastOutSlowIn), 49 | ) 50 | .drive( 51 | TextStyleTween( 52 | begin: Theme.of(context).textTheme.headline4, 53 | end: Theme.of(context).textTheme.headline1, 54 | ), 55 | ), 56 | child: const Center(child: Text('Flutter')), 57 | ), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/pages/transition/fade_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class FadeTransitionPage extends StatefulWidget { 6 | const FadeTransitionPage({super.key}); 7 | 8 | static const routeName = 'FadeTransition'; 9 | 10 | @override 11 | State createState() => _FadeTransitionPageState(); 12 | } 13 | 14 | class _FadeTransitionPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 500), 19 | ); 20 | var _isScaledUp = false; 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | final height = MediaQuery.of(context).size.width / 2; 31 | return AppScaffold( 32 | title: 'FadeTransition', 33 | floatingActionButton: FloatingActionButton( 34 | onPressed: () { 35 | if (_isScaledUp) { 36 | _animationController.reverse(); 37 | } else { 38 | _animationController.forward(); 39 | } 40 | _isScaledUp = !_isScaledUp; 41 | }, 42 | child: const Icon(Icons.refresh), 43 | ), 44 | child: Column( 45 | children: [ 46 | SizedBox( 47 | height: height, 48 | child: Row( 49 | children: [ 50 | _buildContent(0), 51 | _buildContent(0.2), 52 | ], 53 | ), 54 | ), 55 | SizedBox( 56 | height: height, 57 | child: Row( 58 | children: [ 59 | _buildContent(0.4), 60 | _buildContent(0.6), 61 | ], 62 | ), 63 | ), 64 | ], 65 | ), 66 | ); 67 | } 68 | 69 | FadeTransition _buildContent(double start) { 70 | return FadeTransition( 71 | opacity: _animationController 72 | .drive( 73 | CurveTween( 74 | curve: Interval( 75 | start, 76 | start + 0.4, 77 | curve: Curves.fastOutSlowIn, 78 | ), 79 | ), 80 | ) 81 | .drive( 82 | Tween( 83 | begin: 0.1, 84 | end: 1, 85 | ), 86 | ), 87 | child: Image.asset('assets/love.png'), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/pages/transition/positioned_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class PositionedTransitionPage extends StatefulWidget { 6 | const PositionedTransitionPage({super.key}); 7 | 8 | static const routeName = 'PositionedTransition'; 9 | 10 | @override 11 | State createState() => 12 | _PositionedTransitionPageState(); 13 | } 14 | 15 | class _PositionedTransitionPageState extends State 16 | with SingleTickerProviderStateMixin { 17 | late final AnimationController _animationController = AnimationController( 18 | vsync: this, 19 | duration: const Duration(milliseconds: 3000), 20 | ); 21 | var _isMoved = false; 22 | 23 | @override 24 | void dispose() { 25 | _animationController.dispose(); 26 | super.dispose(); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return AppScaffold( 32 | title: 'PositionedTransition', 33 | floatingActionButton: FloatingActionButton( 34 | onPressed: () { 35 | if (_isMoved) { 36 | _animationController.reverse(); 37 | } else { 38 | _animationController.forward(); 39 | } 40 | _isMoved = !_isMoved; 41 | }, 42 | child: const Icon(Icons.refresh), 43 | ), 44 | child: Stack( 45 | children: [ 46 | PositionedTransition( 47 | rect: _animationController 48 | .drive( 49 | CurveTween( 50 | curve: Curves.elasticInOut, 51 | ), 52 | ) 53 | .drive( 54 | RelativeRectTween( 55 | begin: const RelativeRect.fromLTRB(10, 10, 200, 400), 56 | end: const RelativeRect.fromLTRB(100, 400, 10, 10), 57 | ), 58 | ), 59 | child: Image.asset( 60 | 'assets/love.png', 61 | fit: BoxFit.cover, 62 | ), 63 | ) 64 | ], 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/pages/transition/relative_positioned_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class RelativePositionedTransitionPage extends StatefulWidget { 6 | const RelativePositionedTransitionPage({super.key}); 7 | 8 | static const routeName = 'RelativePositionedTransition'; 9 | 10 | @override 11 | State createState() => 12 | _RelativePositionedTransitionPageState(); 13 | } 14 | 15 | class _RelativePositionedTransitionPageState 16 | extends State 17 | with SingleTickerProviderStateMixin { 18 | late final AnimationController _animationController = AnimationController( 19 | vsync: this, 20 | duration: const Duration(milliseconds: 3000), 21 | ); 22 | var _isMoved = false; 23 | 24 | @override 25 | void dispose() { 26 | _animationController.dispose(); 27 | super.dispose(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return AppScaffold( 33 | title: 'RelativePositionedTransition', 34 | floatingActionButton: FloatingActionButton( 35 | onPressed: () { 36 | if (_isMoved) { 37 | _animationController.reverse(); 38 | } else { 39 | _animationController.forward(); 40 | } 41 | _isMoved = !_isMoved; 42 | }, 43 | child: const Icon(Icons.refresh), 44 | ), 45 | child: Stack( 46 | children: [ 47 | RelativePositionedTransition( 48 | rect: _animationController 49 | .drive( 50 | CurveTween( 51 | curve: Curves.elasticInOut, 52 | ), 53 | ) 54 | .drive( 55 | RectTween( 56 | begin: const Rect.fromLTRB(10, 10, -100, -400), 57 | end: const Rect.fromLTRB(200, 500, 0, 0), 58 | ), 59 | ), 60 | size: const Size(50, 50), 61 | child: Image.asset( 62 | 'assets/love.png', 63 | fit: BoxFit.cover, 64 | ), 65 | ) 66 | ], 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/pages/transition/rotation_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class RotationTransitionPage extends StatefulWidget { 6 | const RotationTransitionPage({super.key}); 7 | 8 | static const routeName = 'RotationTransition'; 9 | 10 | @override 11 | State createState() => _RotationTransitionPageState(); 12 | } 13 | 14 | class _RotationTransitionPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 3000), 19 | ); 20 | 21 | @override 22 | void dispose() { 23 | _animationController.dispose(); 24 | super.dispose(); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return AppScaffold( 30 | title: 'RotationTransition', 31 | floatingActionButton: FloatingActionButton( 32 | onPressed: () { 33 | _animationController.forward(from: 0); 34 | }, 35 | child: const Icon(Icons.refresh), 36 | ), 37 | child: RotationTransition( 38 | alignment: Alignment.bottomCenter, 39 | turns: _animationController 40 | .drive( 41 | CurveTween( 42 | curve: Curves.elasticOut, 43 | ), 44 | ) 45 | .drive( 46 | Tween( 47 | begin: 0, 48 | end: 1, 49 | ), 50 | ), 51 | child: Image.asset('assets/love.png'), 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/pages/transition/scale_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class ScaleTransitionPage extends StatefulWidget { 6 | const ScaleTransitionPage({super.key}); 7 | 8 | static const routeName = 'ScaleTransition'; 9 | 10 | @override 11 | State createState() => _ScaleTransitionPageState(); 12 | } 13 | 14 | class _ScaleTransitionPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 500), 19 | ); 20 | var _isScaledUp = false; 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return AppScaffold( 31 | title: 'ScaleTransition', 32 | floatingActionButton: FloatingActionButton( 33 | onPressed: () { 34 | if (_isScaledUp) { 35 | _animationController.reverse(); 36 | } else { 37 | _animationController.forward(); 38 | } 39 | _isScaledUp = !_isScaledUp; 40 | }, 41 | child: const Icon(Icons.refresh), 42 | ), 43 | child: Column( 44 | children: [ 45 | ScaleTransition( 46 | alignment: Alignment.bottomCenter, 47 | scale: _animationController 48 | .drive( 49 | CurveTween( 50 | curve: const Interval(0, 0.8, curve: Curves.fastOutSlowIn), 51 | ), 52 | ) 53 | .drive( 54 | Tween( 55 | begin: 0.3, 56 | end: 1, 57 | ), 58 | ), 59 | child: Image.asset('assets/love.png'), 60 | ), 61 | const SizedBox(height: 16), 62 | ScaleTransition( 63 | alignment: Alignment.topCenter, 64 | scale: _animationController 65 | .drive( 66 | CurveTween( 67 | curve: const Interval(0.4, 1, curve: Curves.fastOutSlowIn), 68 | ), 69 | ) 70 | .drive( 71 | Tween( 72 | begin: 0.3, 73 | end: 1, 74 | ), 75 | ), 76 | child: const Text( 77 | 'I am a dog 🐶', 78 | style: TextStyle(fontSize: 32), 79 | ), 80 | ) 81 | ], 82 | ), 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/pages/transition/size_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class SizeTransitionPage extends StatefulWidget { 6 | const SizeTransitionPage({super.key}); 7 | 8 | static const routeName = 'SizeTransition'; 9 | 10 | @override 11 | State createState() => _SizeTransitionPageState(); 12 | } 13 | 14 | class _SizeTransitionPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 500), 19 | ); 20 | var _isScaledUp = false; 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return AppScaffold( 31 | title: 'SizeTransition', 32 | floatingActionButton: FloatingActionButton( 33 | onPressed: () { 34 | if (_isScaledUp) { 35 | _animationController.reverse(); 36 | } else { 37 | _animationController.forward(); 38 | } 39 | _isScaledUp = !_isScaledUp; 40 | }, 41 | child: const Icon(Icons.refresh), 42 | ), 43 | child: SizeTransition( 44 | axisAlignment: -0.3, 45 | sizeFactor: _animationController 46 | .drive( 47 | CurveTween(curve: Curves.fastOutSlowIn), 48 | ) 49 | .drive( 50 | Tween( 51 | begin: 0.2, 52 | end: 1, 53 | ), 54 | ), 55 | child: Image.asset('assets/love.png'), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/pages/transition/slide_transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../widget/app_scaffold.dart'; 4 | 5 | class SlideTransitionPage extends StatefulWidget { 6 | const SlideTransitionPage({super.key}); 7 | 8 | static const routeName = 'slideTransition'; 9 | 10 | @override 11 | State createState() => _SlideTransitionPageState(); 12 | } 13 | 14 | class _SlideTransitionPageState extends State 15 | with SingleTickerProviderStateMixin { 16 | late final AnimationController _animationController = AnimationController( 17 | vsync: this, 18 | duration: const Duration(milliseconds: 500), 19 | ); 20 | 21 | @override 22 | void dispose() { 23 | _animationController.dispose(); 24 | super.dispose(); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return AppScaffold( 30 | title: 'SlideTransition', 31 | child: Stack( 32 | children: [ 33 | _buildContent(), 34 | SlideTransition( 35 | position: _animationController 36 | .drive(CurveTween(curve: Curves.easeInOut)) 37 | .drive( 38 | Tween( 39 | begin: Offset.zero, 40 | end: const Offset(0, -1), 41 | ), 42 | ), 43 | child: _buildTransitionScreen(), 44 | ), 45 | ], 46 | ), 47 | ); 48 | } 49 | 50 | Column _buildContent() { 51 | return Column( 52 | mainAxisAlignment: MainAxisAlignment.center, 53 | children: [ 54 | Image.asset('assets/love.png'), 55 | ElevatedButton( 56 | onPressed: _animationController.reverse, 57 | child: const Text('CLOSE'), 58 | ) 59 | ], 60 | ); 61 | } 62 | 63 | Widget _buildTransitionScreen() { 64 | return SizedBox.expand( 65 | child: ColoredBox( 66 | color: Colors.black, 67 | child: Center( 68 | child: ElevatedButton( 69 | onPressed: _animationController.forward, 70 | child: const Text('OPEN'), 71 | ), 72 | ), 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/pages/transition/transition_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:animations_app/pages/transition/align_transition_page.dart'; 2 | import 'package:animations_app/pages/transition/decorated_box_transition_page.dart'; 3 | import 'package:animations_app/pages/transition/default_text_style_transition_page.dart'; 4 | import 'package:animations_app/pages/transition/fade_transition_page.dart'; 5 | import 'package:animations_app/pages/transition/positioned_transition_page.dart'; 6 | import 'package:animations_app/pages/transition/relative_positioned_transition_page.dart'; 7 | import 'package:animations_app/pages/transition/rotation_transition_page.dart'; 8 | import 'package:animations_app/pages/transition/scale_transition_page.dart'; 9 | import 'package:animations_app/pages/transition/size_transition_page.dart'; 10 | import 'package:animations_app/pages/transition/slide_transition_page.dart'; 11 | import 'package:animations_app/widget/app_list_tile.dart'; 12 | import 'package:animations_app/widget/app_scaffold.dart'; 13 | import 'package:flutter/material.dart'; 14 | 15 | /// Examples of [TransitionPage] 16 | class TransitionPage extends StatelessWidget { 17 | const TransitionPage({super.key}); 18 | 19 | static const routeName = 'TransitionPage'; 20 | @override 21 | Widget build(BuildContext context) { 22 | return AppScaffold( 23 | title: 'TransitionPage', 24 | child: ListView( 25 | children: const [ 26 | AppListTile( 27 | title: 'AlignTransition', 28 | nextRouteName: AlignTransitionPage.routeName, 29 | ), 30 | AppListTile( 31 | title: 'DecoratedBoxTransition', 32 | nextRouteName: DecoratedBoxTransitionPage.routeName, 33 | ), 34 | AppListTile( 35 | title: 'DefaultTextStyleTransition', 36 | nextRouteName: DefaultTextStyleTransitionPage.routeName, 37 | ), 38 | AppListTile( 39 | title: 'FadeTransition', 40 | nextRouteName: FadeTransitionPage.routeName, 41 | ), 42 | AppListTile( 43 | title: 'PositionedTransition', 44 | nextRouteName: PositionedTransitionPage.routeName, 45 | ), 46 | AppListTile( 47 | title: 'RelativePositionedTransition', 48 | nextRouteName: RelativePositionedTransitionPage.routeName, 49 | ), 50 | AppListTile( 51 | title: 'RotationTransition', 52 | nextRouteName: RotationTransitionPage.routeName, 53 | ), 54 | AppListTile( 55 | title: 'ScaleTransition', 56 | nextRouteName: ScaleTransitionPage.routeName, 57 | ), 58 | AppListTile( 59 | title: 'SizeTransition', 60 | nextRouteName: SizeTransitionPage.routeName, 61 | ), 62 | AppListTile( 63 | title: 'SlideTransition', 64 | nextRouteName: SlideTransitionPage.routeName, 65 | ), 66 | ], 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/util/logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:simple_logger/simple_logger.dart'; 2 | 3 | final logger = SimpleLogger() 4 | ..mode = LoggerMode.print 5 | ..setLevel( 6 | Level.FINEST, 7 | includeCallerInfo: true, 8 | ); 9 | -------------------------------------------------------------------------------- /lib/util/util.dart: -------------------------------------------------------------------------------- 1 | export 'logger.dart'; 2 | -------------------------------------------------------------------------------- /lib/widget/animation_object.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:animations_app/util/util.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class AnimationObject extends StatelessWidget { 7 | const AnimationObject({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | logger.info('build'); 12 | return Stack( 13 | children: [ 14 | SizedBox( 15 | width: 120, 16 | height: 120, 17 | child: Image.asset('assets/love.png'), 18 | ), 19 | Positioned( 20 | left: 0, 21 | right: 0, 22 | top: 30, 23 | child: ClipRect( 24 | child: BackdropFilter( 25 | filter: ImageFilter.blur( 26 | sigmaX: 10, 27 | sigmaY: 10, 28 | ), 29 | child: Container( 30 | height: 30, 31 | color: Colors.white.withAlpha(50), 32 | ), 33 | ), 34 | ), 35 | ) 36 | ], 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/widget/app_list_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppListTile extends StatelessWidget { 4 | const AppListTile({ 5 | super.key, 6 | required this.title, 7 | required this.nextRouteName, 8 | }); 9 | 10 | final String title; 11 | final String nextRouteName; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ListTile( 16 | title: Text(title), 17 | onTap: () { 18 | Navigator.of(context).pushNamed(nextRouteName); 19 | }, 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/widget/app_scaffold.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppScaffold extends StatelessWidget { 4 | const AppScaffold({ 5 | super.key, 6 | required this.title, 7 | required this.child, 8 | this.floatingActionButton, 9 | }); 10 | 11 | final String title; 12 | final Widget child; 13 | final FloatingActionButton? floatingActionButton; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scaffold( 18 | appBar: AppBar( 19 | title: Text(title), 20 | ), 21 | body: child, 22 | floatingActionButton: floatingActionButton, 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/widget/widget.dart: -------------------------------------------------------------------------------- 1 | export 'app_scaffold.dart'; 2 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import dynamic_color 9 | import macos_ui 10 | import url_launcher_macos 11 | 12 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 13 | DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) 14 | MacOSUiPlugin.register(with: registry.registrar(forPlugin: "MacOSUiPlugin")) 15 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 16 | } 17 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - dynamic_color (0.0.2): 3 | - FlutterMacOS 4 | - FlutterMacOS (1.0.0) 5 | - macos_ui (0.1.0): 6 | - FlutterMacOS 7 | - url_launcher_macos (0.0.1): 8 | - FlutterMacOS 9 | 10 | DEPENDENCIES: 11 | - dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`) 12 | - FlutterMacOS (from `Flutter/ephemeral`) 13 | - macos_ui (from `Flutter/ephemeral/.symlinks/plugins/macos_ui/macos`) 14 | - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) 15 | 16 | EXTERNAL SOURCES: 17 | dynamic_color: 18 | :path: Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos 19 | FlutterMacOS: 20 | :path: Flutter/ephemeral 21 | macos_ui: 22 | :path: Flutter/ephemeral/.symlinks/plugins/macos_ui/macos 23 | url_launcher_macos: 24 | :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos 25 | 26 | SPEC CHECKSUMS: 27 | dynamic_color: 394d6a888650f8534e029b27d2f8bc5c64e44008 28 | FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 29 | macos_ui: 125c911559d646194386d84c017ad6819122e2db 30 | url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 31 | 32 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c 33 | 34 | COCOAPODS: 1.11.3 35 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 71 | 73 | 79 | 80 | 81 | 82 | 84 | 85 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = animations 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.mono0926.animations 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.mono0926. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: animations_app 2 | description: A new Flutter application. 3 | version: 1.1.0 4 | publish_to: none 5 | environment: 6 | sdk: '>=2.17.0 <3.0.0' 7 | dependencies: 8 | cupertino_icons: any 9 | flare_flutter: any 10 | flutter: 11 | sdk: flutter 12 | keyboard_visibility: 13 | git: 14 | url: https://github.com/spiderion/flutter_keyboard_visibility.git 15 | ref: null_safe 16 | mono_kit: 17 | quiver: any 18 | simple_logger: any 19 | transparent_image: any 20 | dev_dependencies: 21 | flutter_test: 22 | sdk: flutter 23 | pedantic_mono: any 24 | flutter: 25 | uses-material-design: true 26 | assets: 27 | - assets/ 28 | fonts: 29 | - family: NothingYouCouldDo 30 | fonts: 31 | - asset: fonts/NothingYouCouldDo.ttf 32 | -------------------------------------------------------------------------------- /res/values/strings_en.arb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/res/values/strings_en.arb -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | testWidgets('Smoke test', (tester) async {}); 5 | } 6 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mono0926/flutter-animations/b2a53010509e89ac0af3f17d6e91f40bdeb28410/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | animations 27 | 28 | 29 | 30 | 33 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "animations", 3 | "short_name": "animations", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------