100
1 mars 2019

Menu Drawer dans Flutter

Menu Drawer dans Flutter

Cette fois-ci, nous allons voir comment ajouter un menu drawer dans le Flutter, pour continuer notre apprentissage sur ce nouveau framework fournit par Google. Vous pouvez aussi lire la doc officielle de Flutter dans la section design.

La “navigation drawer”, que l’on peut traduire par “navigation à tiroirs”, est bien connue des développeurs Android. Elle existe depuis longtemps et a même été adaptée pour les application iOS. Ce type de menu est souvent placé sur la gauche de votre application avec une icone dans la toolbar pour le faire apparaître. On peut aussi faire glisser un doigt du bord gauche de l’écran jusqu’au centre. Il est masqué lorsqu’il n’est pas utilisé afin d’optimiser l’affichage sur le smartphone.

On le couple souvent avec des fragments sur Android. Nous allons donc voir comment simplement l’implémenter, le customiser et le coupler dans des vues types fragments composer de webviews. Pour les webviews, vous pouvez lire notre article : webview-dans-flutter.

Ajouter un menu drawer dans flutter

En suivant la documentation officielle de Flutter et le très bon article de Kashif Minhaj sur medium, il est assez simple de créer un menu drawer dans Flutter.

Dans un premier temps, nous allons faire une simple liste d’items, puis nous verrons comment optimiser notre code.
Pas besoin d’ajouter de package pour faire votre menu, en voici un avec trois items redirigeant vers l’équivalent de fragments Flutter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<pre>import 'package:flutter/material.dart';

import 'package:hmwkapp/first_fragment.dart';
import 'package:hmwkapp/second_fragment.dart';
import 'package:hmwkapp/third_fragment.dart';

void main() =&gt; runApp(MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "hmwkapp",
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() =&gt; new _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {

  int _selectedDrawerIndex = 0;

  _getDrawerItemWidget(int pos) {
    switch (pos) {
      case 0:
        return new FirstFragment();
      case 1:
        return new SecondFragment();
      case 2:
        return new ThirdFragment();

      default:
        return new Text("");
    }
  }

  @override
  Widget build(BuildContext context) {

    return new Scaffold(

      appBar: new AppBar(
        title: const Text('hmwkapp'),
      ),

      drawer: new Drawer(
        child: new ListView(
          children: &lt;Widget&gt;[

            DrawerHeader(
              child: Text('Drawer Header'),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),

            ListTile(
              title: Text("Ttem 1"),
              leading: Icon(Icons.home),
              selected: _selectedDrawerIndex == 0,
              onTap: () {
                setState(() =&gt; _selectedDrawerIndex = 0);
                Navigator.of(context).pop(); // close the drawer
              },
            ),

            ListTile(
              title: Text("Ttem 2"),
              leading: Icon(Icons.info),
              selected: _selectedDrawerIndex == 1,
              onTap: () {
                setState(() =&gt; _selectedDrawerIndex = 1);
                Navigator.of(context).pop(); // close the drawer
              },
            ),

            ListTile(
              title: Text("Ttem 3"),
              leading: Icon(Icons.web),
              selected: _selectedDrawerIndex == 2,
              onTap: () {
                setState(() =&gt; _selectedDrawerIndex = 2);
                Navigator.of(context).pop(); // close the drawer
              },
            ),

          ],
        ),
      ),

      body: _getDrawerItemWidget(_selectedDrawerIndex),

    );
  }
}</pre>

Optimiser le menu drawer dans le flutter

Maintenant, regardons comment optimiser rapidement le code, avec un object drawerItem et une fonction _onselectItem()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<pre>import 'package:flutter/material.dart';

import 'package:hmwkapp/first_fragment.dart';
import 'package:hmwkapp/second_fragment.dart';
import 'package:hmwkapp/third_fragment.dart';

void main() =&gt; runApp(MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "hmwkapp",
      home: new MyHomePage(),
    );
  }
}

class DrawerItem {
  String title;
  IconData icon;
  DrawerItem(this.title, this.icon);
}

class MyHomePage extends StatefulWidget {

  final drawerItems = [
    new DrawerItem("Fragment 1", Icons.home),
    new DrawerItem("Fragment 2", Icons.info),
    new DrawerItem("Fragment 3", Icons.web),
  ];

  @override
  _MyHomePageState createState() =&gt; new _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {

  int _selectedDrawerIndex = 0;

  _getDrawerItemWidget(int pos) {
    switch (pos) {
      case 0:
        return new FirstFragment();
      case 1:
        return new SecondFragment();
      case 2:
        return new ThirdFragment();

      default:
        return new Text("");
    }
  }

  _onSelectItem(int index) {
    setState(() =&gt; _selectedDrawerIndex = index);
    Navigator.of(context).pop(); // close the drawer
  }

  @override
  Widget build(BuildContext context) {

    var drawerOptions = &lt;Widget&gt;[];

    for (var i = 0; i &lt; widget.drawerItems.length; i++) {
      var d = widget.drawerItems[i];
      drawerOptions.add(
          new ListTile(
            leading: new Icon(d.icon),
            title: new Text(d.title),
            selected: i == _selectedDrawerIndex,
            onTap: () =&gt; _onSelectItem(i),
          )
      );
    }

    return new Scaffold(

      appBar: new AppBar(
        title: new Text(widget.drawerItems[_selectedDrawerIndex].title),
      ),

      drawer: new Drawer(
        child: new ListView(
          children: &lt;Widget&gt;[

            DrawerHeader(
              child: Text('Drawer Header'),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),

            new Column(children: drawerOptions),
          ],
        ),
      ),

      body: _getDrawerItemWidget(_selectedDrawerIndex),

    );
  }
}</pre>

Il est aussi possible de changer l’icone du menu drawer de la toolbar dans Flutter. Il vous suffit d’utiliser une key dans votre Scaffold et d’appeler _scaffoldKey.currentState.openDrawer()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<pre>class _MyHomePageState extends State&lt;MyHomePage&gt; {

  final GlobalKey&lt;ScaffoldState&gt; _scaffoldKey = new GlobalKey&lt;ScaffoldState&gt;();

  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      key: _scaffoldKey,

      appBar: new AppBar(
        title: const Text('hmwkapp'),
        leading: new IconButton(icon: new Icon(Icons.apps),
            onPressed:() =&gt; _scaffoldKey.currentState.openDrawer()),
      ),

      drawer: new Drawer(
      ),

    );
  }
}</pre>

Compléter fragments avec un menu drawer dans flutter

Pour finir notre explication du menu drawer, il vous faudra créer les fragments associés que les items appellent au clic.

exemple :

1
2
3
4
5
6
7
8
9
10
<pre>import 'package:flutter/material.dart';

class FirstFragment extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text("Hello Fragment 1"),
    );
  }
}</pre>

Vous pouvez aussi le coupler avec des webviews.
Ajoutez le package webview_flutter: ^0.3.1 dans votre fichier pubspec.yaml

exemple :

1
2
3
4
5
6
7
8
9
10
11
12
<pre>import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class SecondFragment extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return WebView(
      initialUrl: 'https://homework.family',
      javascriptMode: JavascriptMode.unrestricted,
    );
  }
}</pre>

On peut aussi faire des liens directs dans notre menu qui redirigeront sur le web.
Ajoutez le package url_launcher: ^4.0.3 dans votre fichier pubspec.yaml

exemple :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<pre>import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

void main() =&gt; runApp(MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: "hmwkapp",
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() =&gt; new _MyHomePageState();
}

class _MyHomePageState extends State&lt;MyHomePage&gt; {

  _launchUrlHmwk() async {
    const url = 'https://homework.family';
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw '';
    }
  }

  @override
  Widget build(BuildContext context) {

    return new Scaffold(

      appBar: new AppBar(
        title: const Text('hmwkapp'),
      ),

      drawer: new Drawer(
        child: new ListView(
          children: &lt;Widget&gt;[

            DrawerHeader(
              child: Text('Drawer Header'),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),

            ListTile(
              title: Text("Ttem 3"),
              leading: Icon(Icons.web),
              selected: _selectedDrawerIndex == 2,
              onTap: () {
                _launchUrlHmwk();
                Navigator.of(context).pop(); // close the drawer
              },
            ),

          ],
        ),
      ),

    );
  }
}</pre>

VOUS EN VOULEZ ENCORE ?

CHANGER D'UNIVERS !