在Flutter应用中添加启动画面

265

你如何为Flutter应用添加启动屏?它应该在任何其他内容加载之前就能够加载和显示。目前,Scaffold(home:X)小部件加载之前会有短暂的闪烁。


2
我不确定设置一个自定义定时器来添加启动画面是否是正确的方法。我不喜欢让处理器处于空闲状态,为什么不要做一些类似于检查所需文件或目录、同步某些日志或在后台备份某些文件等任务,同时在前端完成品牌推广。毕竟,对于处理器来说,3-4秒是很长的时间。 - Mahesh Jamdade
2
这个链接解释了如何实现它:https://flutter.dev/docs/development/ui/splash-screen/android-splash-screen - live-love
使用Flutter原生闪屏包,您将能够轻松完成此操作。这里有一个关于它的教程:https://youtu.be/GV19Hawgpeg - Tawanda Muzavazi
我为Flutter启动屏幕创建了一个教程,其中一个是不使用任何库的,另一个是使用库,即Flutter Native Splash,它们肯定会对你有所帮助。不使用任何库的教程:https://youtu.be/MCosWsD5yKc 使用Flutter Native Splash的教程:https://www.youtube.com/watch?v=GV19Hawgpeg - undefined
25个回答

390

我想更详细地介绍在Flutter中实现启动屏幕的方法。

我跟踪了一下这里,发现Flutter的启动屏幕并不是那么糟糕。

也许大多数开发人员(像我一样)认为Flutter默认没有启动屏幕,他们需要做些什么。实际上已经有一个启动屏幕,但它的背景是白色的,没有人能够理解iOS和Android默认已经有了启动屏幕。

开发者唯一需要做的就是将品牌标志放在正确的位置,启动屏幕就会开始工作。

以下是逐步操作的具体方法:

首先是Android(因为我最喜欢它 :))

  1. 在Flutter项目中找到“android”文件夹。

  2. 浏览到app -> src -> main -> res文件夹,并将所有品牌标志图片的变体放置在相应的文件夹中。例如:

  • 密度为1的图像需要放在mipmap-mdpi中,
  • 密度为1.5的图像需要放在mipmap-hdpi中,
  • 密度为2的图像需要放在mipmap-xhdpi中,
  • 密度为3的图像需要放在mipmap-xxhdpi中,
  • 密度为4的图像需要放在mipmap-xxxhdpi中。

因为Android文件夹中默认没有drawable-mdpi、drawable-hdpi等文件夹,但是我们可以自己创建。因此,图片需要放在mipmap文件夹中。同时,启动屏幕的默认XML代码(在Android中)将使用@mipmap,而不是@drawable资源(如果您愿意,可以更改它)。

  1. 在Android上的最后一步是取消注释drawable/launch_background.xml文件中的某些XML代码。浏览到app -> src -> main -> res-> drawable并打开launch_background.xml。在这个文件中,你会看到为什么Slash屏幕的背景是白色的。为了应用我们在第2步中放置的品牌标志,我们必须取消注释launch_background.xml文件中的一些XML代码。更改后,代码应该像这样:

     <!--<item android:drawable="@android:color/white" />-->
    
     <item>
    
         <bitmap
             android:gravity="center"
             android:src="@mipmap/your_image_name" />
    
     </item>
    
    请注意,我们注释掉了白色背景的XML代码并取消注释关于mipmap图像的代码。如有兴趣,launch_background.xml文件用于styles.xml文件中。在iOS上,您需要在Flutter项目中的“ios”文件夹中找到Runner -> Assets.xcassets -> LaunchImage.imageset。这里应该有LaunchImage.png,LaunchImage@2x.png等。现在,您需要使用您的品牌形象变体替换这些图像。例如:密度为1的图像需要替换LaunchImage.png,密度为2的图像需要替换LaunchImage@2x.png,密度为3的图像需要替换LaunchImage@3x.png,密度为4的图像需要替换LaunchImage@4x.png。如果我没有记错,LaunchImage@4x.png默认不存在,但您可以轻松创建它。如果LaunchImage@4x.png不存在,则还必须在与图像位于同一目录中的Contents.json文件中声明它。更改后,我的Contents.json文件如下:
    {
      "images" : [
        {
          "idiom" : "universal",
          "filename" : "LaunchImage.png",
          "scale" : "1x"
        },
        {
          "idiom" : "universal",
          "filename" : "LaunchImage@2x.png",
          "scale" : "2x"
        },
        {
          "idiom" : "universal",
          "filename" : "LaunchImage@3x.png",
          "scale" : "3x"
        },
        {
          "idiom" : "universal",
          "filename" : "LaunchImage@4x.png",
          "scale" : "4x"
        }
      ],
      "info" : {
        "version" : 1,
        "author" : "xcode"
      }
    }
    

    这应该是你所需要的全部内容了。下次在 Android 或 iOS 上运行应用程序时,你应该会看到你添加的品牌图像作为正确的启动画面。

    谢谢


7
在Android Studio 3.1.1中,我遇到了错误“Cannot resolve symbol '@mipmap/ic_launcher'”,即使我重新生成缓存,但应用程序编译和运行时没有错误,并且启动器图形也显示出来了。 - IanB
5
我有同样的问题,但我无法在运行时运行它,因为它会崩溃并告诉我图像丢失了。但是由于某种原因,它无法解析mipmap。有人知道这是为什么吗? - carlosx2
2
大家好,不确定为什么会出现这个问题,但对我来说似乎是项目同步问题(如果资源存在,没有其他原因找不到资源)。我不知道如何解决它,因为我从未遇到过这个问题,但尝试同步项目、清理、重建等。在drawable文件夹中使用资源,并将mipmap注释替换为drawable注释。我只是猜测 :) - Stoycho Andreev
2
你为什么要添加4x图像,我很好奇。XCode似乎只需要3x,你添加4x的原因是什么? - sbilstein
8
官方文档已经涵盖了此内容。 - rmalviya
显示剩余32条评论

71

在flutter中添加启动屏幕最简单的方法是使用以下包: https://pub.dev/packages/flutter_native_splash

enter image description here

安装指南(由包的作者提供):

1.设置启动屏幕

将您的设置添加到项目的pubspec.yaml文件中或在根项目文件夹中创建一个名为flutter_native_splash.yaml的文件,并在其中添加您的设置。

flutter_native_splash:
  image: assets/images/splash.png
  color: "42a5f5"

图片必须是PNG文件。

您也可以在颜色中使用#。 颜色:“#42a5f5” 如果您不想为特定平台创建启动画面,则还可以将android或ios设置为false。

flutter_native_splash:
  image: assets/images/splash.png
  color: "42a5f5"
  android: false

如果您的图像需要使用整个屏幕(宽度和高度),则可以使用填充属性。

flutter_native_splash:
  image: assets/images/splash.png
  color: "42a5f5"
  fill: true
注意:fill属性尚未为iOS启动屏幕实现。
如果要在Android上禁用全屏启动屏幕,可以使用android_disable_fullscreen属性。
flutter_native_splash:
  image: assets/images/splash.png
  color: "42a5f5"
  android_disable_fullscreen: true

2. 运行该软件包

在添加设置后,使用以下命令运行该软件包:

flutter pub run flutter_native_splash:create 当软件包运行完成时,您的启动画面即可就绪。


2
如果iOS启动画面没有填充整个屏幕,请在pubspec.yaml文件中添加ios_content_mode:scaleToFill,然后重新运行flutter pub run flutter_native_splash:create - Mahmoud Farahat
1
我使用了这个包,工作得非常完美,并且不需要对文件进行任何操作。最佳答案。 - n13

42

Flutter实际上为我们的应用程序添加启动画面提供了更简单的方法。 我们首先需要像设计其他应用程序屏幕一样设计一个基本页面。您需要将其制作为一个StatefulWidget,因为它的状态将在几秒钟内发生变化。

import 'dart:async';
import 'package:flutter/material.dart';
import 'home.dart';

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    Timer(
        Duration(seconds: 3),
        () => Navigator.of(context).pushReplacement(MaterialPageRoute(
            builder: (BuildContext context) => HomeScreen())));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        child: Image.asset('assets/splash.png'),
      ),
    );
  }
}
initState()中,按照您的意愿调用一个持续时间为3秒的Timer(),完成后将导航器推送到我们应用程序的主屏幕。
注意:应用程序只应显示启动画面一次,用户不应在按下返回按钮时再返回到它。 为此,我们使用Navigator.pushReplacement(),它将移动到新屏幕并从导航历史堆栈中删除先前的屏幕。
了解更多信息,请访问Flutter: Design your own Splash Screen

31
这个定制的启动画面在显示前,系统默认的白色启动画面仍会持续1秒以上。必须在生成的Xcode和Android项目中进行覆盖以消除它。 - d3vtoolsmith
是的。在iOS和Android中,默认的启动画面将始终出现,而Flutter启动画面是额外添加的。 - Mahesh Peri
这个例子并不可靠......如果由于网络连接等原因,您的应用程序加载时间超过3秒会怎样呢? - emanuel sanga
为了进行额外的定制,我更支持这个答案。我想要在显示启动画面的同时首先执行一个HTTP请求。这种方法更加容易。 - Idris Stack
我更喜欢这种方式。但是它必须是StatefulWidget吗?我认为我用StatelessWidget也可以实现。 - nelsonspbr

18

目前还没有一个好的例子,但你可以使用每个平台的本地工具自己实现:

iOS: https://docs.nativescript.org/tooling/publishing/creating-launch-screens-ios

Android: https://www.bignerdranch.com/blog/splash-screens-the-right-way/

订阅问题8147以获取关于闪屏页面示例代码的更新。如果iOS上启动页和应用程序之间出现黑色闪烁问题,请订阅问题8127以获取更新。

编辑:截至2017年8月31日,新项目模板中已提供改进的闪屏支持。请参见#11505


有没有实际添加启动画面的示例?当我启动新模板时,我看不到启动画面。 - Ride Sun
@RideSun,请查看我的回答。 - Stoycho Andreev
1
我该如何让启动画面停留更久?我需要在活动中更改一些代码吗? - aliep
但我需要更多,例如当启动画面时,只有创建/导入本地数据库后才能结束启动画面。 - stuckedoverflow

16

对于Android,前往android > app > src > main > res > drawable > launcher_background.xml

现在取消此注释,并将@mipmap/launch_image替换为您的图像位置。

<item>
      <bitmap
          android:gravity="center"
          android:src="@mipmap/launch_image" />
</item>

您可以在这里更改屏幕的颜色 -

<item android:drawable="@android:color/white" />

这对我起作用了... 但是 iOS 部分... 不太好玩。 - IrishGringo
1
请查看以下内容 - https://flutter.io/assets-and-images/#updating-the-launch-screen - Smruti Ranjan Rana
我搞定了... 显然是iOS图片有问题。现在iOS和ANDROID都完美运行。虚惊一场。 - IrishGringo
@SmrutiRanjanRana 这张图片的理想尺寸是多少? - Mattias
2
如果有图像位置的示例,这个答案会更有帮助。否则用户必须猜测如何添加路径。 - Robin Manoli
有没有办法为启动画面添加自定义计时器? - Mahesh Jamdade

14

如果您在应用验证答案后遇到“图像未找到”等错误,请确保添加的是@mipmap/ic_launcher而不是@mipmap/ic_launcher.png


1
当您将光标悬停在错误上时,您的IDE会告诉您这一点。 - Ojonugwa Jude Ochalifu

11

这是在Flutter中添加动态启动画面的无误且最佳方式。

MAIN.DART

import 'package:flutter/material.dart';
import 'constant.dart';

void main() => runApp(MaterialApp(
      title: 'GridView Demo',
      home: SplashScreen(),
      theme: ThemeData(
        primarySwatch: Colors.red,
        accentColor: Color(0xFF761322),
      ),
      routes: <String, WidgetBuilder>{
        SPLASH_SCREEN: (BuildContext context) => SplashScreen(),
        HOME_SCREEN: (BuildContext context) => BasicTable(),
        //GRID_ITEM_DETAILS_SCREEN: (BuildContext context) => GridItemDetails(),
      },
    ));



SPLASHSCREEN.DART

import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:app_example/constants.dart';


class SplashScreen extends StatefulWidget {
  @override
  SplashScreenState createState() => new SplashScreenState();
}

class SplashScreenState extends State<SplashScreen>
    with SingleTickerProviderStateMixin {
  var _visible = true;

  AnimationController animationController;
  Animation<double> animation;

  startTime() async {
    var _duration = new Duration(seconds: 3);
    return new Timer(_duration, navigationPage);
  }

  void navigationPage() {
    Navigator.of(context).pushReplacementNamed(HOME_SCREEN);
  }

@override
dispose() {
  animationController.dispose();  
  super.dispose();
}

  @override
  void initState() {
    super.initState();
    animationController = new AnimationController(
      vsync: this,
      duration: new Duration(seconds: 2),
    );
    animation =
        new CurvedAnimation(parent: animationController, curve: Curves.easeOut);

    animation.addListener(() => this.setState(() {}));
    animationController.forward();

    setState(() {
      _visible = !_visible;
    });
    startTime();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          new Column(
            mainAxisAlignment: MainAxisAlignment.end,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Padding(
                padding: EdgeInsets.only(bottom: 30.0),
                child: new Image.asset(
                  'assets/images/powered_by.png',
                  height: 25.0,
                  fit: BoxFit.scaleDown,
                ),
              )
            ],
          ),
          new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Image.asset(
                'assets/images/logo.png',
                width: animation.value * 250,
                height: animation.value * 250,
              ),
            ],
          ),
        ],
      ),
    );
  }
}



CONSTANTS.DART

:常量文件的Dart实现。

String SPLASH_SCREEN='SPLASH_SCREEN';
String HOME_SCREEN='HOME_SCREEN';
HOMESCREEN.DART
import 'package:flutter/material.dart';

class BasicTable extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Table Widget")),
      body: Center(child: Text("Table Widget")),
    );
  }
}


我认为这是最好的方式。 - Rahul Kushwaha
3
那不是启动画面。启动画面是在你的应用程序启动之前由iOS或Android显示的。因此,您无法在应用程序中执行此操作(因为应用程序尚未启动...)。答案不正确。 - n13

8
@Collin Jackson和@Sniper都是正确的。你可以按照以下步骤分别在Android和iOS中设置启动图像。然后在MyApp()中的initState()中,你可以使用Future.delayed来设置计时器或调用任何API。在从Future返回响应之前,会显示启动图标,然后随着响应的到来,你可以移动到想要在闪屏屏幕后转到的屏幕。你可以查看此链接:Flutter启动画面

4
请在链接到 SO 之外的另一个页面时,在此发布回答内容以避免死链接。 - rak007

7
你可以尝试下面的代码,对我有效:

你可以尝试以下代码,对我有效

import 'dart:async';
import 'package:attendance/components/appbar.dart';
import 'package:attendance/homepage.dart';
import 'package:flutter/material.dart';

class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {


void handleTimeout() {
  Navigator.of(context).pushReplacement(new MaterialPageRoute(
    builder: (BuildContext context) => new MyHomePage()));
}

startTimeout() async {
  var duration = const Duration(seconds: 3);
  return new Timer(duration, handleTimeout);
}

@override
void initState() {
  // TODO: implement initState
  super.initState();

  _iconAnimationController = new AnimationController(
      vsync: this, duration: new Duration(milliseconds: 2000));

  _iconAnimation = new CurvedAnimation(
      parent: _iconAnimationController, curve: Curves.easeIn);
  _iconAnimation.addListener(() => this.setState(() {}));

  _iconAnimationController.forward();

  startTimeout();
}

@override
Widget build(BuildContext context) {
  return new Scaffold(
    body: new Scaffold(
      body: new Center(
        child: new Image(
        image: new AssetImage("images/logo.png"),
        width: _iconAnimation.value * 100,
        height: _iconAnimation.value * 100,
      )),
    ),
  );
}
}

请问您能否发布完整的代码(一个我们可以独立运行而无需定义变量的代码)或者Github链接? - biniam
也不是启动画面。这样做没有意义。 - n13

5
以下是在Flutter应用程序中配置IOS和Android平台的启动画面的步骤。 IOS平台 所有提交到苹果应用商店的应用程序都必须使用Xcode故事板来提供应用程序的启动屏幕。让我们分3个步骤来完成:
Step 1:从您的应用程序目录的根目录打开ios/Runner.xcworkspace。
Step 2:从项目导航器中选择Runner/Assets.xcassets,将所有大小(2x、3x等)的启动图像拖放到其中。您也可以从https://appicon.co/#image-sets生成不同大小的图像。

enter image description here

第三步: 您可以看到LaunchScreen.storyboard文件显示了提供的图像,您也可以通过简单地拖动图像来更改图像的位置。有关更多信息,请参阅官方文档https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/launch-screen/

enter image description here

Android平台

在Android中,当您的Android应用程序初始化时,会显示启动屏幕。让我们通过以下3个步骤设置此启动屏幕:

第1步:打开android/app/src/main/res/drawable/launch_background.xml文件。

第2步:在第4行,您可以选择所需的颜色:

<item android:drawable="@android:color/white" />

第三步:在第10行,你可以更改图片:

android:src="@mipmap/launch_image"

enter image description here

完成了,你做得很好!编程愉快 :)


我测试了这个解决方案,它起作用了!谢谢。 - Esmaeil Ahmadipour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接