Flutter Navigator.pop(context) won't work - flutter

I have seen many questions about Navigator.pop(context) but I didn't find my answer.
As you can see there are three screens so far. The Navigator.pop(context) works fine in the StoryDetailScreen and turns me back to the MainPage. The problem here with EditStoryScreen page, when I get into it I cant go back to the MainPage, when I click on the IconButton I see a black screen.
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return
MultiProvider(
providers: [
ChangeNotifierProvider<Stories>(
create: (_) =>
Stories(),
),
ChangeNotifierProvider<Story>(
create:(ctx) => Story(),
),
],
child: MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: Mainpage(),
routes: {
StoryDetailScreen.routeName: (ctx) => StoryDetailScreen(),
UserStory.routeName: (ctx) => UserStory(),
EditStoryScreen.routeName: (ctx) => EditStoryScreen(),
}),
);
}
}
Mainpage.dart
class Mainpage extends StatefulWidget {
static const routeName = 'main';
#override
_MainpageState createState() => _MainpageState();
}
class _MainpageState extends State<Mainpage> {
var _showOnlyFav = false;
#override
Widget build(BuildContext context) {
final storyCon = Provider.of<Stories>(context);
return Scaffold(
body: SingleChildScrollView(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/back.jpg"), fit: BoxFit.fill)),
child: Column(children: <Widget>[
SizedBox(
height: 50,
),
Container(
child: Text("Short Stories",
style: TextStyle(
fontSize: 40, backgroundColor: Colors.grey[300])),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Row(
children: [
Container(
height: 40,
width: 290,
decoration: BoxDecoration(
color: Colors.grey[300],
border: Border.all(width: 1, color: Colors.black),
borderRadius: BorderRadius.circular(7)
// image: DecorationImage(
// image: AssetImage("images/text.png"))
),
child: Center(
child: Row(
children: [
InkWell(
onTap: () {
Navigator.of(context).pushReplacementNamed(UserStory.routeName);
},
child: Text(
"Edit Stroy",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 30,
// backgroundColor: Colors.grey[300]),
),
),
),
InkWell(
onTap: () {
Navigator.of(context).pushReplacementNamed(EditStoryScreen.routeName);
},
child:Text(
"Add Stroy",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 30,
// backgroundColor: Colors.grey[300]),
),
),)
],
),
),
),
],
))),
StorysGrid(_showOnlyFav),
]),
),
),
);
}
}
EditStoryScreen.dart
class EditStoryScreen extends StatefulWidget {
static const routeName = 'edit';
#override
_EditStoryScreenState createState() => _EditStoryScreenState();
}
class _EditStoryScreenState extends State<EditStoryScreen> {
final _storyFocusNode = FocusNode();
final _imgController = TextEditingController();
final _imgFocusNode = FocusNode();
#override
void initState() {
_imgFocusNode.addListener(updateImg);
super.initState();
}
#override
void dispose() {
_imgFocusNode.removeListener(updateImg);
_storyFocusNode.dispose();
_imgController.dispose();
_imgFocusNode.dispose();
super.dispose();
}
void updateImg() {
if (!_imgFocusNode.hasFocus) {
setState(() {});
}
}
// void backToHome(context) {
// Navigator.pushReplacementNamed(BuildContext(), context);
// }
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Container(
height: 650,
color: Colors.white,
child: Column(
children: [
SizedBox(
height: 30,
),
Align(
alignment: Alignment.topLeft,
child: RaisedButton(
child: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context)
)),
Padding(
padding: const EdgeInsets.fromLTRB(15, 10, 15, 15),
child: Form(
child: ListView(
shrinkWrap: true,
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: "Title"),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_storyFocusNode);
},
),
TextFormField(
decoration: InputDecoration(labelText: "Story's text"),
maxLines: 14,
keyboardType: TextInputType.multiline,
focusNode: _storyFocusNode,
),
Row(
children: [
Container(
width: 100,
height: 100,
margin: EdgeInsets.only(top: 8, right: 10),
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
),
child: _imgController.text.isEmpty
? Text("Enter a Url")
: Center(
child: FittedBox(
child: Image.network(
_imgController.text,
),
),
),
),
Container(
width: 200,
child: TextFormField(
decoration: InputDecoration(
labelText: "Image URL",
),
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
controller: _imgController,
focusNode: _imgFocusNode,
),
)
],
),
],
),
),
),
],
),
),
),
);
}
}
StoryDetailScreen.dart
class StoryDetailScreen extends StatelessWidget {
// final String title;
// final double price;
// ProductDetailScreen(this.title, this.price);
static const routeName = '/story-detail';
#override
Widget build(BuildContext context) {
final storyId =
ModalRoute.of(context).settings.arguments as String; // is the id!
final loadedStory = Provider.of<Stories>(
context,
listen: false,
).findById(storyId);
return Scaffold(
body: SingleChildScrollView(
child: Container(
width: double.infinity,
// height: 700,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/back1.jpg"), fit: BoxFit.fill)),
// color: Color(0xfffae3d9),
// child: Column(children: <Widget>[
// SizedBox(
// height: 10,
// ),
// Container(
// width: 340,
child:
Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
SizedBox(
height: 50,
),
Align(
alignment: Alignment.topLeft,
child: RaisedButton(
child: Icon(Icons.arrow_back_ios),
onPressed: (){
Navigator.pop(context);
})
),
Card(
elevation: 10,
margin: EdgeInsets.all(10),
child: Text("${loadedStory.title}",
softWrap: false,
textDirection: TextDirection.ltr,
style: TextStyle(
color: Color(0xFF6a2c70),
decorationColor: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold,
)),
),
SizedBox(height: 30),
Container(
width: double.infinity,
color: Colors.white70,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 5),
child: Text(
loadedStory.story,
textDirection: TextDirection.rtl,
style: TextStyle(
color: Color(0xFF6a2c70),
decorationColor: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold,
// fontFamily: "Kufam"),
),
),
),
),
SizedBox(
height: 20,
),
Card(
child: Container(
height: 60,
width: 210,
decoration: BoxDecoration(color: Colors.white60),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Like(),
]),
),
),
),
// ],
// )
SizedBox(
height: 30,
)
]),
)
// ]
,
),
// ),
// ),
);
}
}

You're invoking
Navigator.of(context).pushReplacementNamed(UserStory.routeName)
so this is removing your Mainpage from the navigation stack and replacing it with UserStory, which is why when you call Navigator.pop(context), there's nothing to go back to and all you get is a black screen.
Change it to Navigator.of(context).pushNamed(UserStory.routeName).

You have to define the Mainpage route as well in the routes.

Related

The method 'userLogin' isn't defined for the type 'BottomSheet'

I have this error in the onPressed :() function of the login: The method 'userLogin' is not defined for the type 'BottomSheet'.
Could anyone help me solve? Thank you.
CustomButton(
label: "LOGIN",
primaryColor: Theme.of(context).primaryColor,
secondaryColor: Colors.white,
onPressed: () => {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate()) {
userLogin()}
},
),
Here is the complete code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:login_ui/home2.dart';
import 'clipper.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
TextEditingController _emailController,
_passwordController,
_nameController = TextEditingController();
//
bool _visible = false;
Future userLogin() async {
//Login API URL
//use your local IP address instead of localhost or use Web API
String url = "https://www.toptradeitaly.com/login_api/user_login.php";
// Showing LinearProgressIndicator.
setState(() {
_visible = true;
});
// Getting username and password from Controller
var data = {
'username': _emailController.text,
'password': _passwordController.text,
};
//Starting Web API Call.
var response = await http.post(url, body: json.encode(data));
if (response.statusCode == 200) {
//Server response into variable
print(response.body);
var msg = jsonDecode(response.body);
//Check Login Status
if (msg['loginStatus'] == true) {
setState(() {
//hide progress indicator
_visible = false;
});
// Navigate to Home Screen
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomePage(uname: msg['userInfo']['NAME'])));
} else {
setState(() {
//hide progress indicator
_visible = false;
//Show Error Message Dialog
showMessage(msg["message"]);
});
}
} else {
setState(() {
//hide progress indicator
_visible = false;
//Show Error Message Dialog
showMessage("Error during connecting to Server.");
});
}
}
Future<dynamic> showMessage(String _msg) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(_msg),
actions: <Widget>[
TextButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
//
#override
Widget build(BuildContext context) {
//GO logo widget
Widget logo() {
return Padding(
padding:
EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.15),
child: Container(
width: MediaQuery.of(context).size.width,
height: 220,
child: Stack(
children: <Widget>[
Positioned(
child: Container(
child: Align(
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
width: 150,
height: 150,
),
),
height: 154,
)),
Positioned(
child: Container(
height: 154,
child: Align(
child: Text(
"GO",
style: TextStyle(
fontSize: 120,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
),
),
)),
),
Positioned(
width: MediaQuery.of(context).size.width * 0.15,
height: MediaQuery.of(context).size.width * 0.15,
bottom: MediaQuery.of(context).size.height * 0.046,
right: MediaQuery.of(context).size.width * 0.22,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
Positioned(
width: MediaQuery.of(context).size.width * 0.08,
height: MediaQuery.of(context).size.width * 0.08,
bottom: 0,
right: MediaQuery.of(context).size.width * 0.32,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
],
),
),
);
}
void _loginSheet(context) {
showBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return BottomSheet(
emailController: _emailController,
passwordController: _passwordController,
);
},
);
}
void _registerSheet(context) {
showBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return BottomSheet(
emailController: _emailController,
passwordController: _passwordController,
nameController: _nameController,
);
},
);
}
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Theme.of(context).primaryColor,
body: Builder(builder: (context) {
return Column(
children: <Widget>[
logo(),
Padding(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
CustomButton(
label: "LOGIN",
primaryColor: Colors.white,
secondaryColor: Theme.of(context).primaryColor,
onPressed: () => _loginSheet(context),
),
SizedBox(height: 20),
CustomButton(
label: "REGISTER",
primaryColor: Theme.of(context).primaryColor,
secondaryColor: Colors.white,
onPressed: () => _registerSheet(context),
),
],
),
padding: EdgeInsets.only(top: 80, left: 20, right: 20),
),
Expanded(
child: Align(
child: ClipPath(
child: Container(
color: Colors.white,
height: 300,
),
clipper: BottomWaveClipper(),
),
alignment: Alignment.bottomCenter,
),
)
],
crossAxisAlignment: CrossAxisAlignment.stretch,
);
}),
);
}
}
class CustomButton extends StatelessWidget {
final Color primaryColor;
final Color secondaryColor;
final String label;
final Function() onPressed;
const CustomButton({
Key key,
this.primaryColor,
this.secondaryColor,
#required this.label,
this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
height: 50,
width: double.infinity,
child: RaisedButton(
highlightElevation: 0.0,
splashColor: secondaryColor,
highlightColor: primaryColor,
elevation: 0.0,
color: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
side: BorderSide(color: Colors.white, width: 3)),
child: Text(
label,
style: TextStyle(
fontWeight: FontWeight.bold, color: secondaryColor, fontSize: 20),
),
onPressed: onPressed,
),
);
}
}
class CustomTextField extends StatelessWidget {
final Icon icon;
final String hint;
final TextEditingController controller;
final bool obsecure;
const CustomTextField({
this.controller,
this.hint,
this.icon,
this.obsecure,
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return TextField(
controller: controller,
obscureText: obsecure ?? false,
style: TextStyle(
fontSize: 20,
),
decoration: InputDecoration(
hintStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
hintText: hint,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 3,
),
),
prefixIcon: Padding(
child: IconTheme(
data: IconThemeData(color: Theme.of(context).primaryColor),
child: icon,
),
padding: EdgeInsets.only(left: 30, right: 10),
)),
);
}
}
//
final _formKey = GlobalKey<FormState>();
//
class BottomSheet extends StatelessWidget {
const BottomSheet({
Key key,
#required TextEditingController emailController,
#required TextEditingController passwordController,
TextEditingController nameController,
}) : _emailController = emailController,
_passwordController = passwordController,
_nameController = nameController,
super(key: key);
final TextEditingController _emailController;
final TextEditingController _passwordController;
final TextEditingController _nameController;
List<Widget> get _registerLogo => [
Positioned(
child: Container(
padding: EdgeInsets.only(bottom: 25, right: 40),
child: Text(
"REGI",
style: TextStyle(
fontSize: 38,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
alignment: Alignment.center,
),
),
Positioned(
child: Align(
child: Container(
padding: EdgeInsets.only(top: 40, left: 28),
width: 130,
child: Text(
"STER",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 38),
),
),
alignment: Alignment.center,
),
),
];
List<Widget> get _loginLogo => [
Align(
alignment: Alignment.center,
child: Container(
child: Text(
"LOGIN",
style: TextStyle(
fontSize: 42,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
alignment: Alignment.center,
),
),
];
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(color: Theme.of(context).canvasColor),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(40.0), topRight: Radius.circular(40.0)),
child: Container(
child: ListView(
children: <Widget>[
Container(
child: Stack(
children: <Widget>[
Positioned(
left: 10,
top: 10,
child: IconButton(
onPressed: () {
Navigator.of(context).pop();
_emailController.clear();
_passwordController.clear();
_nameController?.clear();
},
icon: Icon(
Icons.close,
size: 30.0,
color: Theme.of(context).primaryColor,
),
),
)
],
),
height: 50,
width: 50,
),
//
Form(
key: _formKey,
child:
//
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: 140,
child: Stack(
children: <Widget>[
Align(
child: Container(
width: 130,
height: 130,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).primaryColor),
),
alignment: Alignment.center,
),
..._nameController != null
? _registerLogo
: _loginLogo
],
),
),
SizedBox(height: 60),
if (_nameController != null)
CustomTextField(
controller: _nameController,
hint: "NAME",
icon: Icon(Icons.person),
),
SizedBox(height: 20),
CustomTextField(
controller: _emailController,
hint: "EMAIL",
icon: Icon(Icons.email),
),
SizedBox(height: 20),
CustomTextField(
controller: _passwordController,
hint: "PASSWORD",
icon: Icon(Icons.lock),
obsecure: true,
),
SizedBox(height: 20),
if (_nameController != null)
CustomButton(
label: "REGISTER",
primaryColor: Theme.of(context).primaryColor,
secondaryColor: Colors.white,
onPressed: () {},
),
SizedBox(height: 20),
if (_nameController == null)
CustomButton(
label: "LOGIN",
primaryColor: Theme.of(context).primaryColor,
secondaryColor: Colors.white,
onPressed: () => {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate()) {
userLogin()}
},
),
SizedBox(height: 20),
],
),
),
),),
],
),
height: MediaQuery.of(context).size.height / 1.1,
width: MediaQuery.of(context).size.width,
color: Colors.white,
),
),
);
}
}

Error: A FocusNode was used after being disposed. Once you have called dispose() on a FocusNode, it can no longer be used

I have created a simple web page where I have two buttons, one to add a donor and the other to list the donors. When each of the button is clicked, I want the respective pages to open.
I click on the 'Add Donor' button, fill the form and click on 'Submit'. Then I click on 'List Donors' and return back to 'Add Donor', and on clicking on the 'Name' field', I get the below error when running this on Chrome Browser.
Error: A FocusNode was used after being disposed.
Once you have called dispose() on a FocusNode, it can no longer be used.
at Object.throw_ [as throw] (http://localhost:62365/dart_sdk.js:5334:11)
at http://localhost:62365/packages/flutter/src/foundation/change_notifier.dart.lib.js:83:21
at focus_manager.FocusNode.new.[_debugAssertNotDisposed] (http://localhost:62365/packages/flutter/src/foundation/change_notifier.dart.lib.js:86:25)
at focus_manager.FocusNode.new.notifyListeners (http://localhost:62365/packages/flutter/src/foundation/change_notifier.dart.lib.js:113:51)
at focus_manager.FocusNode.new.[_notify] (http://localhost:62365/packages/flutter/src/widgets/widget_span.dart.lib.js:47534:12)
at focus_manager.FocusManager.new.[_applyFocusChange] (http://localhost:62365/packages/flutter/src/widgets/widget_span.dart.lib.js:48310:26)
at Object._microtaskLoop (http://localhost:62365/dart_sdk.js:39176:13)
at _startMicrotaskLoop (http://localhost:62365/dart_sdk.js:39182:13)
at http://localhost:62365/dart_sdk.js:34689:9
This is my code snippet
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
BloodDonationPage(),
),
);
},
child: Scaffold(
body: Center(
child: Container(
width: 200,
height: 100,
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Center(
child: Text(
"Blood Donation",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
)),
),
),
),
),
);
}
}
class BloodDonationPage extends StatefulWidget {
#override
_BloodDonationPageState createState() => _BloodDonationPageState();
}
class _BloodDonationPageState extends State<BloodDonationPage> {
bool _addButton = false;
bool _listButton = false;
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 60,
//width: 600,
child: Card(
color: Colors.pink[50],
shadowColor: Colors.pink,
elevation: 20,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
GestureDetector(
onTap: () {
setState(() {
_addButton = true;
_listButton = false;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"Add Donor",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
_addButton = false;
_listButton = true;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"List Donors",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
)),
),
),
),
),
],
),
),
),
_addButton ? Flexible(child: BloodDonorDetailPage()) : SizedBox.shrink(),
_listButton ? Flexible(child: ListBloodDonorPage()) : SizedBox.shrink(),
],
);
}
}
class BloodDonorDetailPage extends StatefulWidget {
#override
_BloodDonorDetailPageState createState() => _BloodDonorDetailPageState();
}
class _BloodDonorDetailPageState extends State<BloodDonorDetailPage> {
final _formKey = GlobalKey<FormBuilderState>();
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(30.0),
child: FormBuilder(
autovalidateMode: AutovalidateMode.disabled,
key: _formKey,
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FormBuilderTextField(
autofocus: true,
name: 'name',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.maxLength(context, 50),
]),
decoration: InputDecoration(labelText: 'Name'),
),
FormBuilderTextField(
name: 'phone',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.minLength(context, 10),
FormBuilderValidators.maxLength(context, 10),
FormBuilderValidators.numeric(context,
errorText: 'Mobile No should be 10 digits')
]),
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Phone'),
),
FormBuilderChoiceChip(
name: 'gender',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['M', 'F']
.map((value) => FormBuilderFieldOption(
value: value,
child: (value == 'M')
? Text('Male')
: Text('Female'),
))
.toList(),
decoration: InputDecoration(labelText: 'Gender'),
),
FormBuilderChoiceChip(
name: 'bloodGroup',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['A+','O+']
.map((value) => FormBuilderFieldOption(value: value))
.toList(),
decoration: InputDecoration(labelText: 'Blood Group'),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Theme.of(context).accentColor,
child: Text('Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
//print(_formKey.currentState.mounted);
Map<String, dynamic> _donorMap;
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
//print(_formKey.currentState.value);
_donorMap = {
..._formKey.currentState.value,
'createdDate': DateTime.now()
};
print(_donorMap);
/*await BloodDonorsController()
.saveBloodDonors(widget.mode!, _donorMap);*/
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Add Donor Successful'),
),
);
_formKey.currentState.reset();
//FocusScope.of(context).requestFocus(focusNode);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Validation Failed'),
),
);
}
},
),
SizedBox(width: 20),
MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
"Reset",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_formKey.currentState.reset();
},
),
],
),
)
],
),
),
),
);
}
}
class ListBloodDonorPage extends StatefulWidget {
#override
_ListBloodDonorPageState createState() => _ListBloodDonorPageState();
}
class _ListBloodDonorPageState extends State<ListBloodDonorPage> {
#override
Widget build(BuildContext context) {
return Container(child: Text('Display List of Donors'),);
}
}
What is the problem here?
Can anyone please help me?
I was able to finally solve this by converting the stateful widgets to methods and adding the Visibility widget to display the widget with the state maintained as shown below.
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
BloodDonationPage(),
),
);
},
child: Scaffold(
body: Center(
child: Container(
width: 200,
height: 100,
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Center(
child: Text(
"Blood Donation",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
)),
),
),
),
),
);
}
}
class BloodDonationPage extends StatefulWidget {
#override
_BloodDonationPageState createState() => _BloodDonationPageState();
}
class _BloodDonationPageState extends State<BloodDonationPage> {
bool _addButton = false;
bool _listButton = false;
final _formKey = GlobalKey<FormBuilderState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 60,
//width: 600,
child: Card(
color: Colors.pink[50],
shadowColor: Colors.pink,
elevation: 20,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
GestureDetector(
onTap: () {
setState(() {
_addButton = true;
_listButton = false;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side:
BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"Add Donor",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
),
),
GestureDetector(
onTap: () {
setState(() {
_addButton = false;
_listButton = true;
});
},
child: Padding(
padding: const EdgeInsets.only(left: 60, right: 30.0),
child: Card(
elevation: 20,
color: Colors.pink[100],
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.white70, width: 1),
borderRadius: BorderRadius.circular(10),
),
margin: EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"List Donors",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold),
)),
),
),
),
),
],
),
),
),
Visibility(visible: _addButton, maintainState: true,child: buildAdd()),
Visibility(visible: _listButton ,child: buildList()),
],
),
);
}
Widget buildList() => Container(child: Text('Display List of Donors'),);
Widget buildAdd() => Padding(
padding: const EdgeInsets.all(30.0),
child: Column( children: [ FormBuilder(
autovalidateMode: AutovalidateMode.disabled,
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FormBuilderTextField(
autofocus: true,
name: 'name',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.maxLength(context, 50),
]),
decoration: InputDecoration(labelText: 'Name'),
),
FormBuilderTextField(
name: 'phone',
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
FormBuilderValidators.minLength(context, 10),
FormBuilderValidators.maxLength(context, 10),
FormBuilderValidators.numeric(context,
errorText: 'Mobile No should be 10 digits')
]),
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Phone'),
),
FormBuilderChoiceChip(
name: 'gender',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['M', 'F']
.map((value) => FormBuilderFieldOption(
value: value,
child: (value == 'M')
? Text('Male')
: Text('Female'),
))
.toList(),
decoration: InputDecoration(labelText: 'Gender'),
),
FormBuilderChoiceChip(
name: 'bloodGroup',
elevation: 10,
selectedColor: Colors.white,
disabledColor: Colors.black12,
alignment: WrapAlignment.spaceAround,
options: ['A+','O+']
.map((value) => FormBuilderFieldOption(value: value))
.toList(),
decoration: InputDecoration(labelText: 'Blood Group'),
),
],),),
SizedBox(height: 100,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Theme.of(context).accentColor,
child: Text('Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
//print(_formKey.currentState.mounted);
Map<String, dynamic> _donorMap;
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
//print(_formKey.currentState.value);
_donorMap = {
..._formKey.currentState.value,
'createdDate': DateTime.now()
};
print(_donorMap);
/*await BloodDonorsController()
.saveBloodDonors(widget.mode!, _donorMap);*/
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Add Donor Successful'),
),
);
_formKey.currentState.reset();
//FocusScope.of(context).requestFocus(focusNode);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Validation Failed'),
),
);
}
},
),
SizedBox(width: 20),
MaterialButton(
color: Theme.of(context).accentColor,
child: Text(
"Reset",
style: TextStyle(color: Colors.white),
),
onPressed: () {
_formKey.currentState.reset();
},
),
],
)
],
),
);
}

How to use Flutter AnimatedContainer with height matching child

Currently this code works to resize a container to toggle between different content, but it's not animating. I think that I need to provide a height property to make the animation work, and when I do provide a height to toggle between it does match, like this:
height: selected ? 400 : 100,
The container animates smoothly between the two states. However the height is no longer adaptive. So I try to supply a height using:
GlobalKey _key = GlobalKey();
_size = _key.currentContext.size;
height: _size.height,
But it gives me errors and I'm not sure how to fix it.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool selected = false;
// GlobalKey _key = GlobalKey();
// Size _size = _key.currentContext.size;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
// _size = _key.currentContext.size;
});
},
child: Padding(
padding: EdgeInsets.all(5),
child: AnimatedContainer(
// height: _size.height,
// key: _key,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
if (selected)
Container(
child: Column(
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
border: Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height:20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue, width: 1, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
"Reply",
),
),
),
],
)
],
),
),
],
),
),
),
),
),
],
),
),
],
)
);
}
}
I thing AnimatedContainer is not Appropriate for this situation. I think its better to use AnimatedCrossFade. The AnimatedContainer will automatically animate between the old and new values of properties when they change using the provided curve and duration.
following code is refactored for using AnimatedCrossFade:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool selected = false;
// GlobalKey _key = GlobalKey();
// Size _size = _key.currentContext.size;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
// _size = _key.currentContext.size;
});
},
child: Padding(
padding: EdgeInsets.all(5),
child: AnimatedCrossFade(
duration: Duration(seconds: 1),
crossFadeState: selected
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: Container(
// height: !selected ? 100 : 400,
// key: _key,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
if (selected)
Container(
child: Column(
children: [
Padding(
padding:
EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin:
EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(20.0),
color: Colors.white,
border:
Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding:
const EdgeInsets.all(
10.0)),
keyboardType:
TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding:
const EdgeInsets.all(10.0)),
keyboardType:
TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue,
width: 1,
style: BorderStyle.solid),
borderRadius:
BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(
0, 10, 0, 10),
child: Text(
"Reply",
),
),
),
],
)
],
),
),
],
),
),
),
secondChild: Container(
// height: !selected ? 100 : 400,
// key: _key,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
],
),
),
),
),
),
),
],
),
),
],
));
}
}
You can use custom animation to do this, like this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
bool selected = false;
GlobalKey _key1 = GlobalKey();
GlobalKey _key2 = GlobalKey();
AnimationController _controller;
Animation _animation;
bool foward = false;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_animation = Tween<double>(
begin: _key1.currentContext.size.height,
end: _key2.currentContext.size.height +
_key1.currentContext.size.height)
.chain(CurveTween(curve: Curves.fastOutSlowIn))
.animate(_controller);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Padding(
padding: EdgeInsets.all(5),
child: GestureDetector(
onTap: () {
if (foward) {
_controller.reverse();
} else {
_controller.forward();
}
foward = !foward;
},
child: (_animation == null)
? _buildWidget(_key1, _key2)
: AnimatedBuilder(
// curve: Curves.fastOutSlowIn,
animation: _controller,
builder: (context, child) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17.0),
child: Container(
height: _animation.value, child: child),
));
},
child: _buildWidget(_key1, _key2)),
),
),
],
)));
}
Widget _buildWidget(Key key1, Key key2) {
return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Widget1(
key: _key1,
),
Widget2(
key: _key2,
),
],
),
);
}
}
class Widget1 extends StatefulWidget {
Widget1({Key key}) : super(key: key);
#override
_Widget1State createState() => _Widget1State();
}
class _Widget1State extends State<Widget1> {
#override
Widget build(BuildContext context) {
return Column(mainAxisSize: MainAxisSize.min, children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
]);
}
}
class Widget2 extends StatefulWidget {
Widget2({Key key}) : super(key: key);
#override
Widget2State createState() => Widget2State();
}
class Widget2State extends State<Widget2> {
#override
Widget build(BuildContext context) {
return Column(mainAxisSize: MainAxisSize.min, children: [
Container(
child: Column(children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
border: Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height: 20),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue, width: 1, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
"Reply",
),
))
])
]))
]);
}
}

How to dynamically sort by date in flutter?

I am working on a to do list app on flutter and I will like to sort the uploaded tasks by date(new ones appear first). for doing this I think a key should be givin to each of the uploaded items in the to do list and this key should include a Date. In react native for doing this I added a function to the data in a flatlist which sorted by date but since I am new to flutter I dont know how can that be done. Any Idea helps :)
main.dart
List<String> _toDoItems = []; //this is the array in which the uploaded tasks are stored, btw Im not using any database.
TextEditingController _controller = TextEditingController();
void _addToDoItem(String task) {
if(task.length > 0) {
setState(() {
_toDoItems.add(task);
});
}
}
void _removeTodoItem(int index) {
setState(() => _toDoItems.removeAt(index));
}
Widget _buildToDoItem(String toDoText, int index) {
return SizedBox(
child: Container(
height: 58,
margin: EdgeInsets.only(left: 22.0, right: 22.0, bottom: 12,),
decoration: BoxDecoration(
border: Border.all(width: 1.5, color: Colors.red),
borderRadius: BorderRadius.all(Radius.circular(18)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children:[
Expanded(
child: ListTile(
title: Text(
toDoText,
style: TextStyle(fontSize: 18),
),
onTap: () => _removeTodoItem(index),
),
),
FlatButton(
child: Text('Delete', style: TextStyle(color: Colors.red, fontSize: 16.5),),
onPressed: () => _removeTodoItem(index),
),
],
),
),
);
}
Widget _buildToDoList() {
return Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
if (index < _toDoItems.length) {
return _buildToDoItem(_toDoItems[index], index);
}
},
),
);
}
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
centerTitle: true,
backgroundColor: Colors.red,
title: Text('To Do List', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold,),),
)
),
backgroundColor: Colors.white,
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 60,
margin: EdgeInsets.all(22),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 10,
child: Container(
height: double.infinity,
child: TextField(
controller: _controller,
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
_controller.clear();
},
style: TextStyle(fontSize: 18,),
),
),
),
Expanded(
flex: 4,
child: Container(
height: double.infinity,
margin: EdgeInsets.only(left: 12),
child: RaisedButton(
textColor: Colors.white,
color: Colors.red,
child: Text('ADD', style: TextStyle(fontSize: 18)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
onPressed: () {
_addToDoItem(_controller.text);
_controller.clear();
FocusScope.of(context).requestFocus(FocusNode());
},
),
),
),
],
),
),
_buildToDoList()
]
),
),
);
}
You need to use the sort() method of List, also you need to be able to stock in a way or another the time of creation of your task.
I've made an example with the code you've posted. Using it your last created element will always be the first of the list.
import 'package:flutter/material.dart';
class ToDoElement {
final String task;
final DateTime timeOfCreation;
ToDoElement(this.task, this.timeOfCreation);
}
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
createState() => _MyAppState();
}
class _MyAppState extends State {
TextEditingController _controller = TextEditingController();
List<ToDoElement> _toDoItems = [];
void _removeTodoItem(int index) {
setState(() => _toDoItems.removeAt(index));
}
void _addToDoItem(String task) {
if (task.isNotEmpty) {
setState(() => _toDoItems.add(ToDoElement(task, DateTime.now())));
}
}
Widget _buildToDoItem(String toDoText, int index) {
return SizedBox(
child: Container(
height: 58,
margin: EdgeInsets.only(left: 22, right: 22, bottom: 12),
decoration: BoxDecoration(
border: Border.all(width: 1.5, color: Colors.red),
borderRadius: BorderRadius.all(Radius.circular(18)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: ListTile(
title: Text(
toDoText,
style: TextStyle(fontSize: 18),
),
onTap: () => _removeTodoItem(index),
),
),
FlatButton(
child: Text(
'Delete',
style: TextStyle(color: Colors.red, fontSize: 16.5),
),
onPressed: () => _removeTodoItem(index),
),
],
),
),
);
}
int compareElement(ToDoElement a, ToDoElement b) =>
a.timeOfCreation.isAfter(b.timeOfCreation) ? -1 : 1;
Widget _buildToDoList() {
_toDoItems.sort(compareElement);
return Expanded(
child: ListView.builder(
itemCount: _toDoItems.length,
itemBuilder: (context, index) {
return _buildToDoItem(_toDoItems[index].task, index);
},
),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
centerTitle: true,
backgroundColor: Colors.red,
title: Text(
'To Do List',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
)),
backgroundColor: Colors.white,
body: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
Container(
height: 60,
margin: EdgeInsets.all(22),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 10,
child: Container(
height: double.infinity,
child: TextField(
controller: _controller,
autofocus: true,
onSubmitted: (val) {
_addToDoItem(val);
_controller.clear();
},
style: TextStyle(
fontSize: 18,
),
),
),
),
Expanded(
flex: 4,
child: Container(
height: double.infinity,
margin: EdgeInsets.only(left: 12),
child: RaisedButton(
textColor: Colors.white,
color: Colors.red,
child: Text('ADD', style: TextStyle(fontSize: 18)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
onPressed: () {
_addToDoItem(_controller.text);
_controller.clear();
FocusScope.of(context).requestFocus(FocusNode());
},
),
),
),
],
),
),
_buildToDoList()
]),
),
);
}
}

How to make custom tabbar with gradient

How to make tab bar like below image in flutter?Is it possible to develop a Tabbar like below ?If not possible then what is the next better working solution?
Thank you for the support and i solved this issue my self without using any answers from stackoverflow
Try this way
I have created tab layout using ScrollablePositionedList
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_widgets/flutter_widgets.dart';
void main() => runApp(HomeScreen());
int currentTab = 0;
class HomeScreen extends StatefulWidget {
#override
_HomeScreenPage createState() => _HomeScreenPage();
}
class TabModel {
String text;
TabModel({this.text});
}
List<TabModel> _tabList = [
TabModel(text: "Android"),
TabModel(text: "IOS"),
TabModel(text: "Java"),
TabModel(text: "JavaScript"),
TabModel(text: "PHP"),
TabModel(text: "HTML"),
TabModel(text: "C++"),
];
class _HomeScreenPage extends State<HomeScreen>
with SingleTickerProviderStateMixin {
PageController _controller = PageController(initialPage: 0, keepPage: false);
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionListener =
ItemPositionsListener.create();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.purple,
brightness: Brightness.light,
accentColor: Colors.red),
darkTheme: ThemeData(
brightness: Brightness.dark,
),
home: Scaffold(
appBar: AppBar(
title: Text("Custom TabBar"),
),
body: Column(
children: <Widget>[
Container(
height: 60,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14.0),
border: Border.all(color: Colors.black, width: 1.0)),
child: ScrollablePositionedList.builder(
scrollDirection: Axis.horizontal,
itemCount: _tabList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
gradient: currentTab == index
? LinearGradient(
colors: [
Colors.redAccent,
Colors.redAccent[200],
Colors.redAccent[100]
],
)
: null,
borderRadius: BorderRadius.circular(13.0),
),
child: FlatButton(
color: Colors.transparent,
onPressed: () {
setState(() {
currentTab = index;
_controller.jumpToPage(currentTab);
});
},
child: Text(
_tabList[index].text,
),
),
);
},
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionListener,
)),
Flexible(
child: Container(
child: PageView(
controller: _controller,
onPageChanged: (pageId) {
setState(() {
currentTab = pageId;
itemScrollController.scrollTo(
index: currentTab, duration: Duration(seconds: 1));
});
},
children: <Widget>[
Container(
color: Colors.pink,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.cyan,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.red,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.green,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.grey,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.purple,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
Container(
color: Colors.teal,
child: Center(
child: Text(
_tabList[currentTab].text,
style: TextStyle(
color: Colors.white,
fontSize: 50,
fontWeight: FontWeight.bold),
),
),
),
],
),
)),
],
)));
}
}
You can find source code for this demo from my github account
OUTPUT
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(home: MainScreen()),
);
class MainScreen extends StatefulWidget {
_MainState createState() => _MainState();
}
class _MainState extends State<MainScreen> {
int viewChoice = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Toolbar Title',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold /*fontSize,etc*/),
),
actions: [
IconButton(
icon: Icon(Icons.account_circle),
onPressed: () {
//Todo when pressed
}),
]),
body: Container(
child: Column(mainAxisSize: MainAxisSize.min, children: [
SizedBox(
height: 200,
width: double.infinity,
child: Stack(children: [
Container(
padding: EdgeInsets.all(10.0),
alignment: Alignment.centerLeft,
color: Colors.yellow,
height: 100.0,
width: double.infinity,
child: Text('Tem',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20.0)), //Tem is in your ex pic
),
Positioned(
top: 75.0,
left: 40.0,
right: 40.0,
child: Container(
margin: EdgeInsets.only(left: 25.0, right: 25.0),
alignment: Alignment.topCenter,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14.0),
border: Border.all(color: Colors.black, width: 1.0)),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Expanded(
child: Container(
decoration: BoxDecoration(
gradient: viewChoice == 0
? LinearGradient(
colors: [Colors.orange, Colors.orangeAccent],
)
: null,
borderRadius: BorderRadius.circular(13.0),
border: viewChoice == 0
? Border.all(color: Colors.black, width: 1.0)
: null,
),
child: FlatButton(
color: Colors.transparent,
onPressed: () {
setState(() {
viewChoice = 0;
});
},
child: Text(
'All',
/*style as your requirement*/
),
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
gradient: viewChoice == 1
? LinearGradient(
colors: [Colors.orange, Colors.orangeAccent],
)
: null,
borderRadius: BorderRadius.circular(13.0),
border: viewChoice == 1
? Border.all(color: Colors.black, width: 1.0)
: null,
),
child: FlatButton(
onPressed: () {
setState(() {
viewChoice = 1;
});
},
child: Text(
'Favorites',
/*style as your requirement*/
),
),
),
),
]),
),
),
]),
),
viewChoice == 0
? ListView(shrinkWrap: true, children: [
//Content of All categories
])
: ListView(shrinkWrap: true, children: [
//Content of All categories
])
]),
),
);
}
}
TabBar without AppBar
Give a try to below code.
import 'package:flutter/material.dart';
import 'package:flutter_text_to_image/utils/app_colors.dart';
class TabBarWidget extends StatefulWidget {
final String firstTabTxt;
final String firstTabViewTxt;
final String secondTabTxt;
final String secondTabViewTxt;
const TabBarWidget({
super.key,
required this.firstTabTxt,
required this.secondTabTxt,
required this.firstTabViewTxt,
required this.secondTabViewTxt,
});
#override
State
<TabBarWidget>
createState() => _TabBarWidgetState();
}
class _TabBarWidgetState extends State
<TabBarWidget>
with SingleTickerProviderStateMixin {
TabController? _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
void dispose() {
_tabController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
height: 100,
child: Column(
children: [
Container(
height: 35,
decoration: BoxDecoration(
border: Border.all(
color: AppColors.tabBorderColor,
),
borderRadius: BorderRadius.circular(
5.0,
),
),
child: TabBar(
controller: _tabController,
indicator: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.waterMelonColor,
AppColors.mangoColor,
AppColors.azureColor,
AppColors.sapphireColor,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.0, 0.0),
stops: [
0.1,
0.4,
0.6,
1.0,
],
tileMode: TileMode.clamp,
),
borderRadius: BorderRadius.circular(
2.0,
),
),
labelColor: AppColors.whiteColor,
unselectedLabelColor: AppColors.blackColor,
tabs: [
Tab(
text: widget.firstTabTxt,
),
Tab(
text: widget.secondTabTxt,
),
],
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
Padding(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
Text(
widget.firstTabViewTxt,
),
],
),
),
Padding(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
Text(
widget.secondTabViewTxt,
),
],
),
),
],
),
),
],
),
);
}
}