Responsive Web And Desktop Development With Flutter

Flutter has already made pretty a splash on the cell enchancment scene. Now it’s taking on larger models as successfully. Here’s what it’s best to know to have the ability to deal with the responsibility of making internet and desktop apps using this glorious cross-platform framework.

This tutorial is not going to be an introduction to Flutter itself. There are a great deal of articles, films and a number of other different books obtainable on-line with straightforward introductions that may help you be taught the basics of Flutter. Instead, we’ll be defending the following two targets:

  1. The current state of Flutter non-mobile enchancment and the way one can run Flutter code inside the browser, on a desktop or laptop computer pc laptop computer;
  2. How to create responsive apps using Flutter, with the intention to see its vitality — notably as an web framework — on full present, ending with a discover about routing based mostly totally on URL.

Let’s get into it!

What Is Flutter, Why It’s Important, What It Has Evolved Into, Where It’s Going

Flutter is Google’s latest app enchancment framework. Google envisions it to be all-encompassing: It will enable the similar code to be executed on smartphones of all producers, on tablets, and on desktop and laptops laptop computer as native apps or as internet pages.

It’s a extremely formidable endeavor, nevertheless Google has been extraordinarily worthwhile until now notably in two components: in creating a really platform-independent framework for Android and iOS native apps that works good and is completely ready for manufacturing use, and in making a formidable front-end internet framework which will share 100% of the code with a applicable Flutter app.

In the next half, we’re going to see what makes the app applicable and what’s the state of non-mobile Flutter enchancment as of now.

Our wise handbook, whereby Alla Kholmatova explores the proper strategy to create environment friendly and maintainable design strategies to design good digital merchandise. Meet Design Systems, with widespread traps, gotchas and the teachings Alla has realized over time.Jump to table of contents ↬

Non-Mobile Development With Flutter

Non-mobile enchancment with Flutter was first publicized in a giant method at Google I/O 2019. This half is about the proper strategy to make it work and about when it actually works.

HOW TO ENABLE WEB AND DESKTOP DEVELOPMENT

To enable internet enchancment, you should first be on Flutter’s beta channel. There are two strategies to get to that point:

  • Install Flutter instantly on the beta channel by downloading the appropriate latest beta mannequin from the SDK archive.
  • If you already have Flutter put in, swap to the beta channel with $ flutter channel beta, after which perform the swap itself by updating your Flutter mannequin (which is certainly a git pull on the Flutter arrange folder) with $ flutter enhance.

After that, you’ll run this:

$ flutter config --enable-web

 

Desktop assist is way extra experimental, notably as a consequence of an absence of tooling for Linux and Windows, making plugin enchancment notably a big ache, and as a consequence of the reality that the APIs used for it are meant for proof-of-concept use and by no means for manufacturing. This is in distinction to internet enchancment, which is using the tried-and-tested dart2js compiler for launch builds, which are not even supported for Windows and Linux native desktop apps.

NoteSupport for macOS is barely greater than assist for Windows and Linux, nevertheless it nonetheless isn’t just about nearly as good as assist for the net and by no means nearly just about nearly as good as the whole assist for cell platforms.

To enable assist for desktop enchancment, it’s best to swap to the grasp launch channel by following the similar steps outlined earlier for the beta channel. Then, run the following by altering <OS_NAME> with each linuxdwelling home windows, or macos:

$ flutter config --enable-<OS_NAME>-desktop

 

At this stage, you in all probability have factors with any of the following steps that I’ll be describing because of the Flutter instrument isn’t doing what I’m saying it should do, some widespread troubleshooting steps are these:

  • Run flutter doctor to look at for factors. A facet influence of this Flutter command is that it should receive any devices it needs that it doesn’t have.
  • Run flutter enhance.
  • Turn it on and off as soon as extra. The outdated tier-1 technical-support reply of restarting your laptop computer is prone to be merely what’s required so that you can have the power to profit from the complete riches of Flutter.

RUNNING AND BUILDING FLUTTER WEB APPS

Flutter internet assist isn’t unhealthy the least bit, and that’s mirrored inside the ease of enchancment for the net.

Running this…

$ flutter models

 

… should current immediately an entry for one factor like this:

Web Server • web-server • web-javascript • Flutter Tools

 

Additionally, working the Chrome browser should set off Flutter to level out an entry for it as successfully. Running flutter run on a applicable Flutter endeavor (additional on that later) when the one “connected device” displaying up is the net server will set off Flutter to start an web server on localhost:<RANDOM_PORT>, which is ready to imply you possibly can entry your Flutter internet app from any browser.

If you’ve got put in Chrome nevertheless it’s not displaying up, it’s best to set the CHROME_EXECUTABLE ambiance variable to the path to the Chrome executable file.

RUNNING AND BUILDING FLUTTER DESKTOP APPS

After you’ve enabled Flutter desktop assist, you’ll run a Flutter app natively in your enchancment workstation with flutter run -d <OS_NAME>, altering <OS_NAME> with the similar price you used when enabling desktop assist. You can also assemble binaries inside the assemble itemizing with flutter assemble <OS_NAME>.

Before you’ll be able to do any of that, though, it’s best to have an inventory containing what Flutter should assemble in your platform. This will doubtless be created routinely for those who create a model new endeavor, nevertheless you’ll need to create it for an present endeavor with flutter create .. Also, the Linux and Windows APIs are unstable, so that you could be must regenerate them for these platforms if the app stops working after a Flutter change.

WHEN IS AN APP COMPATIBLE?

What have I meant all alongside when mentioning {{that a}} Flutter app must be a “compatible project” to make sure that it to work on desktop or the net? Put merely, I indicate that it mustn’t use any plugin that doesn’t have a platform-specific implementation for the platform on which you’re making an attempt to assemble.

To make this stage utterly clear to all people and stay away from misunderstanding, please discover {{that a}} Flutter plugin is a specific Flutter bundle that accommodates platform-specific code that is important for it to provide its choices.

For occasion, it’s best to use the Google-developed url_launcher package as so much as you want (and in addition you might must, given that the net is constructed on hyperlinks).

An occasion of a Google-developed bundle the utilization of which could preclude internet enchancment is path_provider, which is used to get the native storage path to keep away from losing info to. This is an occasion of a bundle that, by the best way, isn’t of any use to an web app, so not with the power to make use of it isn’t really a bummer, other than the reality that it’s best to change your code to make sure that it to work on the web in case you’re using it.

For occasion, it’s best to use the shared_preferences bundle, which is dependent upon HTML localStorage on the web.

Similar caveats are professional regarding desktop platforms: Very few plugins are applicable with desktop platforms, and, as it’s a recurring theme, way more work on this should be carried out on the desktop facet than is de facto important on Flutter for the net.

Creating Responsive Layouts In Flutter

Because of what I’ve described above and for simplicity, I’m going to think about for the rest of this publish that your aim platform is the net, nevertheless the elemental concepts apply to desktop enchancment as successfully.

Supporting the net has benefits and duties. Being nearly compelled to assist completely completely different show display screen sizes might sound like a draw back, nevertheless take into consideration that working the app inside the internet browsers allows you to see very merely how your app will look on screens of varied sizes and aspect ratios, with out having to run separate cell gadget emulators.

Now, let’s focus on code. How can you make your app responsive?

There are two views from which this analysis is completed:

  1. “What widgets am I using or can I use that can or should adapt to screens of different sizes?”
  2. “How can I get information about the size of the screen, and how can I use it when writing UI code?”

We’ll reply the first question later. Let’s first focus on in regards to the latter, because of it could be dealt with very merely and is on the coronary coronary heart of the problem. There are two strategies to do this:

  1. One method is to take the info from the MediaQueryData of the MediaQuery root InheritedWidget, which has to exist inside the widget tree to make sure that a Flutter app to work (it’s part of SuppliesApp/WidgetsApp/CupertinoApp), which you’ll get, similar to another InheritedWidget, with MediaQuery.of(context), which has a measurement property, which is of form Size, and which as a consequence of this reality has two width and peak properties of the type double.
  2. The completely different method is to utilize a LayoutBuilder, which is a builder widget (similar to a StreamBuilder or a FutureBuilder) that passes to the builder carry out (along with the context) a BoxConstraints object that has minHeightmaxHeightminWidth and maxWidth properties.

Here’s an example DartPad using the MediaQuery to get constraints, the code for which is the following:

import 'bundle:flutter/supplies.dart';

void important() => runApp(MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget assemble(context) =>
    SuppliesApp(
      residence: MyHomePage()
    );


class MyHomePage extends StatelessWidget {
  @override
  Widget assemble(context) =>
    Scaffold(
      physique: Center(
        teen: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          youngsters: [
            Text(
              "Width: ${MediaQuery.of(context).size.width}",
              mannequin: Theme.of(context).textual content materialTheme.headline4
            ),
            Text(
              "Height: ${MediaQuery.of(context).size.height}",
              mannequin: Theme.of(context).textual content materialTheme.headline4
            )
          ]
       )
     )
   );
}

 

And here’s one using the LayoutBuilder for the same issue:

import 'bundle:flutter/supplies.dart';

void important() => runApp(MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget assemble(context) =>
    SuppliesApp(
      residence: MyHomePage()
    );


class MyHomePage extends StatelessWidget {
  @override
  Widget assemble(context) =>
    Scaffold(
      physique: LayoutBuilder(
        builder: (context, constraints) => Center(
          teen: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            youngsters: [
              Text(
                "Width: ${constraints.maxWidth}",
                mannequin: Theme.of(context).textual content materialTheme.headline4
              ),
              Text(
                "Height: ${constraints.maxHeight}",
                mannequin: Theme.of(context).textual content materialTheme.headline4
              )
            ]
         )
       )
     )
  );
}

 

Now, let’s think about what widgets can adapt to the constraints.

Fist of all, let’s think about the opposite methods of laying out quite a few widgets in keeping with the scale of the show display screen.

The widget that almost all merely adapts is the GridView. In fact, a GridView constructed using the GridView.extent constructor doesn’t even need your involvement to be made responsive, as you’ll see on this very simple example:

import 'bundle:flutter/supplies.dart';

void important() => runApp(MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget assemble(context) =>
    SuppliesApp(
      residence: MyHomePage()
    );


class MyHomePage extends StatelessWidget 

 

You can accommodate content material materials of varied sizes by altering the maxCrossAxisExtent.

That occasion largely served the goal of displaying the existence of the GridView.extent GridView constructor, nevertheless a so much smarter method to do this might be to utilize a GridView.builder with a SliverGridDelegateWithMaxCrossAxisExtent, on this case the place the widgets to be confirmed inside the grid are dynamically created from one different data building, as you’ll see in this example:

import 'bundle:flutter/supplies.dart';

void important() => runApp(MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget assemble(context) =>
    SuppliesApp(
      residence: MyHomePage()
    );


class MyHomePage extends StatelessWidget 
  remaining List<String> components = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];


  @override
  Widget assemble(context) =>
    Scaffold(
      physique: GridView.builder(
        itemCount: components.measurement,
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 130.0,
          crossAxisSpacing: 20.0,
          mainAxisSpacing: 20.0,
        ),
        itemBuilder: (context, i) => Card(
          teen: Center(
            teen: Padding(
              padding: EdgeInmodels.all(8.0), teen: Text(components[i])
            )
          )
        )
      )
   );

 

An occasion of GridView adapting to completely completely different screens is my personal landing page, which is a fairly easy Flutter internet app consisting of a GridView with a bunch of Cards, similar to that earlier occasion code, in addition to that the Cards are considerably additional sophisticated and greater.

A fairly easy change that might probably be made to apps designed for telephones might be to modify a Drawer with a eternal menu on the left when there’s home.

For occasion, we’d have a ListView of widgets, like the following, which is used for navigation:

class Menu extends StatelessWidget {
  @override
  Widget assemble(context) => ListView(
    youngsters: [
      FlatButton(
        onPressed: () {},
          teen: ListTile(
          foremost: Icon(Icons.looks_one),
          title: Text("First Link"),
        )
      ),
      FlatButton(
        onPressed: () {},
          teen: ListTile(
          foremost: Icon(Icons.looks_two),
          title: Text("Second Link"),
        )
      )
    ]
  );
}

 

On a smartphone, a regular place to utilize which may be inside a Drawer (typically generally known as a hamburger menu).

Alternatives to which may be the BottomNavigationBar or the TabBar, along with the TabBarView, nevertheless with every we’d ought to make additional modifications than are required with the drawer, so we’ll stick with the drawer.

To solely current the Drawer containing the Menu that we seen earlier on smaller screens, you’d write code that seems like the following snippet, checking the width using the MediaQuery.of(context) and passing a Drawer object to the Scaffold supplied that it’s decrease than some width price that we think about to be acceptable for our app:

Scaffold(
    appBar: AppBar(/* ... */),
    drawer: MediaQuery.of(context).measurement.width < 500 ?
    Drawer(
      teen: Menu(),
    ) :
    null,
    physique: /* ... */
)

 

Now, let’s think about the physique of the Scaffold. As the sample important content material materials of our app, we’ll use the GridView that we constructed beforehand, which we maintain in a separate widget named Content to stay away from confusion:

class Content extends StatelessWidget 
  remaining List components = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
  @override
  Widget assemble(context) => GridView.builder(
    itemCount: components.measurement,
    gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 130.0,
      crossAxisSpacing: 20.0,
      mainAxisSpacing: 20.0,
    ),
    itemBuilder: (context, i) => Card(
      teen: Center(
        teen: Padding(
          padding: EdgeInmodels.all(8.0), teen: Text(components[i])
        )
      )
    )
  );

 

On larger screens, the physique itself may be a Row that reveals two widgets: the Menu, which is restricted to a set width, and the Content filling the rest of the show display screen.

On smaller screens, all of the physique might be the Content.

We’ll wrap all of the items in a SafeArea and a Center widget because of usually Flutter internet app widgets, notably when using Rows and Columns, end up open air of the seen show display screen house, and that is mounted with SafeArea and/or Center.

This means the physique of the Scaffold could be the next:

SafeArea(
  teen:Center(
    teen: MediaQuery.of(context).measurement.width < 500 ? Content() :
    Row(
      youngsters: [
        Container(
          width: 200.0,
          teen: Menu()
        ),
        Container(
          width: MediaQuery.of(context).measurement.width-200.0,
          teen: Content()
        )
      ]
    )
  )
)

 

 

import 'bundle:flutter/supplies.dart';

void important() => runApp(MyApp());

class MyApp extends StatelessWidget 


class HomePage extends StatelessWidget 
  @override
  Widget assemble(context) => Scaffold(
    appBar: AppBar(title: Text("test")),
    drawer: MediaQuery.of(context).measurement.width < 500 ? Drawer(
      teen: Menu(),
    ) : null,
    physique: SafeArea(
        teen:Center(
          teen: MediaQuery.of(context).measurement.width < 500 ? Content() :
          Row(
            youngsters: [
              Container(
                width: 200.0,
                teen: Menu()
              ),
              Container(
                width: MediaQuery.of(context).measurement.width-200.0,
                teen: Content()
              )
            ]
          )
        )
    )
  );


class Menu extends StatelessWidget {
  @override
  Widget assemble(context) => ListView(
    youngsters: [
      FlatButton(
        onPressed: () {},
          teen: ListTile(
          foremost: Icon(Icons.looks_one),
          title: Text("First Link"),
        )
      ),
      FlatButton(
        onPressed: () {},
          teen: ListTile(
          foremost: Icon(Icons.looks_two),
          title: Text("Second Link"),
        )
      )
    ]
  );
}

class Content extends StatelessWidget 
  remaining List<String> components = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
  @override
  Widget assemble(context) => GridView.builder(
    itemCount: components.measurement,
    gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 130.0,
      crossAxisSpacing: 20.0,
      mainAxisSpacing: 20.0,
    ),
    itemBuilder: (context, i) => Card(
      teen: Center(
        teen: Padding(
          padding: EdgeInmodels.all(8.0), teen: Text(components[i])
        )
      )
    )
  );

 

This is lots of the stuff you’ll need as a fundamental introduction to responsive UI in Flutter. Much of its utility will rely in your app’s specific UI, and it’s exhausting to pinpoint exactly what you’ll be able to do to make your app responsive, and you may take many approaches relying in your selection. Now, though, let’s see how we’re in a position to make a additional full occasion proper right into a responsive app, severe about widespread app components and UI flows.

Putting It In Context: Making An App Responsive

So far, we have solely a show display screen. Let’s develop that proper right into a two-screen app with working URL-based navigation!

CREATING A RESPONSIVE LOGIN PAGE

Chances are that your app has a login net web page. How can we make that responsive?

Login screens on cell models are pretty comparable to at least one one other usually. The home obtainable isn’t so much; it’s usually solely a Column with some Padding spherical its widgets, and it accommodates TextTopics for typing in a username and a password and a button to log in. So, a fairly customary (though not functioning, as which will require, amongst completely different points, a TextEditingController for each TextTopic) login net web page for a cell app might probably be the following:

Scaffold(
  physique: Container(
    padding: const EdgeInmodels.symmetric(
      vertical: 30.0, horizontal: 25.0
    ),
    teen: Column(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      youngsters: [
        Text("Welcome to the app, please log in"),
        TextTopic(
          decoration: InputDecoration(
            labelText: "username"
          )
        ),
        TextTopic(
          obscureText: true,
          decoration: InputDecoration(
            labelText: "password"
          )
        ),
        RaisedButton(
          color: Colors.blue,
          teen: Text("Log in", mannequin: TextVogue(color: Colors.white)),
          onPressed: () {}
        )
      ]
    ),
  ),
)

 

It seems to be like high-quality on a cell gadget, nevertheless these very massive TextTopics start to look jarring on a tablet, to not point out a good larger show display screen. However, we’re in a position to’t merely decide on a set width because of telephones have completely completely different show display screen sizes, and we should at all times protect a stage of flexibility.

For occasion, via experimentation, we might uncover that the utmost width should be 500. Well, we’d set the Container’s constraints to 500 (I used a Container in its place of Padding inside the earlier occasion because of I knew the place I was going with this) and we’re good to go, correct? Not really, because of which will set off the login widgets to remain to the left facet of the show display screen, which is prone to be even worse than stretching all of the items. So, we wrap in a Center widget, like this:

Center(
  teen: Container(
    constraints: BoxConstraints(maxWidth: 500),
    padding: const EdgeInmodels.symmetric(
      vertical: 30.0, horizontal: 25.0
    ),
    teen: Column(/* ... */)
  )
)

 

That already seems to be like high-quality, and we haven’t even needed to make use of each a LayoutBuilder or the MediaQuery.of(context).measurement. Let’s go one step extra to make this look excellent, though. It would look greater, for my part, if the foreground half was not directly separated from the background. We can receive that by giving a background color to what’s behind the Container with the enter widgets, and retaining the foreground Container white. To make it look considerably greater, let’s maintain the Container from stretching to the very best and bottom of the show display screen on large models, give it rounded corners, and offers it a nice animated transition between the two layouts.

All of that now requires a LayoutBuilder and an outer Container in order every to set a background color and in order so as to add padding all through the Container and by no means merely on the edges solely on larger screens. Also, to make the change in padding amount animated, we merely wish to present that outer Container into an AnimatedContainer, which requires a interval for the animation, which we’ll set to half a second, which is Duration(milliseconds: 500) in code.

 

class LoginWeb web page extends StatelessWidget {
  @override
  Widget assemble(context) =>
    Scaffold(
      physique: LayoutBuilder(
        builder: (context, constraints) {
          return AnimatedContainer(
            interval: Duration(milliseconds: 500),
            color: Colors.lightGreen[200],
            padding: constraints.maxWidth < 500 ? EdgeInmodels.zero : EdgeInmodels.all(30.0),
            teen: Center(
              teen: Container(
                padding: EdgeInmodels.symmetric(
                  vertical: 30.0, horizontal: 25.0
                ),
                constraints: BoxConstraints(
                  maxWidth: 500,
                ),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.spherical(5.0),
                ),
                teen: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  youngsters: [
                    Text("Welcome to the app, please log in"),
                    TextTopic(
                      decoration: InputDecoration(
                        labelText: "username"
                      )
                    ),
                    TextTopic(
                      obscureText: true,
                      decoration: InputDecoration(
                        labelText: "password"
                      )
                    ),
                    RaisedButton(
                      color: Colors.blue,
                      teen: Text("Log in", mannequin: TextVogue(color: Colors.white)),
                      onPressed: () {
                        Navigator.pushReplacement(
                          context,
                          MaterialPageRoute(
                            builder: (context) => HomePage()
                          )
                        );
                      }  
                    )
                  ]
                ),
              ),
            )
          );
        }
      )
   );
}

 

As you’ll see, I’ve moreover modified the RaisedButton’s onPressed to a callback that navigates us to a show display screen named HomePage (which might probably be, as an illustration, the view we constructed beforehand with a GridView and a menu or a drawer). Now, though, that navigation half is what we’re going to focus on.

NAMED ROUTES: MAKING YOUR APP’S NAVIGATION MORE LIKE A PROPER WEB APP

A typical issue for internet apps to have is the pliability to change screens based mostly totally on the URL. For occasion going to https://appurl/login should give you one factor completely completely different than https://appurl/somethingelse. Flutter, in precise reality, helps named routes, which have two capabilities:

  1. In an web app, they’ve exactly that attribute that I mentioned inside the earlier sentence.
  2. In any app, they imply you possibly can predefine routes in your app and offers them names, after which be succesful to navigate to them just by specifying their title.

To do that, we’ve to alter the SuppliesApp constructor to not less than one which seems like the following:

SuppliesApp(
  initialRoute: "/login",
  routes: 
);

 

And then we’re in a position to swap to a definite route by using Navigator.pushNamed(context, routeName) and Navigator.pushReplacementNamed(context, routeName), in its place of Navigator.push(context, route) and Navigator.pushReplacement(context, route).

Here is that applied to the hypothetical app we built within the the rest of this textual content. You can’t really see named routes in movement in DartPad, so it is best to do this out by your self machine with flutter run, or check the example in action:

import 'bundle:flutter/supplies.dart';

void important() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget assemble(context) =>
    SuppliesApp(
      initialRoute: "/login",
      routes: 
    );
}

class LoginWeb web page extends StatelessWidget {
  @override
  Widget assemble(context) =>
    Scaffold(
      physique: LayoutBuilder(
        builder: (context, constraints) {
          return AnimatedContainer(
            interval: Duration(milliseconds: 500),
            color: Colors.lightGreen[200],
            padding: constraints.maxWidth < 500 ? EdgeInmodels.zero : const EdgeInmodels.all(30.0),
            teen: Center(
              teen: Container(
                padding: const EdgeInmodels.symmetric(
                  vertical: 30.0, horizontal: 25.0
                ),
                constraints: BoxConstraints(
                  maxWidth: 500,
                ),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.spherical(5.0),
                ),
                teen: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  youngsters: [
                    Text("Welcome to the app, please log in"),
                    TextTopic(
                      decoration: InputDecoration(
                        labelText: "username"
                      )
                    ),
                    TextTopic(
                      obscureText: true,
                      decoration: InputDecoration(
                        labelText: "password"
                      )
                    ),
                    RaisedButton(
                      color: Colors.blue,
                      teen: Text("Log in", mannequin: TextVogue(color: Colors.white)),
                      onPressed: () {
                        Navigator.pushReplacementNamed(
                          context,
                          "/home"
                        );
                      }
                    )
                  ]
                ),
              ),
            )
          );
        }
      )
   );
}


class HomePage extends StatelessWidget 
  @override
  Widget assemble(context) => Scaffold(
    appBar: AppBar(title: Text("test")),
    drawer: MediaQuery.of(context).measurement.width < 500 ? Drawer(
      teen: Menu(),
    ) : null,
    physique: SafeArea(
        teen:Center(
          teen: MediaQuery.of(context).measurement.width < 500 ? Content() :
          Row(
            youngsters: [
              Container(
                width: 200.0,
                teen: Menu()
              ),
              Container(
                width: MediaQuery.of(context).measurement.width-200.0,
                teen: Content()
              )
            ]
          )
        )
    )
  );


class Menu extends StatelessWidget {
  @override
  Widget assemble(context) => ListView(
    youngsters: [
      FlatButton(
        onPressed: () {},
          teen: ListTile(
          foremost: Icon(Icons.looks_one),
          title: Text("First Link"),
        )
      ),
      FlatButton(
        onPressed: () {},
          teen: ListTile(
          foremost: Icon(Icons.looks_two),
          title: Text("Second Link"),
        )
      ),
      FlatButton(
        onPressed: () {Navigator.pushReplacementNamed(
          context, "/login");},
          teen: ListTile(
          foremost: Icon(Icons.exit_to_app),
          title: Text("Log Out"),
        )
      )
    ]
  );
}

class Content extends StatelessWidget 
  remaining List<String> components = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"];
  @override
  Widget assemble(context) => GridView.builder(
    itemCount: components.measurement,
    gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 130.0,
      crossAxisSpacing: 20.0,
      mainAxisSpacing: 20.0,
    ),
    itemBuilder: (context, i) => Card(
      teen: Center(
        teen: Padding(
          padding: EdgeInmodels.all(8.0), teen: Text(components[i])
        )
      )
    )
  );

 

Onward With Your Flutter Adventure

That should give you an considered what you’ll be able to do with Flutter on larger screens, notably on the web. It’s a good looking framework, very easy to utilize, and its extreme cross-platform assist solely makes it additional vital to be taught and start using. So, go ahead and start trusting Flutter for internet apps, too!

Leave a Reply

Your email address will not be published. Required fields are marked *