Flutter web app progress indicator before loading app?
Asked Answered
M

8

28

Hi I am a mobile app developer and not much familiar with web development, I was finding any approach to implement Progress Indicator before loading the flutter web app like Gmail loading screen. Flutter web is cool but it takes few moments before loading the app. Can we add any indicator for this loading duration? Any code implemented in flutter would be the part of flutter app and it won't work, There should be another approach to achieve this.

Maller answered 25/7, 2019 at 20:32 Comment(0)
M
38

With the help of @Abhilash, I was able to accomplish this. I got loader code from w3schools.

My project/web/index.html is like this.

<html>

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script defer src="index.dart.js" type="application/javascript"></script>

  <style>
    .loading {
      display: flex;
      justify-content: center;
      align-items: center;
      margin: 0;
      position: absolute;
      top: 50%;
      left: 50%;
      -ms-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
    }
    
    .loader {
      border: 16px solid #f3f3f3;
      border-radius: 50%;
      border-top: 16px solid blue;
      border-right: 16px solid green;
      border-bottom: 16px solid red;
      border-left: 16px solid pink;
      width: 120px;
      height: 120px;
      -webkit-animation: spin 2s linear infinite;
      animation: spin 2s linear infinite;
    }
    
    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
      }
    }
    
    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }
      100% {
        transform: rotate(360deg);
      }
    }
  </style>
</head>

<body>
  <div class="loading">
    <div class="loader"></div>
  </div>

  <script src="main.dart.js" type="application/javascript"></script>
</body>

</html>
Maller answered 1/2, 2020 at 18:15 Comment(1)
this method worked for me but its takes about 10 to 15 seconds to disapear before going to next screenBenavides
L
10

In your question you mentioned

Any code implemented in flutter would be the part of flutter app and it won't work,...

I assume you tried to add the splash screen approach for android or IOS. Since flutter-web is simply an index.html and a couple of js files(for eg., main.dart.js), you should perhaps try the CSS loading animation trick. Since you didn't share any code I am not writing any code but the following would be my approach as explained by this red stapler video. He/she kindly provided a lot of CSS based animations here along with the codepen implementations for that.

So following would be my steps in the flutter_web_project\web\index.html file.

  1. Add a span element in the body of index.html to show the css animation itself.
  2. Create a div wrapper to position the span animation in your index.html.
  3. Then listen to the onLoad event of the window and remove the div element from your page or fade it out as described in the video.
Lukasz answered 19/8, 2019 at 9:13 Comment(0)
M
10

Adam's answer will remove loader before flutter is actually loaded.

I found this script to be the most complete answer:

<html>
<head>
  <style>
        .loading {
          display: flex;
          flex-flow: column;
          justify-content: center;
          align-items: center;
          margin: 0;
          position: absolute;
          top: 50%;
          left: 50%;
          -ms-transform: translate(-50%, -50%);
          transform: translate(-50%, -50%);
        }

        .loader {
          border: 8px solid #f3f3f3;
          border-radius: 50%;
          border-top: 8px solid #00AD87;
          border-right: 8px solid #C30E48;
          border-bottom: 8px solid #00AD87;
          border-left: 8px solid #C30E48;
          width: 60px !important;
          height: 60px !important;
          -webkit-animation: spin 2s linear infinite;
          animation: spin 2s linear infinite;
        }

        @-webkit-keyframes spin {
          0% {
            -webkit-transform: rotate(0deg);
          }
          100% {
            -webkit-transform: rotate(360deg);
          }
        }

        @keyframes spin {
          0% {
            transform: rotate(0deg);
          }
          100% {
            transform: rotate(360deg);
          }
        }
  </style>
</head>

<body>

  <!-- First time loading -->
  <div class="loading">
      <div class="loader"></div>
  </div>

  <!-- Ensure first time loading progress is gone after app loads -->
  <script>
      window.addEventListener("flutter-first-frame", function() {
          var element = document.getElementsByClassName("loading");
          element[0].parentNode.removeChild(element[0]);
      });
  </script>

<script defer src="main.dart.js" type="application/javascript"</script>

</body>
</html>
Muffin answered 17/1, 2022 at 7:14 Comment(0)
H
9

In addition to answer of @Shahzad Akram you should remove the loading div because in Safari browser it may cause of flickering. So in the first screen you need to implement the folowing code (for example, in initState method):

import 'package:universal_html/html.dart'

...

@override
void initState() {
  super.initState()
  // Remove `loading` div
  final loader = document.getElementsByClassName('loading');
  if(loader.isNotEmpty) {
    loader.first.remove();
  }
}

P.S. For nice loaders you can visit loading.io.

Haunch answered 17/9, 2020 at 7:41 Comment(3)
Is it possible to implement just from js inside index.html with Flutter 2.2 ?Arther
@AdamSmaka, if you will know when flutter completes downloading of all scripts required for app initialization, yes,Haunch
That's interesting. 🧐 I can see there is more code probably regarding that with mentioned above flutter version. It would be nice to have everything in one file.Arther
A
3

If you want to remove loading div with just JS use this code

  <script>
    window.onload = (event) => {
      console.log('page is fully loaded');
      var element = document.getElementById("loader");
      element.parentNode.removeChild(element);
    };
  </script>

Notice that it assumes that loader is a <div id="loader"></div> tag

Arther answered 14/7, 2021 at 6:9 Comment(0)
W
2

I think the accepted answer is partially right as it's presented a loading indicator rather than a progress indicator. From flutter doc you can have a rough estimation of the flutter's actual loading progress. I've compiled an example using this indicator and it's showcased here.

Add this style

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  width: 100%;
}

.progress-bar__container {
  width: 80%;
  height: 2rem;
  border-radius: 2rem;
  position: relative;
  overflow: hidden;
  transition: all 0.5s;
  will-change: transform;
  box-shadow: 0 0 5px #e76f51;
}

.progress-bar {
  position: absolute;
  height: 100%;
  width: 100%;
  content: "";
  background-color: #e76f51;
  top:0;
  bottom: 0;
  left: -100%;
  border-radius: inherit;
  display: flex;
  justify-content: center;
  align-items:center;
  color: white;
  font-family: sans-serif;
}

.progress-bar__text {
  display: none;
}

and append this code on index.html of your flutter app.

function updateProgress(num) {
  const progressBarContainer = document.querySelector('.progress-bar__container');
  const progressBar = document.querySelector('.progress-bar');
  const progressBarText = document.querySelector('.progress-bar__text');

  let time = 0;
  let endState = 100;

  gsap.to(progressBar, {
    x: num + "%",
    duration: 2,
  });
}

window.addEventListener('load', function(ev) {
  var loading = document.querySelector('#loading');
  loading.textContent = "Loading entrypoint...";
  updateProgress(15);
  _flutter.loader.loadEntrypoint({
    serviceWorker: {
      serviceWorkerVersion: serviceWorkerVersion,
    },
    onEntrypointLoaded: async function(engineInitializer) {
      loading.textContent = "Initializing engine...";
      updateProgress(50);
      let appRunner = await engineInitializer.initializeEngine();
      updateProgress(80);
      loading.textContent = "Running app...";
      await appRunner.runApp();
      updateProgress(100);
    }
  });
});
Woolgrower answered 12/2, 2023 at 11:42 Comment(0)
N
1

In addition to answers from @Shahzad and @BambinoUA, I also needed to add defer keyword for main.dart.js script tag as well.

<script defer src="main.dart.js" type="application/javascript"></script>

Below is my scenario where this was needed:

  • app was hosted on Gitlab pages
  • browser was Chrome (with a slow internet)

In this case, only blank screen was visible until the whole script is downloaded. Then the animation was visible only for 0.5 second and flutter widgets loaded immediately after that. Thus failing the purpose of having loading animation. This doesn't happen in local testing.

I also tried putting the animation div before all scripts, but it didn't help.

Naturally answered 26/7, 2021 at 13:11 Comment(0)
K
0

During startup of a flutter web app, we have the 2 phases: the first phase is when the index.html page has already loaded but the actually flutter app is loading. Then when the flutter app is loaded, we still might need to do some preparation within the flutter app. I like both phases to show an indication of loading and I want this to be the same. So... what I did:

  1. First my index.html displays a gif which shows a circular progress indicator similar to the one I have in flutter (see 2) loading.gif

I do this similar to what this person describes: https://retroportalstudio.medium.com/indicate-website-loading-for-flutter-web-apps-7dc5e2c59e24

  1. Then in my flutter app, I show this indicator:

    return Container( decoration: BoxDecoration(color: Colors.white), child: Center(child: CircularProgressIndicator()) );

This indicator is pretty much the same as the gif. I created this gif with a combination of https://gifcap.dev/ and gimp to crop it.

The result is a fairly smooth loading circular progress indicator almost instant upon opening my website all the way up to when my flutterweb app opens.

Kennakennan answered 26/7, 2022 at 11:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.