Not show snackbar - android

android studio 3.6
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primaryColor: new Color(Constants.COLOR_PRIMARY),
primaryTextTheme: TextTheme(headline6: TextStyle(color: Colors.white))),
home: new SignInForm());
}
}
class SignInForm extends StatefulWidget {
#override
State<StatefulWidget> createState() {
logger.d("createState:");
return new _SignInFormState();
}
}
class _SignInFormState extends State {
final _formKey = GlobalKey<FormState>();
final _scaffoldKey = GlobalKey<ScaffoldState>();
String _textVersion = "";
String _email = null;
String _password = null;
#override
Widget build(BuildContext context) {
logger.d("build:");
//String _errorMessage = null;
return Scaffold(
appBar: new AppBar(
centerTitle: true,
title: new Text('Sign in',
style: TextStyle(fontWeight: FontWeight.bold))),
body: new Container(
margin: const EdgeInsets.only(
left: Constants.DEFAULT_MARGIN,
right: Constants.DEFAULT_MARGIN),
child: new Form(
key: _formKey,
child: new Column(children: [
new TextFormField(
decoration: new InputDecoration(hintText: 'Email'),
keyboardType: TextInputType.emailAddress,
onChanged: (value) {
setState(() {
_email = value;
});
}),
new TextFormField(
decoration: new InputDecoration(hintText: 'Password'),
obscureText: true),
new Container(
margin: const EdgeInsets.only(
top: Constants.DEFAULT_MARGIN / 2),
height: Constants.MIN_HEIGHT,
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Text("Forgot password?",
style: TextStyle(
color: new Color(Constants.COLOR_PRIMARY))),
new Align(
alignment: Alignment.centerRight,
child: new RaisedButton(
// Buttons are disabled by default
child: Text('Sign in'.toUpperCase()),
color: new Color(Constants.COLOR_PRIMARY),
textColor: new Color(
Constants.COLOR_PRIMARY_TEXT_COLOR),
onPressed: () {
if (_formKey.currentState.validate()) {
logger.d(
"onPressed: check_email = $_email");
if (_email == null ||
_email.trim().isEmpty) {
logger.d(
"onPressed: show_error_message");
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text("Аll fields must be filled"),
backgroundColor: Colors.red));
}
}
}))
])),
new Container(
margin: const EdgeInsets.all(Constants.DEFAULT_MARGIN),
child: new Text('Registration'.toUpperCase(),
style: new TextStyle(
color: new Color(Constants.COLOR_PRIMARY),
fontWeight: FontWeight.bold))),
new Container(
margin: const EdgeInsets.all(Constants.DEFAULT_MARGIN),
child: new Text(_textVersion))
]))));
}
press button and get error in
in this line:
Scaffold.of(context).showSnackBar(
logcat:
The context used was: SignInForm
state: _SignInFormState#fe66a
When the exception was thrown, this was the stack:
#0 Scaffold.of (package:flutter/src/material/scaffold.dart:1456:5)
#1 _SignInFormState.build.<anonymous closure> (package:flutter_sample/signinform.dart:86:52)
#2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:14)
#3 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
#4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#74eb7
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(268.7, 208.0)
finalLocalPosition: Offset(52.7, 18.0)
button: 1
sent tap down

The issue happens because the current passed context doesn't have any matching ancestor (in this case a matching ancestor scaffold).
Option 1:
The easiest way to fix this issue is, in your MyApp, replace:
home: new SignInForm()
with:
home: Scaffold(body: SignInForm())
Option 2:
You have to specify the key property of your scaffold:
Scaffold(key: _scaffoldKey, body: // Your remaining code);
And display the snackbar using:
_scaffoldKey.currentState.showSnackBar(
SnackBar(content: Text("Аll fields must be filled"),
backgroundColor: Colors.red)
);
Option 3:
You can use a Builder widget to fix the issue:
Scaffold(body: Builder(builder: (context) {
return Container(child:// Your widget);
// No other change needed
},);
I personally prefer option 3.
When the Scaffold is actually created in the same build function, the
context argument to the build function can't be used to find the
Scaffold (since it's "above" the widget being returned in the widget
tree).
Reference of method

Related

Flutter error: type 'String' is not a subtype of type 'Map<dynamic, dynamic>' in type cast

I am working on diary flutter android application with firebase real time database.
I am trying to make three functions: add, delete, edit.
For now, add and delete functions work well but edit part causes problems.
When I edit the texts and click 'save', it is updated to firebase itself but it shows "type 'String' is not a subtype of type 'Map<dynamic, dynamic>' in type cast" this error. Edit function can be done by clicking value from firebase animated list.
I put lots of effort to fix it and found what is problem with String but couldn't solve it.
Could anyone help me to solve this? Thank you a lot.
Below are models.
//1. Main
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
appBarTheme: AppBarTheme(color: Color(0xfff5f5f5),foregroundColor:Color(0xff0d47a1)),
splashColor: Color(0xff00bcd4),
scaffoldBackgroundColor: Color(0xffe9f1f2),
hoverColor: Color(0xff26c6da),
shadowColor: Colors.black,
fontFamily: 'Itim',
),
home: MainPage()));
}
//2. Main Page
class MainPage extends StatefulWidget {
MainPage({Key? key}) : super(key: key);
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
late PageController _myPage;
int selectedPage = 0;
void initState() {
super.initState();
_myPage = PageController(initialPage: 0);
selectedPage = 0;
}
List<IconData> iconlist = [
Icons.home_outlined,
Icons.add,
Icons.settings,
Icons.person,
];
List<Widget> _currentpage = [
ListOfNotes(),
AddNotes(),
SettingsPage(),
AccountPage(),
];
int _bottomnavindex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'NOTES',
style: TextStyle(fontFamily: 'Graduate', color: Color(0xff0d47a1)),
),
),
body: _currentpage[_bottomnavindex],
floatingActionButton: FloatingActionButton(
child: Icon(Icons.sunny),
onPressed: () {},
backgroundColor: Color(0xff039be5),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.miniEndDocked,
bottomNavigationBar: AnimatedBottomNavigationBar(
leftCornerRadius: 30,
//rightCornerRadius: 0,
gapLocation: GapLocation.end,
activeColor: Color(0xffe91e63),
inactiveColor: Color(0xff0d47a1),
icons: iconlist,
activeIndex: _bottomnavindex,
onTap: (index) => setState(() {
_bottomnavindex = index;
selectedPage = index;
}),
),
);
}
}
//3. AddNotes
class AddNotes extends StatefulWidget {
AddNotes({Key? key}) : super(key: key);
#override
State<AddNotes> createState() => _AddNotesState();
}
class _AddNotesState extends State<AddNotes> {
late PageController _myPage;
bool _validate=false;
TextEditingController _controller1 = TextEditingController();
TextEditingController _controller2 = TextEditingController();
final messageDao = MessageDao();
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: Container(
height: 500,
width: 300,
decoration: BoxDecoration(
color: Color(0xffe1e9f0),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: TextField(
enableInteractiveSelection: true,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.newline,
minLines:1,
decoration: InputDecoration(
errorText: (_validate)?'CANT BE NULL':null,
hintText: 'NOTE TITLE',
border: InputBorder.none,
hintStyle: TextStyle(
fontFamily: 'Graduate', color: Color(0xffc3dbf0)),),
controller: _controller1,
autocorrect: false,
style: TextStyle(
fontFamily: 'Itim', color: Color(0xff191176)),
),
),
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: TextField(
enableInteractiveSelection: true,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.newline,
minLines:1,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'NOTE CONTENT',
hintStyle: TextStyle(
fontFamily: 'Graduate', color: Color(0xffc3dbf0)),),
controller: _controller2,
style: TextStyle(
fontFamily: 'Itim', color: Color(0xff191176)),
),
),
],
),
),
),
floatingActionButton: FloatingActionButton.small(onPressed: () {
setState(() {
_controller1.text.isEmpty ? _validate = true : _validate = false;
if(!_validate){
add();
}
});
},
backgroundColor: Color(0xffeab9d6),
hoverColor: Colors.white,
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Text('OK', style: TextStyle(fontFamily: 'Graduate',color: Color(0xffcd087c)),),),
),
);
}
void add(){
final message = NotesOfApp(_controller1.text,_controller2.text, DateTime.now(), DateTime.now(),DateTime.now().microsecondsSinceEpoch);
messageDao.saveNotes(message);
_controller1.clear();
_controller2.clear();
}
}
//4. AddNotesToList
class MessageDao {
final DatabaseReference _notesRef = FirebaseDatabase.instance.ref();
void saveNotes(NotesOfApp notes) {
_notesRef.push().set(notes.toJson());
}
Query getNotesQuery() {
return _notesRef;
}
}
//5. Notes
class NotesOfApp {
final String NoteTitle;
final String NoteContent;
final DateTime created;
final DateTime editted;
final int date;
NotesOfApp(this.NoteTitle, this.NoteContent,this.created,this.editted,this.date);
NotesOfApp.fromJson(Map<dynamic, dynamic> json)
: created = DateTime.parse(json['created']),
editted = DateTime.parse(json['editted']),
NoteTitle = json['NoteTitle'] as String,
NoteContent = json['NoteContent'] as String,
date=json['date'] ;
Map<dynamic, dynamic> toJson() => <dynamic, dynamic>{
'created' : created.toIso8601String().split('T').first,
'editted' : editted.toIso8601String().split('T').first,
'NoteTitle': NoteTitle,
'NoteContent' :NoteContent,
'date':DateTime.now().microsecondsSinceEpoch,
};
}
//6. List of notes
class ListOfNotes extends StatelessWidget {
final reference = FirebaseDatabase.instance.ref().orderByChild('date');
List<String> keys=[];
List<Color> colors = [
Color(0xffefdada),
Color(0xffefe6e9),
Color(0xfff9f0fa),
Color(0xfff1eef5),
Color(0xfff8fae2),
Color(0xfffffcf2),
Color(0xfffff3ef)
];
ListOfNotes({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
height: double.infinity,
child: FirebaseAnimatedList(
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
Map notes = snapshot.value as Map;
for(DataSnapshot i in snapshot.children ) {
keys.add(i.key.toString());
break;
}
return _buildList(context, notes: (notes));
},
query: reference,
),
)));
}
Widget _buildList(BuildContext context, {required Map notes}) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Container(
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
color: colors[Random().nextInt(colors.length)],
),
child: Column(
//mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
title: Text(notes['NoteTitle'],
style: TextStyle(
fontFamily: 'Graduate',
fontSize: 10,
color: Color(0xff191176),
fontWeight: FontWeight.bold)),
subtitle: Text(notes['editted'],
style: TextStyle(
color: Color(0xff191176),
fontFamily: 'Graduate',
fontSize: 10,
fontWeight: FontWeight.bold)),
tileColor: colors[Random().nextInt(colors.length)],
onLongPress: () {
showAnimatedDialog(
animationType: DialogTransitionType.slideFromTop,
curve: Curves.easeInOutCubicEmphasized,
duration: Duration(seconds: 1),
context: (context),
builder: (builder) => Warning(
NoteTitle: notes['NoteTitle'],
));
},
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NoteContents(
NoteTitle: notes['NoteTitle'],
NoteContent: notes['NoteContent'],
list:keys,
)));
},
),
SizedBox(
height: 8,
),
]),
));
}
}
//7. Note Content
class NoteContents extends StatelessWidget {
final String NoteContent;
final String NoteTitle;
final List<String> list;
NoteContents({Key? key, required this.NoteContent, required this.NoteTitle, required this.list}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: Container(
height: 500,
width: 300,
decoration: BoxDecoration(
color: Color(0xffe1e9f0),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
),
child:Column(
children: [
ListTile(
onTap:(){Navigator.of(context).push(MaterialPageRoute(builder: (context)=>UpdateNotes(NoteTitle: NoteTitle, NoteContent:NoteContent,list: list,)));},
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 18),
child: Column(
children:[
Text('$NoteTitle',style:TextStyle(color: Color(0xff191176),fontFamily: 'Graduate',fontWeight: FontWeight.w500)),
SizedBox(height: 10),
Text('$NoteContent',style:TextStyle(color: Color(0xff191176),fontSize:12),),
]),
),
onLongPress: (){Navigator.of(context).push(MaterialPageRoute(builder: (context)=>UpdateNotes(NoteTitle: NoteTitle, NoteContent:NoteContent,list: list,)));},
)
],
),)),
floatingActionButton: FloatingActionButton.small(
onPressed: () {
// print(NoteTitle);
// print(NoteContent);
Navigator.of(context).pop();
},
backgroundColor: Color(0xffeab9d6),
hoverColor: Colors.white,
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10))),
child: Text('BACK',
style: TextStyle(
fontFamily: 'Graduate',
color: Color(0xffcd087c),
fontSize: 8)),
),
),
);
}
}
//8. Update
class UpdateNotes extends StatelessWidget {
final String NoteTitle, NoteContent;
final List<String> list;
UpdateNotes({Key? key, required this.NoteTitle, required this.NoteContent,required this.list})
: super(key: key);
final controller1 = TextEditingController(),
controller2 = TextEditingController();
#override
Widget build(BuildContext context) {
controller1.text = '$NoteTitle';
controller2.text = '$NoteContent';
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xffe9f1f2),
shadowColor: Color(0xffe9f1f2),
),
body: Center(
child: Container(
height: 500,
width: 300,
decoration: BoxDecoration(
color: Color(0xffe1e9f0),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
),
style: TextStyle(color: Color(0xff191176)),
controller: controller1,
),
),
SizedBox(
height: 12,
),
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
minLines: 1,
maxLines: 500,
decoration: InputDecoration(
border: InputBorder.none,
),
style: TextStyle(color: Color(0xff191176)),
controller: controller2,
),
),
],
),
),
),
floatingActionButton: FloatingActionButton.small(
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
backgroundColor: Color(0xffeab9d6),
hoverColor: Colors.white,
onPressed: () {
showAnimatedDialog(
animationType: DialogTransitionType.fade,
curve: Curves.easeInOutCubicEmphasized,
duration: Duration(seconds: 1),
context: (context),
builder: (builder) => Warning2(
NoteTitle: controller1.text,
NoteContent: controller2.text,
list: list,
));
},
child: Text('SAVE',
style: TextStyle(
fontFamily: 'Graduate',
color: Color(0xffcd087c),
fontSize: 8)),),
),
);
}
}
//9. Update pop up
class Warning2 extends StatelessWidget {
final List<String> list;
Warning2({Key? key, required this.NoteTitle, required this.NoteContent, required this.list}) : super(key: key);
final String NoteTitle,NoteContent;
#override
Widget build(BuildContext context) {
return ClassicGeneralDialogWidget(
titleText: 'SURE WANT TO UPDATE ?',
onPositiveClick:(){
Update('$NoteTitle','$NoteContent',list);
Navigator.of(context).pop();
} ,
onNegativeClick: (){
Navigator.of(context).pop();
}
);
}
}
Future<void> Update(String NoteTitle,String NoteContent,List<String> list) async {
String key="";
String result="";
DatabaseReference ref = FirebaseDatabase.instance.ref();
final snapshot = await FirebaseDatabase.instance.ref().get();
for(DataSnapshot i in snapshot.children ){
key = i.key.toString();
for(int i=0;i<list.length;i++){
if(key==list[i]){
result=list[i];
}
}
}
await ref.child(result).update({
"NoteTitle":"$NoteTitle",
"NoteContent":"$NoteContent",
"editted":DateTime.now().toIso8601String().split('T').first,
});
}
//10. delete pop up
void check(String NoteTitle) async{
print(NoteTitle);
final reference = FirebaseDatabase.instance.ref();
String key="";
final snapshot = await FirebaseDatabase.instance.ref().get();
for(DataSnapshot i in snapshot.children ){
if(i.child('NoteTitle').value.toString()==NoteTitle) {
key = i.key.toString();
break;
}
}
reference.child(key).remove();
}
class Warning extends StatelessWidget {
Warning({Key? key, this.NoteTitle}) : super(key: key);
final String? NoteTitle;
#override
Widget build(BuildContext context) {
return ClassicGeneralDialogWidget(
titleText: 'SURE WANT TO DELETE ?',
onPositiveClick:(){
check('$NoteTitle');
Navigator.of(context).pop();
} ,
onNegativeClick: (){
Navigator.of(context).pop();
}
);
}
}
These are codes and in' Notes' model, there is "Map<dynamic, dynamic>".
These dependencies are from pubspec.yaml.
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
animated_bottom_navigation_bar: ^1.0.1
firebase_database: ^9.0.20
firebase_core: ^1.20.0
flutter_animated_dialog: ^2.0.1
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
uses-material-design: true
fonts:
- family: Graduate
fonts:
- asset: fonts/Graduate-Regular.ttf
- family: Itim
fonts:
- asset: fonts/Itim-Regular.ttf
And this is how error shows on application. Other things on page are showed well and other pages work well too. But only this content part is missing.
And this is the full error code.
======== Exception caught by widgets library =======================================================
The following _CastError was thrown building:
type 'String' is not a subtype of type 'Map<dynamic, dynamic>' in type cast
When the exception was thrown, this was the stack:
#0 ListOfNotes.build.<anonymous closure> (package:diaryreal/ListOfNotes.dart:32:46)
#1 FirebaseAnimatedListState._buildItem (package:firebase_database/ui/firebase_animated_list.dart:209:30)
#2 SliverAnimatedListState._itemBuilder (package:flutter/src/widgets/animated_list.dart:624:30)
#3 SliverChildBuilderDelegate.build (package:flutter/src/widgets/sliver.dart:471:22)
#4 SliverMultiBoxAdaptorElement._build (package:flutter/src/widgets/sliver.dart:1236:28)
#5 SliverMultiBoxAdaptorElement.performRebuild.processElement (package:flutter/src/widgets/sliver.dart:1169:67)
#6 Iterable.forEach (dart:core/iterable.dart:325:35)
#7 SliverMultiBoxAdaptorElement.performRebuild (package:flutter/src/widgets/sliver.dart:1213:24)
#8 SliverMultiBoxAdaptorElement.update (package:flutter/src/widgets/sliver.dart:1146:7)
#9 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)
#10 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4832:16)
#11 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4977:11)
#12 Element.rebuild (package:flutter/src/widgets/framework.dart:4529:5)
#13 StatefulElement.update (package:flutter/src/widgets/framework.dart:5009:5)
#14 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)
#15 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6222:14)
#16 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)
#17 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5825:32)
#18 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6375:17)
#19 _ViewportElement.update (package:flutter/src/widgets/viewport.dart:237:11)
#20 Element.updateChild (package:flutter/src/widgets/framework.dart:3530:15)
And this is what I got 'debug' tab.

Navigate to a new screen without leaving parent screen

I am completely new to Flutter and I have this screen that uses bottomSheet and I want to go to a new screen when I click on a project, while staying inside this parent screen that has the bottomSheet in it. Here is the source code for the parent screen and the Projects screen inside it.
Parent Main Menu screen
import 'package:flutter/material.dart';
import 'projects.dart';
import 'app-bar.dart';
class MainMenu extends StatefulWidget {
#override
_MainMenuState createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedIndex = 0;
static List<TabItem> _widgetOptions = <TabItem>[
TabItem(
text: new Text('Projects'),
className: Projects(),
),
TabItem(
text: new Text('Organization'),
className: null,
),
TabItem(
text: new Text('Profile'),
className: null,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: SafeArea(
child: new DefaultTabController(
length: 3,
child: new Scaffold(
key: _scaffoldKey,
appBar: appBar(_widgetOptions.elementAt(_selectedIndex).text),
body: _widgetOptions.elementAt(_selectedIndex).className,
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.view_column),
label: 'Projects'
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
label: 'Organization'
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile'
)
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
),
)
),
);
}
}
class TabItem {
Widget text;
dynamic className;
TabItem({ #required this.text, #required this.className });
}
Projects
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pmtool/project-page.dart';
import './interfaces/iprojects.dart';
import './constants/route-names.dart';
class Projects extends StatefulWidget {
#override
_ProjectsState createState() => _ProjectsState();
}
class _ProjectsState extends State<Projects> {
final GlobalKey<ScaffoldState> _scaffoldState = new GlobalKey<ScaffoldState>();
static const List<Text> sortOptions = [
Text('Project Name'),
Text('Project Number'),
Text('Client Name'),
Text('Percent Completed'),
Text('Date Added'),
Text('Project Type'),
];
static const List<String> sortOrder = [
'Descending',
'Ascending',
];
static const List<String> filters = [
'Ongoing',
'All',
'Completed',
];
List<bool> isSelected = [
true, false, false, false, false, false,
];
String selectedSort = 'Descending';
static List<ProjectsMock> projects = [
ProjectsMock(projectId: '1', projectNumber: '1', projectName: 'Project 1', clientName: 'asd', projectStatus: 'Ongoing'),
ProjectsMock(projectId: '2', projectNumber: '2', projectName: 'Project 2', clientName: 'qwe', projectStatus: 'Completed'),
];
String selectedFilter = 'Ongoing';
void selectItem(int index) {
setState(() {
for (int i = 0; i < isSelected.length; i++) {
if (i != index) {
isSelected[i] = false;
return;
}
isSelected[i] = true;
}
});
}
void navigateToProject(BuildContext context, ProjectsMock project) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProjectPage(),
settings: RouteSettings(
arguments: project,
)
)
);
}
void setBottomSheet(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext buildContext) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text('Filters', style: TextStyle(fontWeight: FontWeight.bold),),
new Wrap(
spacing: 5.0,
children: List.generate(filters.length, (index) {
if (selectedFilter == filters.elementAt(index)) {
return new ActionChip(
label: new Text(filters.elementAt(index)),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
onPressed: () {
return;
},
);
}
return new ActionChip(
label: new Text(filters.elementAt(index)),
backgroundColor: Colors.white,
labelStyle: TextStyle(color: Colors.blue),
onPressed: () {
return;
},
);
}),
),
new Text('Sort by', style: TextStyle(fontWeight: FontWeight.bold),),
new Wrap(
spacing: 5.0,
children: List.generate(sortOptions.length, (index) {
if (isSelected[index]) {
return new ActionChip(
label: sortOptions.elementAt(index),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
onPressed: () {
return;
},
);
}
return new ActionChip(
label: sortOptions.elementAt(index),
backgroundColor: Colors.white,
labelStyle: TextStyle(color: Colors.blue),
onPressed: () {
return;
},
);
}),
),
new Container(
margin: const EdgeInsets.only(top: 10.0),
child: new Text('Sort Order', style: TextStyle(fontWeight: FontWeight.bold),),
),
new Wrap(
spacing: 5.0,
children: List.generate(sortOrder.length, (index) {
if (selectedSort == sortOrder[index]) {
return new ActionChip(
label: Text(sortOrder.elementAt(index)),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
onPressed: () {
return;
},
);
}
return new ActionChip(
label: Text(sortOrder.elementAt(index)),
backgroundColor: Colors.white,
labelStyle: TextStyle(color: Colors.blue),
onPressed: () {
return;
},
);
}),
),
],
),
);
}
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
floatingActionButton: new FloatingActionButton(child: new Icon(Icons.filter_alt), onPressed: () => setBottomSheet(context), mini: true),
key: _scaffoldState,
body: new Column(
children: <Widget>[
new Expanded(
child: new Column(
children: <Widget>[
// Search header
new Container(
padding: const EdgeInsets.all(10.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new TextField(
decoration: new InputDecoration(
hintText: 'Search',
labelText: 'Search',
suffixIcon: new IconButton(icon: Icon(Icons.search), onPressed: () {
return;
}),
contentPadding: const EdgeInsets.only(left: 5.0, right: 5.0)
),
)
),
],
),
],
),
),
new Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: new Column(
children: List.generate(projects.length, (index) {
return new Container(
margin: const EdgeInsets.only(bottom: 10.0),
child: new RaisedButton(
onPressed: () => navigateToProject(context, projects.elementAt(index)),
color: Colors.white,
textColor: Colors.black,
child: new Padding(
padding: const EdgeInsets.all(10.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Expanded(
child: new Column(
children: <Widget>[
new Text(projects.elementAt(index)?.projectName, style: TextStyle(fontWeight: FontWeight.bold)),
new Text(projects.elementAt(index)?.projectNumber),
]
),
),
new Expanded(
child: new Column(
children: <Widget>[
new Text(projects.elementAt(index)?.clientName, style: TextStyle(fontWeight: FontWeight.bold)),
new Text(projects.elementAt(index)?.projectStatus),
]
),
)
],
),
),
),
);
}),
),
)
],
),
)
],
),
);
}
}
Here is a snapshot of the page.
How do I do it? I tried using Navigator but it goes to a completely new screen. Let me know if you need more information.
You create another inside your main.dart file and use Navigator to move to that screen without actually moving to another screen instead replacing the current one
this is how the code goes
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(string1: string),//passing a parameter
),
);
and this how the class goes
class DisplayPictureScreen extends StatelessWidget {
final String string1;
const DisplayPictureScreen({Key key, this.string1}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(value[0]["label"],style: TextStyle(color: Colors.black,fontSize: 20),
)),
body: Column(
children: [
Text("lsfnklsnlvfdngvlirs")
],
),
);
}
}

Sign in Method getting called on a null (Firebase) Flutter

sometimes, when I attempt to the the sign in process with firebase I get these errors:
W/DynamiteModule( 8142): Local module descriptor class fo com.google.firebase.auth not found.
I/FirebaseAuth( 8142): [FirebaseAuth:] Preparing to create service connection to gms implementation
D/FirebaseAuth( 8142): Notifying id token listeners about user ( skEEmC0dDBW9z73MsfShWX8M1iu1 ).
I/flutter ( 8142): Error:NoSuchMethodError: The method 'call' was called on null.
I/flutter ( 8142): Receiver: null
I/flutter ( 8142): Tried calling: call()
Especially if I click on the register button the go back to the log in. Can someone explain why do I get this error and how can I fix it:
Here is the code:
class LoginPage extends StatefulWidget{
static const routeName = '/login';
LoginPage({this.onSignedIn});
final VoidCallback onSignedIn;
#override
State<StatefulWidget> createState() => new _LoginPageState();
}
enum FormType {
login,
}
class _LoginPageState extends State <LoginPage> {
final formKey = new GlobalKey<FormState>();
String _email,_password;
bool validateAndSave(){
final form = formKey.currentState;
if(form.validate()){
form.save();
return true;
}
return false;
}
void validateAndSubmit() async{
if(validateAndSave()){
try{
await FirebaseAuth.instance.signInWithEmailAndPassword(email: _email, password: _password);
widget.onSignedIn();
}catch (e){
print('Error:$e');
}
}
}
void moveToRegister() {
Navigator.of(context).pushReplacementNamed(RegisterPage.routeName);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title:new Text ('',
style: new TextStyle(color:Colors.white, fontWeight:FontWeight.bold)
),
backgroundColor: Color(0xff04346c),
),
body: Stack (
children:<Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xff04a3b3),
Color(0xff04a3b3),
Color(0xff04a3b3),
Color(0xff04a3b3),
]
)
),
),
Center(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)
),
child: Container(
height:350,
width:350,
padding: EdgeInsets.all(16.0),
child: Form(
key:formKey,
child: new Column(
children:
buildInputs() + buildSubmitButtons(),
)
)
)
)
)
],
),
);
}
List<Widget> buildInputs(){
return [
Image.asset('imageapp/myimage.png',height:50,width: 250,),
new TextFormField(
decoration: new InputDecoration(labelText: 'Email',
icon: new Icon (Icons.email)
),
onSaved: (value) => _email = value,
),
new TextFormField(
decoration: new InputDecoration (labelText: 'Password',
icon: new Icon (Icons.lock)
),
obscureText: true,
onSaved: (value) => _password = value,
),
];
}
List<Widget> buildSubmitButtons(){
return [
Padding(padding: EdgeInsets.all(3.0)),
new RaisedButton(
child: new Text('Login',style: new TextStyle(fontSize:18.0,color: Colors.white),
),
color: Color(0xff04346c),
shape: RoundedRectangleBorder(
borderRadius : new BorderRadius.circular(30.0)
),
onPressed: validateAndSubmit
),
new FlatButton(
onPressed: moveToRegister,
child: new Text('Create an account',style: new TextStyle(fontSize:13.0),)
)
];
}
}
The problem was on this
widget.onSignedIn();
I changed it to Navigate.... (To the dashboard page)

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 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