Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Exception caught by gesture. No MediaQuery widget found inside showModalBottomSheet

Why I can't use showModalBottomSheet inside floatingActionButton? It just keeps showing me this error:

I/flutter (16368): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter (16368): The following assertion was thrown while handling a gesture:
I/flutter (16368): No MediaQuery widget found.
I/flutter (16368): MyApp widgets require a MediaQuery widget ancestor.
I/flutter (16368): The specific widget that could not find a MediaQuery ancestor was:
I/flutter (16368):   MyApp
I/flutter (16368): The ownership chain for the affected widget is: "MyApp ← [root]"
I/flutter (16368): Typically, the MediaQuery widget is introduced by the MaterialApp or WidgetsApp widget at the top of
I/flutter (16368): your application widget tree.
I/flutter (16368): 
I/flutter (16368): When the exception was thrown, this was the stack:
I/flutter (16368): #0      debugCheckHasMediaQuery.<anonymous closure> (package:flutter/src/widgets/debug.dart:211:7)
I/flutter (16368): #1      debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:223:4)
I/flutter (16368): #2      showModalBottomSheet (package:flutter/src/material/bottom_sheet.dart:469:10)
I/flutter (16368): #3      _MyAppState.build.<anonymous closure> (package:flutter_happy_habits/main.dart:32:29)
I/flutter (16368): #4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:706:14)
import 'package:flutter/material.dart';
import './models/home.dart';
import 'models/progress.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _selectedPage = 0;
  final _pageOptions = [
    Home(),
    Progress(),
    Progress(),
  ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: true,
      home: new Scaffold(
        appBar: AppBar(title: Text('Flutter Demo')),
        body: _pageOptions[_selectedPage],
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () { showModalBottomSheet(
            context: context,
            builder: (context) {
              return Text('Modal bottom sheet', style: TextStyle(fontSize: 30));
            });
          }
        ),
        bottomNavigationBar: BottomAppBar(
          shape: CircularNotchedRectangle(),
          notchMargin: 4.0,
          child: new Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              IconButton(
                icon: Icon(Icons.home),
                onPressed: () {
                  print("Home");
                  setState(() {
                    _selectedPage = 0;
                  });
                },
              ),
              IconButton(
                icon: Icon(Icons.insert_chart),
                onPressed: () {
                  print("Progress");
                  setState(() {
                    _selectedPage = 1;
                  });
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
like image 623
phongyewtong Avatar asked Nov 28 '22 01:11

phongyewtong


2 Answers

Its because, the showModalBottomSheet tries to access the ancestor of type MaterialApp from the given context.

Use Builder widget to get new context with MaterialApp ancestor or Separate your MaterialAapp and Scaffold widgets into separate widgets.

Using Builder :

floatingActionButton: Builder(
  builder: (context) => FloatingActionButton(
      child: Icon(Icons.add),
      onPressed: () { showModalBottomSheet(
          context: context,
          builder: (context) {
            return Text('Modal bottom sheet', style: TextStyle(fontSize: 30));
          });
      }
  ),
),
like image 153
Crazy Lazy Cat Avatar answered Dec 23 '22 14:12

Crazy Lazy Cat


I've got a solution. I don't know if it's the best but it works. The showModalBottomSheet should not have the same context as the materialapp, so it must be separated in a statelesswidget as you can see in this example.

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter App',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {

    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(title: const Text('Modal bottom sheet')),
        body: new Center(
          child: new RaisedButton(
            child: const Text('SHOW BOTTOM SHEET'),
            onPressed: () {
              showModalBottomSheet<void>(context: context, builder: (BuildContext context) {
                return new Container(
                  child: new Padding(
                    padding: const EdgeInsets.all(32.0),
                    child: new Text('This is the modal bottom sheet. Click anywhere to dismiss.',
                      textAlign: TextAlign.center,
                      style: new TextStyle(
                        color: Theme.of(context).accentColor,
                        fontSize: 24.0
                      )
                    )
                  )
                );
              });
            }
          )
        )
      )
    );
  }
}
like image 44
javier Balsas Avatar answered Dec 23 '22 12:12

javier Balsas