drawer_demo.dart 8.9 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/gestures.dart' show DragStartBehavior;
6
import 'package:flutter/material.dart';
7

8 9
import '../../gallery/demo.dart';

10 11 12
const String _kAsset0 = 'people/square/trevor.png';
const String _kAsset1 = 'people/square/stella.png';
const String _kAsset2 = 'people/square/sandra.png';
13
const String _kGalleryAssetsPackage = 'flutter_gallery_assets';
14 15

class DrawerDemo extends StatefulWidget {
16
  const DrawerDemo({super.key});
17

18
  static const String routeName = '/material/drawer';
19 20

  @override
21
  State<DrawerDemo> createState() => _DrawerDemoState();
22 23 24
}

class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
25
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
26

27
  static const List<String> _drawerContents = <String>[
28 29 30
    'A', 'B', 'C', 'D', 'E',
  ];

31 32 33 34 35 36 37
  static final Animatable<Offset> _drawerDetailsTween = Tween<Offset>(
    begin: const Offset(0.0, -1.0),
    end: Offset.zero,
  ).chain(CurveTween(
    curve: Curves.fastOutSlowIn,
  ));

38 39 40
  late AnimationController _controller;
  late Animation<double> _drawerContentsOpacity;
  late Animation<Offset> _drawerDetailsPosition;
41 42 43 44 45
  bool _showDrawerContents = true;

  @override
  void initState() {
    super.initState();
46
    _controller = AnimationController(
47 48 49
      vsync: this,
      duration: const Duration(milliseconds: 200),
    );
50 51
    _drawerContentsOpacity = CurvedAnimation(
      parent: ReverseAnimation(_controller),
52 53
      curve: Curves.fastOutSlowIn,
    );
54
    _drawerDetailsPosition = _controller.drive(_drawerDetailsTween);
55 56 57 58 59 60 61 62
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

63
  IconData? _backIcon() {
64 65 66
    switch (Theme.of(context).platform) {
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
67 68
      case TargetPlatform.linux:
      case TargetPlatform.windows:
69 70
        return Icons.arrow_back;
      case TargetPlatform.iOS:
71
      case TargetPlatform.macOS:
72 73 74 75 76
        return Icons.arrow_back_ios;
    }
  }

  void _showNotImplementedMessage() {
77
    Navigator.pop(context); // Dismiss the drawer.
78
    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
79
      content: Text("The drawer's items don't do anything"),
80 81 82 83 84
    ));
  }

  @override
  Widget build(BuildContext context) {
85
    return Scaffold(
86
      drawerDragStartBehavior: DragStartBehavior.down,
87
      key: _scaffoldKey,
88 89 90
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(_backIcon()),
91
          alignment: Alignment.centerLeft,
92 93 94 95 96
          tooltip: 'Back',
          onPressed: () {
            Navigator.pop(context);
          },
        ),
97
        title: const Text('Navigation drawer'),
98
        actions: <Widget>[MaterialDemoDocumentationButton(DrawerDemo.routeName)],
99
      ),
100 101
      drawer: Drawer(
        child: Column(
102
          children: <Widget>[
103
            UserAccountsDrawerHeader(
104 105
              accountName: const Text('Trevor Widget'),
              accountEmail: const Text('trevor.widget@example.com'),
106
              currentAccountPicture: const CircleAvatar(
107
                backgroundImage: AssetImage(
108 109 110 111
                  _kAsset0,
                  package: _kGalleryAssetsPackage,
                ),
              ),
112
              otherAccountsPictures: <Widget>[
113
                GestureDetector(
114
                  dragStartBehavior: DragStartBehavior.down,
115 116 117
                  onTap: () {
                    _onOtherAccountsTap(context);
                  },
118
                  child: Semantics(
119 120
                    label: 'Switch to Account B',
                    child: const CircleAvatar(
121
                      backgroundImage: AssetImage(
122 123 124 125
                        _kAsset1,
                        package: _kGalleryAssetsPackage,
                      ),
                    ),
126 127
                  ),
                ),
128
                GestureDetector(
129
                  dragStartBehavior: DragStartBehavior.down,
130 131 132
                  onTap: () {
                    _onOtherAccountsTap(context);
                  },
133
                  child: Semantics(
134 135
                    label: 'Switch to Account C',
                    child: const CircleAvatar(
136
                      backgroundImage: AssetImage(
137 138 139 140
                        _kAsset2,
                        package: _kGalleryAssetsPackage,
                      ),
                    ),
141 142
                  ),
                ),
143
              ],
144
              margin: EdgeInsets.zero,
145 146
              onDetailsPressed: () {
                _showDrawerContents = !_showDrawerContents;
147
                if (_showDrawerContents) {
148
                  _controller.reverse();
149
                } else {
150
                  _controller.forward();
151
                }
152 153
              },
            ),
154
            MediaQuery.removePadding(
155 156 157
              context: context,
              // DrawerHeader consumes top MediaQuery padding.
              removeTop: true,
158 159
              child: Expanded(
                child: ListView(
160
                  dragStartBehavior: DragStartBehavior.down,
161 162
                  padding: const EdgeInsets.only(top: 8.0),
                  children: <Widget>[
163
                    Stack(
164 165
                      children: <Widget>[
                        // The initial contents of the drawer.
166
                        FadeTransition(
167
                          opacity: _drawerContentsOpacity,
168
                          child: Column(
169 170
                            mainAxisSize: MainAxisSize.min,
                            crossAxisAlignment: CrossAxisAlignment.stretch,
171
                            children: _drawerContents.map<Widget>((String id) {
172 173 174
                              return ListTile(
                                leading: CircleAvatar(child: Text(id)),
                                title: Text('Drawer item $id'),
175 176 177
                                onTap: _showNotImplementedMessage,
                              );
                            }).toList(),
178
                          ),
179 180
                        ),
                        // The drawer's "details" view.
181
                        SlideTransition(
182
                          position: _drawerDetailsPosition,
183 184 185
                          child: FadeTransition(
                            opacity: ReverseAnimation(_drawerContentsOpacity),
                            child: Column(
186 187 188
                              mainAxisSize: MainAxisSize.min,
                              crossAxisAlignment: CrossAxisAlignment.stretch,
                              children: <Widget>[
189
                                ListTile(
190 191 192 193
                                  leading: const Icon(Icons.add),
                                  title: const Text('Add account'),
                                  onTap: _showNotImplementedMessage,
                                ),
194
                                ListTile(
195 196 197 198 199 200
                                  leading: const Icon(Icons.settings),
                                  title: const Text('Manage accounts'),
                                  onTap: _showNotImplementedMessage,
                                ),
                              ],
                            ),
201
                          ),
202 203
                        ),
                      ],
204
                    ),
205 206
                  ],
                ),
207 208 209 210 211
              ),
            ),
          ],
        ),
      ),
212 213
      body: Center(
        child: InkWell(
214
          onTap: () {
215
            _scaffoldKey.currentState!.openDrawer();
216
          },
217
          child: Semantics(
218 219 220
            button: true,
            label: 'Open drawer',
            excludeSemantics: true,
221
            child: Column(
222 223
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
224
                Container(
225 226 227 228
                  width: 100.0,
                  height: 100.0,
                  decoration: const BoxDecoration(
                    shape: BoxShape.circle,
229 230
                    image: DecorationImage(
                      image: AssetImage(
231 232 233
                        _kAsset0,
                        package: _kGalleryAssetsPackage,
                      ),
234
                    ),
235 236
                  ),
                ),
237
                Padding(
238
                  padding: const EdgeInsets.only(top: 8.0),
239
                  child: Text('Tap here to open the drawer',
240
                    style: Theme.of(context).textTheme.titleMedium,
241
                  ),
242
                ),
243 244
              ],
            ),
245 246 247 248 249
          ),
        ),
      ),
    );
  }
250 251

  void _onOtherAccountsTap(BuildContext context) {
252
    showDialog<void>(
253
      context: context,
254
      builder: (BuildContext context) {
255
        return AlertDialog(
256 257
          title: const Text('Account switching not implemented.'),
          actions: <Widget>[
258
            TextButton(
259 260
              child: const Text('OK'),
              onPressed: () {
261
                Navigator.pop(context);
262 263 264 265 266
              },
            ),
          ],
        );
      },
267 268
    );
  }
269
}