Add android_splash_screen (#903)

Adds a Flutter app designed for devices running at least Android 12 that exemplifies how to implement an animated splash screen with the SplashScreen API.
pull/936/head
Camille Simon 3 years ago committed by GitHub
parent b7156523ff
commit fa0b54bb9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,71 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
local.properties
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.gradle
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.packages
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
# Avoid committing generated Javascript files:
*.dart.js
*.info.json # Produced by the --dump-info flag.
*.js # When generated by dart2js. Don't specify *.js if your
# project includes source files written in JavaScript.
*.js_
*.js.deps
*.js.map

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: f4abaa0735eba4dfd8f33f73363911d63931fe03
channel: stable
project_type: app

@ -0,0 +1,35 @@
# Splash Screen Sample
A Flutter app that exemplifies how to implement an animated splash screen for Android devices running at least Android 12, the version that supplies the new [SplashScreen API](https://developer.android.com/about/versions/12/features/splash-screen).
**NOTE:** There is a pub package available to implement static splash screens in your Flutter app: [flutter_native_splash](https://pub.dev/packages/flutter_native_splash).
## Goals
- Demonstrate the compatibility of animated splash screens and Flutter apps running on Android
- Demonstrate the smoothness achievable by a splash screen as a transition to the Flutter UI
## The important bits
### Remove deprecated code
When creating a Flutter app, the Android code generated may include the deprecated implementation of a splash screen. This includes a definition of `io.flutter.embedding.android.SplashScreenDrawable` in the ` /android/app/src/main/AndroidManifest.xml` file and an implementation of `provideSplashScreen()` in the `/android/app/src/main/kotlin/MainActivity.kt` file. Make sure to remove this code.
**NOTE:** This should no longer be a concern as of Flutter 2.5.
### Modify Android build files
In order to support the Android 12 SplashScreen API, you need to:
1. Update the Android `compileSdkVersion` to 31 in the `/android/app/build.gradle` file, and
2. Update the `ext.kotlin_version` to the latest Kotlin extension version (1.5.31 at the time of publication) in the `/android/build.gradle` file.
### Timing the splash screen animation
In order to ensure a smooth transition between the animated splash screen and the Flutter UI displaying for the first time, be sure to handle both the case where the Flutter UI is ready to be displayed before the animation finishes and vice versa. This can be done by overriding `onFlutterUiDisplayed()` and `onFlutterUiNoLongerDisplayed()` in `/android/app/src/main/kotlin/com/example/splash-screen-sample/MainActivity.kt`, the implementation of `FlutterActivity` in this project.
## Questions/Issues
If you have a general question about splash screens or their implementation in Flutter, the best places to go are:
* [Android 12 Splash Screen Documentation](https://developer.android.com/about/versions/12/features/splash-screen)
* [Flutter Guidance on Adding a Splash Screen to Your App](https://flutter.dev/docs/development/ui/advanced/splash-screen?tab=android-splash-alignment-kotlin-tab)
If you run into an issue with the sample itself, please file an issue
in the [main Flutter repo](https://github.com/flutter/flutter/issues).

@ -0,0 +1,19 @@
include: package:flutter_lints/flutter.yaml
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
linter:
rules:
avoid_types_on_closure_parameters: true
avoid_void_async: true
cancel_subscriptions: true
close_sinks: true
directives_ordering: true
package_api_docs: true
package_prefixed_library_names: true
test_types_in_equals: true
throw_in_finally: true
unnecessary_statements: true

@ -0,0 +1,11 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties

@ -0,0 +1,71 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 31
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.splash_screen_sample"
minSdkVersion 21
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.core:core-splashscreen:1.0.0-alpha02"
implementation "androidx.core:core:1.5.0-alpha05"
implementation "androidx.core:core-ktx:1.6.0"
implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
implementation "androidx.core:core-animation:1.0.0-alpha02"
implementation "androidx.interpolator:interpolator:1.0.0"
def appcompat_version = "1.3.1"
implementation "androidx.appcompat:appcompat:$appcompat_version"
// For loading and tinting drawables on older versions of the platform
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
implementation "androidx.constraintlayout:constraintlayout:2.1.0"
}

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.splash_screen_sample">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

@ -0,0 +1,41 @@
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.splash_screen_sample">
<application
android:label="splash_screen_sample"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/LaunchTheme"
android:launchMode="singleTop"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

@ -0,0 +1,211 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.splash_screen_sample
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.os.Bundle
import android.transition.AutoTransition
import android.transition.Transition
import android.transition.TransitionManager
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.View
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.animation.doOnEnd
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.splashscreen.SplashScreenViewProvider
import androidx.core.view.postDelayed
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity() {
var flutterUIReady : Boolean = false
var initialAnimationFinished : Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This activity will be handling the splash screen transition.
val splashScreen = installSplashScreen()
// The splash screen goes edge to edge, so for a smooth transition to our app, also
// want to draw edge to edge.
WindowCompat.setDecorFitsSystemWindows(window, false)
val insetsController = WindowCompat.getInsetsController(window, window.decorView)
insetsController?.isAppearanceLightNavigationBars = true
insetsController?.isAppearanceLightStatusBars = true
// The content view needs to be set before calling setOnExitAnimationListener
// to ensure that the SplashScreenView is attached to the right view root.
val rootLayout = findViewById(android.R.id.content) as FrameLayout
View.inflate(this, R.layout.main_activity_2, rootLayout)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.container)) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(insets.left, insets.top, insets.right, insets.bottom)
windowInsets.inset(insets)
}
// Setting an OnExitAnimationListener on the splash screen indicates
// to the system that the application will handle the exit animation.
// The listener will be called once the app is ready.
splashScreen.setOnExitAnimationListener { splashScreenViewProvider ->
onSplashScreenExit(splashScreenViewProvider)
}
}
override fun onFlutterUiDisplayed(){
flutterUIReady = true
if (initialAnimationFinished) {
hideSplashScreenAnimation()
}
}
override fun onFlutterUiNoLongerDisplayed(){
flutterUIReady = false
}
/**
* Hides the splash screen only when the entire animation has finished and the Flutter UI is ready to display.
*/
private fun hideSplashScreenAnimation(){
val splashView = findViewById(R.id.container) as ConstraintLayout
splashView
.animate()
.alpha(0.0f)
.setDuration(SPLASHSCREEN_FINAL_ANIMATION_ALPHA_ANIMATION_DURATION)
}
/**
* Handles the transition from the splash screen to the application.
*/
private fun onSplashScreenExit(splashScreenViewProvider: SplashScreenViewProvider) {
val accelerateInterpolator = FastOutLinearInInterpolator()
val splashScreenView = splashScreenViewProvider.view
val iconView = splashScreenViewProvider.iconView
// Change the alpha of the main view.
val alpha = ValueAnimator.ofInt(255, 0)
alpha.duration = SPLASHSCREEN_ALPHA_ANIMATION_DURATION
alpha.interpolator = accelerateInterpolator
// And translate the icon down.
val translationY = ObjectAnimator.ofFloat(
iconView,
View.TRANSLATION_Y,
iconView.translationY,
splashScreenView.height.toFloat()
)
translationY.duration = SPLASHSCREEN_TY_ANIMATION_DURATION
translationY.interpolator = accelerateInterpolator
// And play all of the animation together.
val animatorSet = AnimatorSet()
animatorSet.playTogether(alpha)
// Apply layout constraints of starting frame of animation to
// FrameLayout's container for the TransitionManager to know
// where to start the transition.
val root = findViewById<ConstraintLayout>(R.id.container)
val set1 = ConstraintSet().apply {
clone(this@MainActivity, R.layout.main_activity)
}
set1.applyTo(root)
// Retrieve layout constraints of final frame of animation
// for TransitionManager to know where to end the transition.
val set2 = ConstraintSet().apply {
clone(this@MainActivity, R.layout.main_activity_2)
}
var transitionStarted = false
val autoTransition = AutoTransition().apply {
interpolator = AccelerateDecelerateInterpolator()
}
autoTransition.addListener(object: Transition.TransitionListener {
override fun onTransitionEnd(transition: Transition) {
initialAnimationFinished = true
if (flutterUIReady) {
hideSplashScreenAnimation()
}
}
override fun onTransitionCancel(transition: Transition){}
override fun onTransitionPause(transition: Transition) {}
override fun onTransitionResume(transition: Transition) {}
override fun onTransitionStart(transition: Transition) {}
})
val alphaUpdateListener: (ValueAnimator) -> Unit = { valueAnimator ->
if (!transitionStarted && valueAnimator.animatedFraction > 0.5) {
transitionStarted = true
TransitionManager.beginDelayedTransition(root, autoTransition)
iconView.visibility = View.GONE
// Apply constraints of final frame of animation to
// FrameLayout's container once the transition is in progress.
set2.applyTo(root)
}
splashScreenView.background.alpha = valueAnimator.animatedValue as Int
}
alpha.addUpdateListener(alphaUpdateListener)
// Once the application is finished, remove the splash screen from our view
// hierarchy.
animatorSet.doOnEnd {
splashScreenViewProvider.remove()
}
waitForAnimatedIconToFinish(splashScreenViewProvider, splashScreenView) {
animatorSet.start()
}
}
/**
* Wait until the AVD animation is finished before starting the splash screen dismiss animation.
*/
private fun SplashScreenViewProvider.remainingAnimationDuration() = iconAnimationStartMillis +
iconAnimationDurationMillis - System.currentTimeMillis()
private fun waitForAnimatedIconToFinish(
splashScreenViewProvider: SplashScreenViewProvider,
view: View,
onAnimationFinished: () -> Unit
) {
// If wanting to wait for our Animated Vector Drawable to finish animating, can compute
// the remaining time to delay the start of the exit animation.
val delayMillis: Long =
if (WAIT_FOR_AVD_TO_FINISH) splashScreenViewProvider.remainingAnimationDuration() else 0
view.postDelayed(delayMillis, onAnimationFinished)
}
private companion object {
const val SPLASHSCREEN_ALPHA_ANIMATION_DURATION = 500 as Long
const val SPLASHSCREEN_TY_ANIMATION_DURATION = 500 as Long
const val SPLASHSCREEN_FINAL_ANIMATION_ALPHA_ANIMATION_DURATION = 250 as Long
const val WAIT_FOR_AVD_TO_FINISH = false
}
}

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="72dp"
android:height="72dp"
android:viewportHeight="800"
android:viewportWidth="800">
<path
android:fillColor="#3ddc84"
android:pathData="m596.328,310.906c22.484,-39.699 46.513,-78.699 68.084,-118.812 4.258,-14.364 -17.654,-23.707 -25.102,-10.703 -22.603,38.973 -45.139,77.986 -67.716,116.974 -107.224,-48.772 -235.192,-48.772 -342.415,0 -23.491,-39.715 -45.567,-80.447 -69.895,-119.56 -10.384,-10.813 -29.373,3.556 -21.753,16.461 22.277,38.562 44.614,77.091 66.914,115.64C88.641,372.042 9.442,494.721 -0,625c266.667,0 533.333,0 800,0C790.261,494.557 711.967,372.81 596.328,310.906ZM216.039,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.056,51.902 -27.872,51.263zM584.348,511.17c-24.214,1.092 -41.724,-28.29 -29.21,-49.016 10.591,-21.768 44.808,-23.114 57.082,-2.246 14.575,21.206 -2.055,51.902 -27.872,51.263z"
android:strokeWidth="1.93078" />
</vector>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/logo_background" />
</shape>

@ -0,0 +1,80 @@
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- This is the animated Android icon that initiates the entire splash screen animation-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:width="108dp"
android:height="108dp"
android:viewportHeight="432"
android:viewportWidth="432">
<!--
Scale down the icon and translate if to fit
within the inner 2/3 (scale <= 0.67) or the viewport.
-->
<group
android:translateX="97"
android:translateY="97"
android:scaleX="0.55"
android:scaleY="0.55">
<clip-path android:pathData="m322.02,167.89c12.141,-21.437 25.117,-42.497 36.765,-64.158 2.2993,-7.7566 -9.5332,-12.802 -13.555,-5.7796 -12.206,21.045 -24.375,42.112 -36.567,63.166 -57.901,-26.337 -127.00,-26.337 -184.90,0.0 -12.685,-21.446 -24.606,-43.441 -37.743,-64.562 -5.6074,-5.8390 -15.861,1.9202 -11.747,8.8889 12.030,20.823 24.092,41.629 36.134,62.446C47.866,200.90 5.0987,267.15 0.0,337.5c144.00,0.0 288.00,0.0 432.0,0.0C426.74,267.06 384.46,201.32 322.02,167.89ZM116.66,276.03c-13.076,0.58968 -22.531,-15.277 -15.773,-26.469 5.7191,-11.755 24.196,-12.482 30.824,-1.2128 7.8705,11.451 -1.1102,28.027 -15.051,27.682zM315.55,276.03c-13.076,0.58968 -22.531,-15.277 -15.773,-26.469 5.7191,-11.755 24.196,-12.482 30.824,-1.2128 7.8705,11.451 -1.1097,28.027 -15.051,27.682z" />
<path
android:fillColor="#3ddc84"
android:pathData="m322.02,167.89c12.141,-21.437 25.117,-42.497 36.765,-64.158 2.2993,-7.7566 -9.5332,-12.802 -13.555,-5.7796 -12.206,21.045 -24.375,42.112 -36.567,63.166 -57.901,-26.337 -127.00,-26.337 -184.90,0.0 -12.685,-21.446 -24.606,-43.441 -37.743,-64.562 -5.6074,-5.8390 -15.861,1.9202 -11.747,8.8889 12.030,20.823 24.092,41.629 36.134,62.446C47.866,200.90 5.0987,267.15 0.0,337.5c144.00,0.0 288.00,0.0 432.0,0.0C426.74,267.06 384.46,201.32 322.02,167.89ZM116.66,276.03c-13.076,0.58968 -22.531,-15.277 -15.773,-26.469 5.7191,-11.755 24.196,-12.482 30.824,-1.2128 7.8705,11.451 -1.1102,28.027 -15.051,27.682zM315.55,276.03c-13.076,0.58968 -22.531,-15.277 -15.773,-26.469 5.7191,-11.755 24.196,-12.482 30.824,-1.2128 7.8705,11.451 -1.1097,28.027 -15.051,27.682z"
android:strokeWidth="1.93078" />
<group android:name="anim">
<path
android:fillAlpha="0.999"
android:fillColor="#979797"
android:fillType="nonZero"
android:pathData="m-197.42,638.59c0.0,0.0 -5.9627,-259.30 46.113,-215.87 32.895,27.437 76.838,-65.597 91.553,-46.592 2.7119,-7.7182 95.045,109.16 139.74,17.953 10.678,-21.792 43.788,-64.489 78.236,-16.164 54.226,76.069 110.90,-100.75 179.84,-17.966 36.393,43.701 96.377,-23.605 148.05,19.889 42.614,35.869 83.166,3.7255 109.76,61.101 24.321,52.465 35.893,197.64 35.893,197.64L631.77,92.867L-197.42,92.867Z"
android:strokeAlpha="1"
android:strokeColor="#00000000"
android:strokeWidth="12" />
</group>
</group>
</vector>
</aapt:attr>
<target android:name="anim">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="1000"
android:propertyName="translateY"
android:repeatCount="0"
android:valueFrom="0"
android:valueTo="-432"
android:valueType="floatType"
android:interpolator="@android:interpolator/accelerate_decelerate" />
</aapt:attr>
</target>
<target android:name="anim">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="500"
android:propertyName="translateX"
android:repeatCount="-1"
android:repeatMode="reverse"
android:valueFrom="-162"
android:valueTo="162"
android:valueType="floatType"
android:interpolator="@android:interpolator/accelerate_decelerate" />
</aapt:attr>
</target>
</animated-vector>

@ -0,0 +1,58 @@
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- This layout is the first frame of the interpolation animation. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/icon_background"
android:layout_width="192dp"
android:layout_height="192dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/android_background" />
<ImageView
android:id="@+id/imageView"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_marginBottom="6dp"
android:src="@drawable/android"
app:layout_constraintBottom_toBottomOf="@+id/icon_background"
app:layout_constraintEnd_toEndOf="@+id/icon_background"
app:layout_constraintStart_toStartOf="@+id/icon_background"
app:layout_constraintTop_toTopOf="@+id/icon_background"
app:srcCompat="@drawable/android" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Super Splash Screen Demo"
android:textSize="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,76 @@
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- This layout is the final frame of the interpolation animation. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<ImageView
android:id="@+id/icon_background"
android:layout_width="72dp"
android:layout_height="72dp"
app:layout_constraintBottom_toBottomOf="@+id/imageView"
app:layout_constraintEnd_toEndOf="@+id/imageView"
app:layout_constraintStart_toStartOf="@+id/imageView"
app:layout_constraintTop_toTopOf="@+id/imageView"
android:src="@drawable/android_background" />
<ImageView
android:id="@+id/imageView"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
android:src="@drawable/android"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/android" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Super Splash Screen Demo"
android:textSize="24dp"
app:layout_constraintBottom_toBottomOf="@+id/imageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toTopOf="@+id/imageView" />
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
app:constraint_referenced_ids="imageView2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon_background" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="@+id/icon_background"
app:layout_constraintTop_toBottomOf="@+id/icon_background"
tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<style name="Theme.App" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:enforceNavigationBarContrast">false</item>
</style>
<style name="LaunchTheme" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splashScreenBackground</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_icon</item>
<item name="windowSplashScreenAnimationDuration">2000</item>
<item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
</resources>

@ -0,0 +1,21 @@
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="splashScreenBackground">#034565</color>
<color name="logo_background">#034565</color>
<color name="white">#FFFFFF</color>
</resources>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<dimen name="content_animation_margin_start">30dp</dimen>
<dimen name="content_animation_margin_end">10dp</dimen>
</resources>

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<style name="Theme.App" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:enforceNavigationBarContrast">false</item>
</style>
<style name="LaunchTheme" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splashScreenBackground</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splashscreen_icon</item>
<item name="windowSplashScreenAnimationDuration">2000</item>
<item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
</resources>

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.splash_screen_sample">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

@ -0,0 +1,29 @@
buildscript {
ext.kotlin_version = '1.5.31'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

@ -0,0 +1,115 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:flutter/material.dart';
Future<void> main() async {
runApp(const MyApp());
}
/* Main widget that contains the Flutter starter app. */
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 42, bottom: 250),
child: Align(
alignment: Alignment.topCenter, child: CustomAppBar())),
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
/* A Flutter implementation of the last frame of the splashscreen animation */
class CustomAppBar extends StatelessWidget {
const CustomAppBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Widget titleSection = Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 12, right: 4),
child: ClipRRect(
borderRadius: BorderRadius.circular(36.0),
child: Image.asset(
'images/androidIcon.png',
width: 72.0,
height: 72.0,
fit: BoxFit.fill,
),
),
),
const Padding(
padding: EdgeInsets.only(top: 3),
child: Text("Super Splash Screen Demo",
style: TextStyle(color: Colors.black54, fontSize: 24)),
),
],
);
return titleSection;
}
}

@ -0,0 +1,23 @@
name: splash_screen_sample
description: A sample Flutter app with animated splash screen on Android 12.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.4
flutter:
uses-material-design: true
assets:
- images/androidIcon.png

@ -0,0 +1,9 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('This test always passes', (tester) async {});
}

@ -13,6 +13,7 @@ declare -ar PROJECT_NAMES=(
"add_to_app/multiple_flutters/multiple_flutters_module"
"add_to_app/plugin/flutter_module_using_plugin"
"add_to_app/prebuilt_module/flutter_module"
"android_splash_screen"
"animations"
"experimental/desktop_photo_search"
"experimental/federated_plugin/federated_plugin"

@ -13,6 +13,7 @@ declare -ar PROJECT_NAMES=(
"add_to_app/multiple_flutters/multiple_flutters_module"
"add_to_app/plugin/flutter_module_using_plugin"
"add_to_app/prebuilt_module/flutter_module"
"android_splash_screen"
"animations"
"experimental/desktop_photo_search"
"experimental/federated_plugin/federated_plugin"

@ -13,6 +13,7 @@ declare -ar PROJECT_NAMES=(
"add_to_app/multiple_flutters/multiple_flutters_module"
"add_to_app/plugin/flutter_module_using_plugin"
"add_to_app/prebuilt_module/flutter_module"
"android_splash_screen"
"animations"
"experimental/desktop_photo_search"
"experimental/federated_plugin/federated_plugin"

Loading…
Cancel
Save