Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

smooth transition from native splash sceen to an animated page - how to do? #692

Open
FetFrumos opened this issue Apr 17, 2024 · 10 comments

Comments

@FetFrumos
Copy link

I am working on a Flutter app for both Android and iOS, and I'm using the flutter_native_splash plugin to create a static splash screen. However, my client wants an animated splash screen immediately following the static one. The plugin doesn't support animations directly, so we agreed on a setup where a static splash screen is displayed first, followed by a custom animated splash screen built within Flutter.

The static splash screen is set up with flutter_native_splash, which scales the image to fit different device screens, but I'm unsure how to perfectly align the image size of the animated splash screen to match the static one.

What are the best practices to synchronize the image dimensions between the static image used by flutter_native_splash and the subsequent animated image in Flutter?

is this even possible? any advice - I will be very grateful

@ziadsarour
Copy link

@FetFrumos have you found a way to sync the static and dynamic images ?

@CHUNG-HAO
Copy link

I thought we could discuss how we could contribute to this open source project, haha^^

@BriceFab
Copy link

Same! My client want a "fade in/out" animation

@wiesnery
Copy link

This should be an easy one - at least a fade out on calling FlutterNativeSplash.remove(); right?

@wiesnery
Copy link

Well maybe not - have you checke the code in - https://github.com/jonbhanson/flutter_native_splash/blob/master/lib/flutter_native_splash.dart ?
This seems like it only prevents the first frame to draw - so to make a smooth animation, we would need to find the currently displayed image and fade away.
Have you tried with a dynamic screenshot maybe?

@CHUNG-HAO
Copy link

@BriceFab How did you eventually solve this problem? Thank you.

@ziadsarour
Copy link

ziadsarour commented Sep 16, 2024

@FetFrumos @CHUNG-HAO

I have maybe found a solution but :

  • not tested on devices with devicePixelRatio != 3
  • on Android >= 12 there is a slide out + fade out transition on the native splash and I don't know how to prevent this

Create 2 splash images, one for iOS and Android < 12 and another one for Android >= 12 :

  • assets/images/splash.png : 1440x1440 for iOS and Android < 12
  • assets/images/splash_android12.png : 1080x1080 for Android >= 12

Here is an explanation on how you have to export your images :

Capture d’écran 2024-09-16 à 21 07 12



assets/images/splash.png assets/images/splash_android12.png
Mobile Image Mobile Android12

Change your pubspec.yaml to :

dependencies:
  device_info_plus: 10.1.2

...

flutter_native_splash:
  color: "#FFFFFF"
  image: assets/images/splash/image.png
  fullscreen: false
  web: false
  ios: true
  info_plist_files:
    - ios/Runner/Info-Debug.plist
    - ios/Runner/Info-Release.plist
  android: true
  android_12:
    color: "#FFFFFF"
    image: assets/images/splash/image_android12.png
    icon_background_color: "#FFFFFF"

Do not forget to generate splash using dart run flutter_native_splash:create

Create your splash route :

class RouteAppSplash extends StatefulWidget {
  const RouteAppSplash({super.key});

  @override
  State<RouteAppSplash> createState() => _RouteAppSplashState();
}

class _RouteAppSplashState extends State<RouteAppSplash> {
  final _completer = Completer();
  var _logoImage = '';
  var _logoScale = 1.0;

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((timestamp) {
      // replace native splash by the custom one
      // scale and image are computed based on device
      _hydrate();

      _completer.future.then((_) async {
        // * 1. run your animation
        // * 2. redirect to your main screen
      });
    });
  }

  Future<void> _hydrate() async {
    if (Platform.isIOS) {
      _logoImage = 'assets/images/splash.png'; // 1440x1440
      _logoScale = 360 / MediaQuery.sizeOf(context).width; // @1x width divided by logical screen width
    } else if (Platform.isAndroid) {
      final deviceInfo = DeviceInfoPlugin();
      final androidInfo = await deviceInfo.androidInfo;
      final version = int.tryParse(androidInfo.version.release ?? '') ?? 0;

      if (version >= 12) {
        _logoImage = 'assets/images/splash_android12.png'; // 1080x1080
        _logoScale = .75;
      } else if (Platform.isAndroid) {
        _logoImage = 'assets/images/splash.png'; // 1440x1440
        _logoScale = 1;
      }
    }

    if (mounted) {
      await precacheImage(AssetImage(_logoImage), context); // precache to avoid blink
    }

    setState(() {});
    FlutterNativeSplash.remove(); // remove native splash
    _completer.complete(); // notify that custom splash is displayed
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        child: Transform.scale(
          scale: _logoScale,
          child: Image.asset(
            _logoImage,
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }
}

@chahohbily
Copy link

chahohbily commented Oct 1, 2024

@ziadsarour It's a little unclear where you got the FlutterNativeSplash.remove() line from. Is this a custom static method?
And how did you manage to avoid the slide-out + smooth disappear transition on the native splash screen in the ios system? On the ios emulator this transition is still present

@iapicca
Copy link

iapicca commented Oct 27, 2024

@FetFrumos @CHUNG-HAO

I have maybe found a solution but :

  • not tested on devices with devicePixelRatio != 3
  • on Android >= 12 there is a slide out + fade out transition on the native splash and I don't know how to prevent this

Create 2 splash images, one for iOS and Android < 12 and another one for Android >= 12 :

  • assets/images/splash.png : 1440x1440 for iOS and Android < 12
  • assets/images/splash_android12.png : 1080x1080 for Android >= 12

Here is an explanation on how you have to export your images :

Change your pubspec.yaml to :

dependencies:
  device_info_plus: 10.1.2

...

flutter_native_splash:
  color: "#FFFFFF"
  image: assets/images/splash/image.png
  fullscreen: false
  web: false
  ios: true
  info_plist_files:
    - ios/Runner/Info-Debug.plist
    - ios/Runner/Info-Release.plist
  android: true
  android_12:
    color: "#FFFFFF"
    image: assets/images/splash/image_android12.png
    icon_background_color: "#FFFFFF"

Do not forget to generate splash using dart run flutter_native_splash:create

Create your splash route :

class RouteAppSplash extends StatefulWidget {
  const RouteAppSplash({super.key});

  @override
  State<RouteAppSplash> createState() => _RouteAppSplashState();
}

class _RouteAppSplashState extends State<RouteAppSplash> {
  final _completer = Completer();
  var _logoImage = '';
  var _logoScale = 1.0;

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((timestamp) {
      // replace native splash by the custom one
      // scale and image are computed based on device
      _hydrate();

      _completer.future.then((_) async {
        // * 1. run your animation
        // * 2. redirect to your main screen
      });
    });
  }

  Future<void> _hydrate() async {
    if (Platform.isIOS) {
      _logoImage = 'assets/images/splash.png'; // 1440x1440
      _logoScale = 360 / MediaQuery.sizeOf(context).width; // @1x width divided by logical screen width
    } else if (Platform.isAndroid) {
      final deviceInfo = DeviceInfoPlugin();
      final androidInfo = await deviceInfo.androidInfo;
      final version = int.tryParse(androidInfo.version.release ?? '') ?? 0;

      if (version >= 12) {
        _logoImage = 'assets/images/splash_android12.png'; // 1080x1080
        _logoScale = .75;
      } else if (Platform.isAndroid) {
        _logoImage = 'assets/images/splash.png'; // 1440x1440
        _logoScale = 1;
      }
    }

    if (mounted) {
      await precacheImage(AssetImage(_logoImage), context); // precache to avoid blink
    }

    setState(() {});
    FlutterNativeSplash.remove(); // remove native splash
    _completer.complete(); // notify that custom splash is displayed
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        child: Transform.scale(
          scale: _logoScale,
          child: Image.asset(
            _logoImage,
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }
}

if this stuff works should be part of the package

@ziadsarour
Copy link

@ziadsarour It's a little unclear where you got the FlutterNativeSplash.remove() line from. Is this a custom static method? And how did you manage to avoid the slide-out + smooth disappear transition on the native splash screen in the ios system? On the ios emulator this transition is still present

FlutterNativeSplash.remove() is part of the package.
I don't have (and never had) a slide-out + smooth disappear transition on iOS, it might be due to your code/configuration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants