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

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;
});
},
),
],
),
),
),
);
}
}

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));
});
}
),
),

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
)
)
)
);
});
}
)
)
)
);
}
}

you can put the showModalBottomSheet inside Builder() it works with me
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
(questionindex < question.length)
? Quiz(question, questionindex, nextquestion)
: Result(playagain),
Builder(
builder: (context) {
return ElevatedButton(
child: Text('Show Modal Bottom Sheet'),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Wrap(
children: [
ListTile(
leading: Icon(Icons.share),
title: Text('Share'),
),
ListTile(
leading: Icon(Icons.copy),
title: Text('Copy Link'),
),
ListTile(
leading: Icon(Icons.edit),
title: Text('Edit'),
),
],
);
},
);
},
);
},
)
],
),
),

Related

Error While Navigating From Splash Screen to the next screen in Flutter

I made stateless widget splash screen that test if the user is already logged in then will open mainhome screen immediately except that it will open sign in screen. It is working well but there is errors...
output:
E/flutter (21294): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (21294): At this point the state of the widget's element tree is no longer stable.
E/flutter (21294): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter (21294): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:4241:9)
E/flutter (21294): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:4255:6)
E/flutter (21294): #2 Element.findAncestorStateOfType (package:flutter/src/widgets/framework.dart:4322:12)
E/flutter (21294): #3 Navigator.of (package:flutter/src/widgets/navigator.dart:2549:40)
E/flutter (21294): #4 SplashScreen.build.<anonymous closure> (package:fbissalama/Screens/splashscreen.dart:20:18)
E/flutter (21294): #5 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
E/flutter (21294): #6 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
E/flutter (21294): #7 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
E/flutter (21294): #8 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<Following>(
create: (BuildContext context) => Following(),
),
ChangeNotifierProvider<ProviderController>(
create: (BuildContext context) => ProviderController(),
),
ChangeNotifierProvider<Verifying>(
create: (BuildContext context) => Verifying(),
),
//TODO
//Add AuthController Here...
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: "Bissalama",
onGenerateRoute: onGenerate,
initialRoute: AppRoutes.splashScreenPage,
routes: {
AppRoutes.loginPage: (context) => const SignInScreen(),
AppRoutes.splashScreenPage: (context) => const SplashScreen(),
AppRoutes.mainHomePage: (context) => const MainHome(),
AppRoutes.addJourneyPage: (context) => const AddJourneyPage(),
AppRoutes.currentJourneyPage: (context) => const CurrentJourneyPage(),
AppRoutes.favoriteJourneyPage: (context) => const FavoritePage(),
AppRoutes.settingsPage: (context) => const SettingsPage(),
AppRoutes.aboutPage: (context) => const AboutPage(),
},
),
),
);
}
splashscreen.dart:
class SplashScreen extends StatelessWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Timer(const Duration(seconds: 1), () {
final String? user = FirebaseAuth.instance.currentUser?.phoneNumber;
final String? user1 = FirebaseAuth.instance.currentUser?.email;
if (user1 != null || user != null) {
Navigator.of(context).pushReplacementNamed('/home');
} else {
Navigator.of(context).pushReplacementNamed('/');
}
});
return Scaffold(
body: Container(
color: Colors.blueAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
AppAssets.busIcon,
fit: BoxFit.fitHeight,
),
),
const SizedBox(
height: 20,
),
Text(
"Bissalama",
style: GoogleFonts.lobster(
textStyle: const TextStyle(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.bold),
),
),
const SizedBox(
height: 20,
),
const SpinKitPouringHourGlassRefined(
color: Colors.white, size: 50.0),
],
),
),
);
}
}
I searched A lot about this problem I may recognize the problem, maybe I'm using a context which is disposed like I'm navigating with a disposed context, I didn't see any Solution.
How Can I solve this Error in Stateless widget.
class SplashScreen extends StatelessWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: Future.delayed(const Duration(seconds: 1), () async {
final String? user = FirebaseAuth.instance.currentUser?.phoneNumber;
final String? user1 = FirebaseAuth.instance.currentUser?.email;
if (user1 != null || user != null) {
Navigator.of(context).pushReplacementNamed('/home');
} else {
Navigator.of(context).pushReplacementNamed('/');
}
}),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Container(
color: Colors.blueAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
AppAssets.busIcon,
fit: BoxFit.fitHeight,
),
),
const SizedBox(
height: 20,
),
Text(
"Bissalama",
style: GoogleFonts.lobster(
textStyle: const TextStyle(color: Colors.white, fontSize: 30, fontWeight: FontWeight.bold),
),
),
const SizedBox(
height: 20,
),
const SpinKitPouringHourGlassRefined(color: Colors.white, size: 50.0),
],
),
);
},
),
);
}
}
Try this

Why is the showModalBottomSheet() function not working [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Why is this code not working and the bottom sheet is not getting displayed. I've also retried running the code and still it doesn't work. I want to show a modal bottom sheet in flutter on a button click.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
void startInputAction(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (_) {
return Container(
height: 200,
padding: EdgeInsets.all(10),
child: Text("Something"),
);
},
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Error Practice Bottom Sheet"),
backgroundColor: Colors.purple,
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.purple,
padding: EdgeInsets.all(20),
child: Text("Click here"),
onPressed: () => startInputAction(context),
)
],
),
),
),
);
}
}
MateriaApp is at same level that's why you are getting this error.
Following code will solve your issue.
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
void startInputAction(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (_) {
return Container(
height: 200,
padding: EdgeInsets.all(10),
child: Text("Something"),
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Error Practice Bottom Sheet"),
backgroundColor: Colors.purple,
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.purple,
padding: EdgeInsets.all(20),
child: Text("Click here"),
onPressed: () => startInputAction(context))
],
),
),
);
}
}
Check out this example in the Flutter docs.
https://api.flutter.dev/flutter/material/showModalBottomSheet.html
Your issue might have to do with you passing the same BuildContext from the Scaffold. You should at least add a Builder widget in the body parameter of Scaffold to get the appropriate context required for this widget.
Here's the code:
class _MyAppState extends State<MyApp> {
void startInputAction(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (_) {
return Container(
height: 200,
padding: EdgeInsets.all(10),
child: Text("Something"),
);
},
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Error Practice Bottom Sheet"),
backgroundColor: Colors.purple,
),
body: Builder(
builder: (context) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.purple,
padding: EdgeInsets.all(20),
child: Text("Click here"),
onPressed: () => startInputAction(context),
)
],
),
);
},
),
),
);
}
}
As #Viren suggested, you need to have a MaterialApp in your code.
Check the code below:
import 'package:flutter/material.dart';
void main() => runApp(
// add your material app here
MaterialApp(
home: MyApp(),
),
);
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
void startInputAction(BuildContext context){
showModalBottomSheet(
context: context,
builder: (_){
return Container(
height: 200,
padding: EdgeInsets.all(10),
child: Text("Something"),
);
}
)
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Error Practice Bottom Sheet"),
backgroundColor: Colors.purple,
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
color: Colors.purple,
padding: EdgeInsets.all(20),
child: Text("Click here"),
onPressed: () => startInputAction(context)
)
],
),
),
),
);
}
}

Flutter/Dart Android App NoSuchMethodError

I got a quick question about a flutter/dart app I am making throwing this certain error.
It has something to do with my showadddialog class. When I press the flatbutton with the text "save" in _showAddDialog() it works fine but my app crashes if I tap out of the alert dialog window without entering anything or if I press the flatbutton named "delete", and both actions give the same error. however, when I restart I can see that the delete button still worked to delete the events from the shared preferences, it just crashed afterward. What could be causing this in my code? Idk where it could be calling a map on null...
Screenshot reference: https://gyazo.com/f894ae742ea50cd714026b1bbe753678
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building HomePage(dirty, dependencies: [_LocalizationsScope-[GlobalKey#42494], _InheritedTheme], state: _HomePageState#acde6):
The method 'map' was called on null.
Receiver: null
Tried calling: map<Widget>(Closure: (dynamic) => ListTile)
The relevant error-causing widget was
HomePage
package:hello_world/main.dart:16
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _HomePageState.build
package:hello_world/main.dart:135
#2 StatefulElement.build
package:flutter/…/widgets/framework.dart:4334
#3 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4223
#4 Element.rebuild
package:flutter/…/widgets/framework.dart:3947
...
════════════════════════════════════════════════════════════════════════════════
Code here:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:table_calendar/table_calendar.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Calendar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
CalendarController _controller;
Map<DateTime, List<dynamic>> _events;
List<dynamic> _selectedEvents;
TextEditingController _eventController;
SharedPreferences prefs;
#override
void initState() {
super.initState();
_controller = CalendarController();
_eventController = TextEditingController();
_events = {};
_selectedEvents = [];
initPrefs();
}
initPrefs() async {
prefs = await SharedPreferences.getInstance();
setState(() {
_events = Map<DateTime, List<dynamic>>.from(
decodeMap(json.decode(prefs.getString("events") ?? "{}"))
);
});
}
Map<String, dynamic> encodeMap(Map<DateTime, dynamic> map) {
Map<String, dynamic> newMap = {};
map.forEach((key, value) {
newMap[key.toString()] = map[key];
});
return newMap;
}
Map<DateTime, dynamic> decodeMap(Map<String, dynamic> map) {
Map<DateTime, dynamic> newMap = {};
map.forEach((key, value) {
newMap[DateTime.parse(key)] = map[key];
});
return newMap;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Calendar'),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TableCalendar(
events: _events,
initialCalendarFormat: CalendarFormat.week,
calendarStyle: CalendarStyle(
canEventMarkersOverflow: true,
todayColor: Colors.orange,
selectedColor: Theme.of(context).primaryColor,
todayStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white
)
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonDecoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(20.0),
),
formatButtonTextStyle: TextStyle(color: Colors.white),
formatButtonShowsNext: false,
),
startingDayOfWeek: StartingDayOfWeek.sunday,
onDaySelected: (date, events) {
setState(() {
_selectedEvents = events;
});
},
builders: CalendarBuilders(
selectedDayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(10.0)
),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
)
),
todayDayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(10.0)
),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
)
),
),
calendarController: _controller,
),
..._selectedEvents.map((event) => ListTile(
title: Text(event),
)),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _showAddDialog,
),
);
}
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
content: TextField(
controller: _eventController,
),
actions: <Widget>[
FlatButton(
child: Text("Save"),
onPressed: () {
if (_eventController.text.isEmpty) return;
if (_events[_controller.selectedDay] != null) {
_events[_controller.selectedDay].add(_eventController.text);
} else {
_events[_controller.selectedDay] = [
_eventController.text
];
}
prefs.setString("events", json.encode(encodeMap(_events)));
_eventController.clear();
Navigator.pop(context);
},
),
FlatButton(
child: Text("Delete Events"),
onPressed: () {
setState(() {
_events.remove(_controller.selectedDay);
prefs.setString("events", json.encode(encodeMap(_events)));
_eventController.clear();
Navigator.pop(context);
},
);
}
)
],
)
);
setState(() {
_selectedEvents = _events[_controller.selectedDay];
});
}
}
I have gone through your code, and handled delete event null exception as per below.
Change your last setState code with below:
setState(() {
_selectedEvents = _events[_controller.selectedDay] ?? [];
});
Conclusion:
_selectedEvents null value can be handled by ?? [] in your code.

How navigate to another screen

I have a next RaisedButton to go a next screen called DetailOracion.
Based on the example of Flutter to push new screen but doest work.
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Oraciones Cristianas'),
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailOracion()));
},
child: Text('Hello Wolrd'),
)
],
),
)),
),
);
}
My DetailOracion
class DetailOracion extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hola'),
),
body: Text('Segunda Pantalla'),
);
}
}
And the error message its the next
I/flutter ( 3441): The following assertion was thrown while handling a gesture:
I/flutter ( 3441): Navigator operation requested with a context that does not include a Navigator.
I/flutter ( 3441): The context used to push or pop routes from the Navigator must be that of a widget that is a
I/flutter ( 3441): descendant of a Navigator widget.
When used the MaterialPageRoute you need to send your main class inside of MaterialApp from runApp()
Explain with Code
Correct
void main() => runApp(MaterialApp(
title: 'Oraciones Cristianas',
home: MyApp(),
));
You send yout first Screen insde of MaterialApp(), able to use MaterialPageRoute()
Incorrect
void main() => runApp(myApp());
If you simply send your first screen without MaterialApp() wrapper doesnt works
Use a Builder around your button or around the Column as in the following code:
Builder(
builder: (context) => RaisedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) => SelectUserType()));
},
child: Text('Registrese'),
),
),

How to create Expandable ListView in Flutter

How to make an Expandable ListView using Flutter like the screenshot below?
I want to make a scrollable list view of ExpansionTileswhich when expanded shows a non-scrollable list view.
I tried to implement list view of ExpansionTiles inside which I nested another list view using listView.builder(...). But when I expanded the ExpansionTile the list view didn't show up...
(The screenshot is for illustrative purpose)
Is there a way to get similar output in Flutter?
EDIT: My Source Code:
import 'package:flutter/material.dart';
void main() => runApp(
new MaterialApp(
home: new MyApp(),
)
);
var data = {
"01/01/2018": [
["CocaCola", "\$ 5"],
["Dominos Pizza", "\$ 50"],
],
"04/01/2018": [
["Appy Fizz", "\$ 10"],
["Galaxy S9+", "\$ 700"],
["Apple iPhone X", "\$ 999"],
],
};
List<String> dataKeys = data.keys.toList();
String getFullDate(String date) {
List<String> dateSplit = date.split('/');
List<String> months = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"];
return "${dateSplit[0]} ${months[int.parse(dateSplit[1]) - 1]} ${dateSplit[2]}";
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Widget> _buildList(int keyIndex) {
List<Widget> list = [];
for (int i = 0; i < data[dataKeys[keyIndex]].length; i++) {
list.add(
new Row(
children: <Widget>[
new CircleAvatar(
child: new Icon(Icons.verified_user),
radius: 20.0,
),
new Text(data[dataKeys[keyIndex]][i][0])
],
)
);
}
return list;
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Expense Monitor"),
),
body: new Container (
child: new ListView.builder(
itemCount: dataKeys.length,
itemBuilder: (BuildContext context, int keyIndex) {
return new Card(
child: new ExpansionTile(
title: new Text(getFullDate(dataKeys[keyIndex])),
children: <Widget>[
new Column(
children: _buildList(keyIndex)
)
]
),
);
}
)
)
);
}
}
Error as shown in Console:
I/flutter (12945): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (12945): The following assertion was thrown during performResize():
I/flutter (12945): Vertical viewport was given unbounded height.
I/flutter (12945): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (12945): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (12945): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (12945): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (12945): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (12945): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (12945): the height of the viewport to the sum of the heights of its children.
I/flutter (12945): When the exception was thrown, this was the stack:
I/flutter (12945): #0 RenderViewport.performResize.<anonymous closure> (package:flutter/src/rendering/viewport.dart:944:15)
I/flutter (12945): #1 RenderViewport.performResize (package:flutter/src/rendering/viewport.dart:997:6)
I/flutter (12945): #2 RenderObject.layout (package:flutter/src/rendering/object.dart:1555:9)
I/flutter (12945): #3 _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:109:13)
......
I/flutter (12945): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (12945): Another exception was thrown: RenderBox was not laid out: RenderViewport#df29c NEEDS-LAYOUT NEEDS-PAINT
Try this:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: MyApp(), debugShowCheckedModeBanner: false,),);
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: vehicles.length,
itemBuilder: (context, i) {
return ExpansionTile(
title: Text(vehicles[i].title, style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic),),
children: <Widget>[
Column(
children: _buildExpandableContent(vehicles[i]),
),
],
);
},
),
);
}
_buildExpandableContent(Vehicle vehicle) {
List<Widget> columnContent = [];
for (String content in vehicle.contents)
columnContent.add(
ListTile(
title: Text(content, style: TextStyle(fontSize: 18.0),),
leading: Icon(vehicle.icon),
),
);
return columnContent;
}
}
class Vehicle {
final String title;
List<String> contents = [];
final IconData icon;
Vehicle(this.title, this.contents, this.icon);
}
List<Vehicle> vehicles = [
Vehicle(
'Bike',
['Vehicle no. 1', 'Vehicle no. 2', 'Vehicle no. 7', 'Vehicle no. 10'],
Icons.motorcycle,
),
Vehicle(
'Cars',
['Vehicle no. 3', 'Vehicle no. 4', 'Vehicle no. 6'],
Icons.directions_car,
),
];
Try this:
First Make an ExpandableContainer using AnimatedContainer.
Then Make an ExpandableListView which will create a Column . The first child of Column will be a button to expand and Second will be ExpandableContainer .
ExpandableContainer will have a ListView as its child.
The last step will be to make a ListView of ExpandableListView.
The Result :
The Code :
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new Home()));
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: new Text("Expandable List"),
backgroundColor: Colors.redAccent,
),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new ExpandableListView(title: "Title $index");
},
itemCount: 5,
),
);
}
}
class ExpandableListView extends StatefulWidget {
final String title;
const ExpandableListView({Key key, this.title}) : super(key: key);
#override
_ExpandableListViewState createState() => new _ExpandableListViewState();
}
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new Container(
color: Colors.blue,
padding: new EdgeInsets.symmetric(horizontal: 5.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new IconButton(
icon: new Container(
height: 50.0,
width: 50.0,
decoration: new BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
child: new Center(
child: new Icon(
expandFlag ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Colors.white,
size: 30.0,
),
),
),
onPressed: () {
setState(() {
expandFlag = !expandFlag;
});
}),
new Text(
widget.title,
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
)
],
),
),
new ExpandableContainer(
expanded: expandFlag,
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
decoration:
new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.grey), color: Colors.black),
child: new ListTile(
title: new Text(
"Cool $index",
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
),
leading: new Icon(
Icons.local_pizza,
color: Colors.white,
),
),
);
},
itemCount: 15,
))
],
),
);
}
}
class ExpandableContainer extends StatelessWidget {
final bool expanded;
final double collapsedHeight;
final double expandedHeight;
final Widget child;
ExpandableContainer({
#required this.child,
this.collapsedHeight = 0.0,
this.expandedHeight = 300.0,
this.expanded = true,
});
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return new AnimatedContainer(
duration: new Duration(milliseconds: 500),
curve: Curves.easeInOut,
width: screenWidth,
height: expanded ? expandedHeight : collapsedHeight,
child: new Container(
child: child,
decoration: new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.blue)),
),
);
}
}
Screenshot:
Code:
class MyPage extends StatelessWidget {
List<Widget> _getChildren(int count, String name) => List<Widget>.generate(
count,
(i) => ListTile(title: Text('$name$i')),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
ExpansionTile(
title: Text('List-A'),
children: _getChildren(4, 'A-'),
),
ExpansionTile(
title: Text('List-B'),
children: _getChildren(3, 'B-'),
),
],
),
);
}
}

Categories

Resources