Responsive Container in flutter - flutter

I have a Single child scroll view with child container which I defined the height and width
The problem is when I click on textfield the button is hidden/does not go up. How do I make the height responsive?
#override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
_height = MediaQuery.of(context).size.height;
return SingleChildScrollView(
controller: _scrollController,
child: Container(
width: _width,
height: _height,
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: userBloc.user$,
builder: (BuildContext context, AsyncSnapshot snapshot) {
User user = snapshot?.data;
String maskedEmail = _getMaskedEmail(user);
return Column(
children: <Widget>[
widget.instruction != null
? Container(
padding: GenericAssets.paddingSymV10,
child: Text(
widget.instruction,
style: GenericAssets.defaultText,
textAlign: TextAlign.center,
))
: Container(),
(maskedEmail?.isNotEmpty ?? false)
? Column(
children: <Widget>[
Padding(
padding: GenericAssets.paddingSymV10,
child: Text(
S.of(context).strProvideMaskedEmail,
style: GenericAssets.defaultText,
textAlign: TextAlign.center),
),
Padding(
padding: GenericAssets.paddingSymV10,
child: Text(maskedEmail,
style: GenericAssets.defaultText,
textAlign: TextAlign.center),
)
],
)
: Container(),
Container(
child: TextFormField(
style: GenericAssets.defaultText18,
controller: _emailController,
focusNode: _emailFocusNode,
keyboardType: TextInputType.emailAddress,
inputFormatters: [LowerCaseTextFormatter()],
decoration: InputDecoration(
labelText:
S.of(context).fieldEmail.toUpperCase(),
labelStyle: GenericAssets.textFormLabel,
contentPadding:
GenericAssets.textFormFieldSpacing),
validator: (value) {
if (value.isEmpty) {
return S.of(context).msgTextFieldMandatory(
S.of(context).fieldEmail);
}
if (!isEmail(value) ||
!HelperFunctions.isPatternValid(
ProjectConstants.emailPattern, value)) {
return S.of(context).msgPleaseEnterAValidValue(
S.of(context).fieldEmail);
}
return null;
},
),
),
Padding(
padding: GenericAssets.paddingSymV5,
child: PasswordField(
_passwordController,
checkFormat: false,
showPassword: true,
focusNode: _passwordFocusNode,
),
)
],
);
},
),
),
FullWidthButton(
S.of(context).strLogin,
() async {
LoggerService.log(
LogEventType.ButtonPress,
LogDetails(
buttonName: 'Login', displayName: 'Login Screen'));
if (_formKey.currentState.validate()) {
widget.onSubmit(context, widget.authenticationManager,
_passwordController.text, _emailController.text);
}
},
),
InkWell(
onTap: onForgotPassword,
child: Padding(
padding: GenericAssets.padding10,
child: Text(
S.of(context).strForgotPassword,
style: GenericAssets.footNoteLink,
),
),
),
InkWell(
onTap: onResetApp,
child: Padding(
padding: GenericAssets.padding10,
child: Text(
S.of(context).btnResetApplication,
style: GenericAssets.footNoteLink,
),
),
)
],
),
),
),
);
}
I want to show the buttons and other widgets when keyboard is shown.
This is a widget I'm calling it from
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => HelperFunctions.logBackpress('Login Screen'),
child: Scaffold(
appBar: AppBar(title: AppBarTitle(S.of(context).strLogin)),
body: StreamBuilder(
stream: manager.loginState$,
builder: (BuildContext context, AsyncSnapshot snapshot) {
bool isLoading = snapshot?.data?.isLoading ?? false;
return Stack(
children: <Widget>[
LoginForm(onSubmit, authenticationManager: manager),
LoadingIndicator(isLoading)
],
);
},
),
),
);
}

Related

Not able to get element index in a listview - Flutter

i'm trying to make operations on clicked elements in a listView in flutter. An alertDialog should appear once I click an element so I can update its value. My backend works perfectly using the put http method. The problem is that i'm able to read the input value in console but not able to read the index of the clicked element.
As it's mentionned above, i'm able to read the input value which means that my api works correctly, but not able to retrieve the clicked element's index in the listView.
Console output:
I/flutter ( 4120): ============================== null
I/flutter ( 4120): 33
here is my update function:
handleMeasurement(String iv_id, String value) async {
final response = await http.put(
Uri.parse('${baseUrl}/api/v1/measurements/update/' + iv_id),
body: <String, String>{
"input_value": value
});
}
and here is my ui:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Traitement des mesures',
style: TextStyle(color: Colors.black),
),
centerTitle: true,
),
body: Visibility(
visible: isLoaded,
replacement: Center(child: CircularProgressIndicator()),
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(15),
itemCount: mesures?.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () => showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Mesure'),
content: TextField(
controller: _textFieldController,
decoration:
InputDecoration(hintText: "Entrez la valeur"),
),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => {
print(
"============================== ${mesures![index].measurement_id}"),
print(_textFieldController.text),
handleMeasurement(
"${mesures![index].measurement_id}",
_textFieldController.text),
Navigator.pop(context, 'OK')
},
child: const Text('OK'),
),
],
),
),
child: Container(
margin: EdgeInsets.only(bottom: 15),
child: Row(
children: [
SizedBox(
width: 70,
child: AspectRatio(
aspectRatio: 0.88,
child: Container(
decoration: BoxDecoration(
color: Color(0xFFF5F6F9),
borderRadius: BorderRadius.circular(15),
),
child: Image.asset(
'assets/note2.png',
),
),
),
),
SizedBox(width: 20),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Paramètre: ${mesures![index].param_name}",
style: TextStyle(
color: Colors.black, fontSize: 16),
maxLines: 2,
),
SizedBox(height: 10),
Text.rich(
TextSpan(
text:
"Description: ${mesures![index].description}",
style: TextStyle(
fontWeight: FontWeight.w600,
color: kPrimaryColor),
),
),
],
),
],
),
),
);
},
),
)
],
),
),
);
}
Can anyone help me out with it? thanks in advance!

set selected to radio button Flutter

How to set radio button to selected based on String value fetched from API?
I have an async function that does the API call and fetches the user profile. I need to set the selected gender to the radio button.
I tried calling SetState() from an async function but it results in infinite loop call for build().
Below is my code:
#override
Widget build(BuildContext context) {
if(isProfileExists) {
getProfileDetails();
print("selected radio : "+selectedRadio.toString());
if(selectedRadio >= 0) {
setMemberType(selectedRadio);
}
}
double width=MediaQuery.of(context).size.width;
double height=MediaQuery.of(context).size.height;
Future<bool> _onWillPop() async {
Navigator.pushNamedAndRemoveUntil(context, '/home', ModalRoute.withName('/home'));
}
return new WillPopScope(
child: Scaffold(
appBar: AppBar(
title: Text(
_userName+"\'s Profile ",
style: TextStyle(fontSize: 20.0),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.save
),
)
),
],
),
key: _scaffoldKey,
body: Container(
height: height,
width: width,
child: SingleChildScrollView(
padding: EdgeInsets.fromLTRB(0, 20.0, 0, 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
onTap: (){},
child: TextField(
decoration: InputDecoration(labelText: "Bio"),
controller: bioTextController,
),
),
SizedBox(height: 20.0,),
Padding(
padding: EdgeInsets.all(10.0),
child: Text("Basic Information", style: TextStyle(
color: Colors.black54,
fontSize: 14.0
),
),
),
TextField(
decoration: InputDecoration(labelText: "Height"),
controller: heightTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "Weight"),
controller: weightTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "BMI"),
controller: bmiTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "Target Weight"),
controller: targetWeightTextController,
),
TextFormField(
decoration: InputDecoration(labelText: "Date Of Birth"),
controller: dateOfBirthController,
),
TextFormField(
decoration: InputDecoration(labelText: "Age"),
readOnly: true,
controller: ageTextController,
),
SizedBox(height: 15.0),
Text("Gender"),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Radio(
value: 0,
groupValue: radioValue,
onChanged: setMemberType,
),
Text("Female" ),
Radio(
value: 1,
groupValue: radioValue,
onChanged: setMemberType,
),
Text("Male"),
],
),
...
And the set state function is below:
void setMemberType(int i) {
setState(() {
radioValue = i;
if(i == 0)
_gender = "F";
else
_gender = "M";
});
}
You cannnot call setState from your build method.
Remove this:
if(isProfileExists) {
getProfileDetails();
print("selected radio : "+selectedRadio.toString());
if(selectedRadio >= 0) {
setMemberType(selectedRadio);
}
}
Instead, use an initState inside the State of your Stateful Widget:
#override
void initState() {
if(isProfileExists) {
getProfileDetails();
if(selectedRadio >= 0) {
radioValue = selectedRadio;
}
}
}

Could not find the correct Provider<RetailerProvider> above this EditRetailer Widget

#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Column(
children: <Widget>[
_myAppBar(context),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 80,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Stack(children: <Widget>[
// The containers in the background
Column(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 8.0, right: 8.0),
child: Container(
width: MediaQuery.of(context).size.width,
height: 80.0,
child: Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Material(
color: Colors.white,
elevation: 14.0,
shadowColor: Color(0x802196F3),
child: Center(
child: GestureDetector(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'${items[index].name}',
style: TextStyle(
color: Colors.black,
fontSize: 20.0),
),
],
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditRetailer(items[index])));
},
),
),
),
),
),
),
]),
]);
}),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color(0xFFFA7397),
child: Icon(
FontAwesomeIcons.listUl,
color: Color(0xFFFDDE42),
),
onPressed: () {
//Navigator.push(context,MaterialPageRoute(builder: (context) => TaskScreen()),
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RetailerScreen(Retailer('', '', '', '')),
fullscreenDialog: true),
);
},
),
);
}
The problem occurred when i add this line of code into my above widget :
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditRetailer(items[index])));
},
My editRetailer.dart code
class EditRetailer extends StatefulWidget {
final Retailer retailer;
EditRetailer([this.retailer]);
#override
_EditRetailerState createState() => _EditRetailerState();
}
class _EditRetailerState extends State<EditRetailer> {
final nameController = TextEditingController();
final phoneController = TextEditingController();
final gstController = TextEditingController();
final addressController = TextEditingController();
#override
void dispose() {
nameController.dispose();
phoneController.dispose();
gstController.dispose();
addressController.dispose();
super.dispose();
}
#override
void initState() {
if (widget.retailer == null) {
//New Record
nameController.text = "";
phoneController.text = "";
gstController.text = "";
addressController.text = "";
new Future.delayed(Duration.zero, () {
final retailerProvider = Provider.of<RetailerProvider>(context,listen: false);
retailerProvider.loadValues(Retailer(null,null,null,null));
});
} else {
//Controller Update
nameController.text=widget.retailer.name;
phoneController.text=widget.retailer.phone;
gstController.text=widget.retailer.gst;
addressController.text=widget.retailer.address;
//State Update
new Future.delayed(Duration.zero, () {
final retailerProvider = Provider.of<RetailerProvider>(context,listen: false);
retailerProvider.loadValues(widget.retailer);
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
final retailerProvider = Provider.of<RetailerProvider>(context);
return Scaffold(
appBar: AppBar(title: Text('Edit Retailer')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(hintText: 'Retailer Name'),
onChanged: (value) {
retailerProvider.changeName(value);
},
),
TextField(
controller: phoneController,
decoration: InputDecoration(hintText: 'Retailer Phone'),
onChanged: (value) => retailerProvider.changePhone(value),
),
TextField(
controller: gstController,
decoration: InputDecoration(hintText: 'Retailer GST'),
onChanged: (value) => retailerProvider.changeGst(value),
),
TextField(
controller: addressController,
decoration: InputDecoration(hintText: 'Retailer Address'),
onChanged: (value) => retailerProvider.changeAddress(value),
),
SizedBox(
height: 20.0,
),
RaisedButton(
child: Text('Save'),
onPressed: () {
retailerProvider.saveRetailer();
Navigator.of(context).pop();
},
),
(widget.retailer !=null) ? RaisedButton(
color: Colors.red,
textColor: Colors.white,
child: Text('Delete'),
onPressed: () {
retailerProvider.removeProduct(widget.retailer.gst);
Navigator.of(context).pop();
},
): Container(),
],
),
),
);
}
}
This is the error im getting while running the app.
Error: Could not find the correct Provider<RetailerProvider> above this EditRetailer Widget
This likely happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that EditRetailer is under your MultiProvider/Provider<RetailerProvider>.
This usually happen when you are creating a provider and trying to read it immediatly.

Scroll not working in vertical list created using ListView?

I've created a vertical list inside a scrollable container. But the issue I'm facing is that the list is not scrolling.
This is the component which creates the parent container.
class _MainPageState extends State<MainPage> {
SharedPreferences sharedPreferences;
String _date = "Today";
#override
void initState() {
super.initState();
this.checkLoginStatus();
}
checkLoginStatus() async {
sharedPreferences = await SharedPreferences.getInstance();
if (sharedPreferences.getString("token") == null) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) => Login(),
),
(Route<dynamic> route) => false,
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: loggedInBar(sharedPreferences, context),
drawer: appDrawer(sharedPreferences, context),
body: SingleChildScrollView(
child: Container(
decoration: BoxDecoration(
color: hexToColor("#FFFFFF"),
),
child: Column(
children: <Widget>[
hero(),
SizedBox(height: 10),
Container(
padding: const EdgeInsets.fromLTRB(30, 20, 30, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
customText(
'$_date',
"#000000",
"26.0",
TextAlign.center,
"Roboto Black",
FontWeight.w900,
),
OutlineButton(
child: Container(
alignment: Alignment.center,
height: 42.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
customText(
"CHOOSE DAY",
"#EC2F3C",
"18",
TextAlign.center,
"Roboto Bold",
FontWeight.w800,
),
Icon(
Icons.date_range,
size: 22.0,
color: hexToColor("#EC2F3C"),
),
],
),
)
],
),
],
),
),
onPressed: () {
DatePicker.showDatePicker(context,
theme: DatePickerTheme(
containerHeight: 210.0,
),
showTitleActions: true,
minTime: DateTime(
DateTime.now().year - 100,
DateTime.now().month,
DateTime.now().day,
),
maxTime: DateTime(
DateTime.now().year - 17,
DateTime.now().month,
DateTime.now().day,
), onConfirm: (date) {
print('confirm $date');
var dateString = date;
var formattedDate = Jiffy(dateString).yMMMd;
setState(() {
_date = formattedDate;
});
}, currentTime: DateTime.now(), locale: LocaleType.en);
},
color: hexToColor("#efefef"),
splashColor: hexToColor("#efefef"),
highlightElevation: 2,
borderSide: BorderSide(
color: hexToColor("#EC2F3C"),
width: 2,
),
highlightedBorderColor: hexToColor("#EC2F3C"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(3),
),
),
],
),
),
AllEvents(), // the widget which creates the list(mentioned below)
SizedBox(height: 30),
footer(),
],
),
),
),
);
}
}
The widget which creates the list is this.
class _AllEventsState extends State<AllEvents> {
final String url = "<api url>";
List data;
#override
void initState() {
super.initState();
this.getAllEvents();
}
createRoute(id) {
Navigator.pushNamed(context, '/eventdetail', arguments: id);
}
Future<String> getAllEvents() async {
var response = await http.get(
Uri.encodeFull(url),
headers: {"Accept": "application/json"},
);
setState(() {
var convertDataToJson = jsonDecode(response.body);
data = convertDataToJson["events"];
});
return "Success";
}
#override
Widget build(BuildContext context) {
ScrollController _controller = new ScrollController();
return Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
physics: const AlwaysScrollableScrollPhysics(),
controller: _controller,
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext cont, int index) {
// format date
var dateString = data[index]["eventDate"];
var eventDate = Jiffy(dateString).MMMEd;
if (data == null) {
return Center(
child: Container(
padding: const EdgeInsets.fromLTRB(30, 20, 30, 20),
child: CircularProgressIndicator(),
),
);
} else {
return Container(
padding: const EdgeInsets.fromLTRB(30, 7, 30, 7),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new InkWell(
onTap: () {
createRoute(data[index]['_id']);
},
child: Card(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: hexToColor("#EBEBEB"),
),
borderRadius: BorderRadius.circular(8.0),
),
padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
customText(
eventDate.toString(),
"#000000",
"20.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
customText(
"10, 9",
"#000000",
"20.0",
TextAlign.right,
"Roboto Black",
FontWeight.w900,
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: customText(
"${data[index]['city']} | ${data[index]['arenaName']} | ${data[index]['categories'][0]['title']}",
"#000000",
"18.0",
TextAlign.left,
"Roboto Black",
FontWeight.w900,
),
),
],
),
],
),
),
),
),
],
),
),
);
}
},
),
);
}
}
The scroll is only working on touching outside the list area and once the list area covers the entire screen I'm unable to scroll the page further. I think I'm doing many mistakes here as I'm a noob in flutter. I'm unable to wrap my head around what I'm doing wrong as I don't think this is how it's supposed to work.
Please help me fix this issue. Any help would be great? Thank you
change the scroll physics of list to NeverScrollableScrollPhysics
ListView.builder(
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
controller: _controller,
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext cont, int index) {
// code for building list item
});

Use Navigator.push (MaterialPageRoute) instead of AlertDialog

I would like to use Navigator.push (MaterialPageRoute) instead of AlertDialog as now I think its better for my user to have a full page to post content rather than a dialog box, how would I go about editing my code to do this? Thanks in advance
appBar: AppBar(
centerTitle: true,
title: Text('hehe',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25.0),),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: IconButton(icon: Icon(Icons.comment),
onPressed: () {
showDialog(context: context,
builder: (BuildContext context){
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
content: Form(key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
initialValue: '',
onSaved: (val) => board.subject = val,
validator: (val) => val == "" ? val: null,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: RaisedButton(
color: Colors.indigo,
child: Text(
'Post',
style: TextStyle(color: Colors.white),),
onPressed: () {
handleSubmit();
Navigator.of(context).pop();
},
),
)
],
),
),
);
},
);
}
),
),
],
),
Create a StatefulWidget subclass say MyForm.
class MyForm extends StatefulWidget {
#override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("My form")),
body: Form(
key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
initialValue: '',
onSaved: (val) => board.subject = val,
validator: (val) => val == "" ? val : null,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: RaisedButton(
color: Colors.indigo,
child: Text(
'Post',
style: TextStyle(color: Colors.white),
),
onPressed: () {
handleSubmit();
Navigator.of(context).pop();
},
),
)
],
),
),
);
}
}
And use it like this in your onPressed method.
onPressed: () {
Navigator.push(context, MaterialPagerRoute(builder: (context) => MyForm()));
}
So, when the button is clicked, you will be navigated to the new page which is your form currently.