Flutter Form Field floating at the top - flutter

I am having an issue with flutter forms.
Basically I have 3 simple rows added to a Stack. The last one contains a form. Below that there are 'Pinned' elements by Adobe XD, but the row containing the form is floating at the top of the screen... I would expect it to be arranged below the two first rows.
You can see the issue in the screenshot below. The form is on top of the image, but I want it to be above the 2 white lines which I want to replace by functional form fields.
Where am I going wrong? I have put the form in a separate Widget.
LoginPage.dart
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
stops: [
0.4,
1
],
colors: [
Colors.black,
Color(0xff7d060b),
])),
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: SafeArea(
child: Stack(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
/* Image.asset(
'assets/images/Logo.png',
height: 100,
width: 250,
),*/
Image.asset(
'assets/images/fewturelogo.png',
height: 50,
),
Container(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
color: Colors.white,
icon: const Icon(Icons.not_listed_location_rounded),
onPressed: () {
print('Hello');
showDialog(
context: context,
barrierDismissible: false,
// user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Was ist Rentalsplanet?'),
content: new SingleChildScrollView(
child: new ListBody(children: [
new Text(
'Hier erscheinen Informationen über Rentalsplanet')
]),
),
actions: [
new ElevatedButton(
child: Text('Alles klar!'),
onPressed: () {
Navigator.of(context).pop();
})
],
);
});
},
)),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.only(top: 70.0),
child: Image.asset(
'assets/images/SplashImageLogin.png',
scale: 1.1,
),
),
],
),
Row(children: [
Container(
margin: const EdgeInsets.only(top: 70.0),
child: SizedBox(width: 100, child: LoginForm()),
)
]),
],
),
),
),
);
LoginForm.dart
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
children: <Widget>[
new Flexible(
child: TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
),
ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
// Add TextFormFields and ElevatedButton here.
],
),
);
}

because you are using stack... stack is not an easy thing to work with and in your case, if you don't have to use it replace it with Column and your problem will be fixed.
if not alignment in Stack or fractionaloffset or Transform.translate will help you
Transform.translate will fix your problem but it might cause some responsive issues

Related

How to stack two bottom sheet in flutter?

I want to stack two bottom sheet each other in flutter as show in photo. The upper one is shown when in error state. In photo, it build with alert dialog. I want is with bottom sheet. How can I get it?
Edit:
Here is my code that I want to do. Lower bottom sheet is with pin field, autoComplete. autoComplete trigger StreamController, and then streamBuilder watch Error state and show dialog.
confirmPasswordModalBottomSheet(
BiometricAuthRegisterBloc biometricAuthRegBloc) {
showMaterialModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StreamBuilder(
stream: biometricAuthRegBloc.biometricAuthRegisterStream,
builder: (context,AsyncSnapshot<ResponseObject>biometricAuthRegSnapShot) {
if (biometricAuthRegSnapShot.hasData) {
if (biometricAuthRegSnapShot.data!.messageState ==
MessageState.requestError) {
showModalBottomSheet(context: context, builder:
(BuildContext context){
return Container(
width: 200,height: 200,
child: Center(child: Text('Helllllllllo'),),);
});
}
}
return SizedBox(
width: 100,
height: 300,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: margin30,
),
Text(CURRENT_PIN_TITLE),
SizedBox(
height: margin30,
),
Padding(
padding: const EdgeInsets.only(
left: margin60, right: margin60),
child: PinCodeField(
pinLength: 6,
onChange: () {},
onComplete: (value) {
biometricAuthRegBloc.biometricAuthRegister(
biometricType:_biometricAuthTypeForApi,
password: value);
},
),
),
SizedBox(
height: margin30,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal:
margin80),
child: AppButton(
onClick: () {},
label: CANCEL_BTN_LABEL,
),
),
Container(
padding: const EdgeInsets.all(8.0),
margin:
EdgeInsets.symmetric(vertical: 8.0,
horizontal: 30),
decoration: BoxDecoration(
color: Colors.grey,
border: Border.all(color: Colors.black),
),
child: const Text(
FINGER_PRINT_DIALOG,
textAlign: TextAlign.center,
),
)
],
),
);
});
},
);
}
When I do like that above, I get setState() or markNeedsBuild() called during build. Error and why? Sorry for my previous incomplete question.
I am bit confused with your question but stacking two bottomsheet is just easy. You just need to call the showModalBottomSheet whenever you want it shown to user. You can check out the following implementation:
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ElevatedButton(
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 500,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet 1'),
ElevatedButton(
child: const Text('Show second modal 2'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.redAccent,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet 2'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
},
);
},
),
],
),
),
);
},
);
},
child: Text('Show bottom sheet 1'),
),
);
}
}
I have solution. All I need to do is, need to add WidgetBinding.insatance.addPostFrameCallback((timeStamp){showModalBottomSheet()}); in the StreamBuilder return.

Listview.builder not showing my images when implementing in Flutter

I am trying to implement a horizontal Listview which shows my images pulled from the Flutter image_picker plugin.
its work fine if I do not use a Listview and only display a single image. however I am trying to use multiple images and as soon as I place within the Listview the widgets just shows up as black. my code for the Listview is as follows:
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
Navigator.pushReplacementNamed(context, 'inventory');
return false;
},
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.green[700],
title: Text(
'MyApp',
textAlign: TextAlign.center,
),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
Navigator.pushReplacementNamed(
context,
'inventory');
},
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 10.0),
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white, //remove this when you add image.
),
child: GestureDetector(
onTap: (){
Navigator.pushNamed(context,'profile');
},
child: Image(
image:NetworkImage("imageUrl goes here"),
width: 120,
height: 120,
fit: BoxFit.cover,
),
),
),
)
],
),
body: SafeArea(
child: Column(
children: [
pickedFile == null ?
GestureDetector(
onTap: () {
_showMyDialog();
setState(() {
});
},
child: Container(
width: 200,
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Click to add a Photo',textAlign:
TextAlign.center,style: TextStyle(fontSize: 24),),
SizedBox(height: 20,),
Icon(
Icons.add_circle_outline,
color: Colors.grey[700],
size: 30,
),
],
),
margin: EdgeInsets.all(20.0),
decoration: BoxDecoration(
border: Border.all(width: 2,color: Colors.grey),
shape: BoxShape.circle
),
),
)
:
GestureDetector(
onTap: () {
_showMyDialog();
setState(() {
});
},
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: _imageFileList!.length,
itemBuilder: (BuildContext context, int index) {
return kIsWeb
? Image.network(_imageFileList![index].path)
: Image.file(File(_imageFileList!
[index].path));
}
)
],
),
),),
);
}
}
I am not showing the whole code as the page is too long however the rest of the page works fine. if i remove the Listview builder and instead test using just the below it works fine. what am i doing wrong?
child: Row(
children: [
kIsWeb
? Container(
child: Image.network(_imageFileList![index].path))
: Container(
child: Image.file(File(_imageFileList![index].path)));
}
),
],
),
Please help.
**Edited the above code with my full widget
Either use Row or use ListView, not both.
You can use Row with List.generate:
Row(
children: List.generate(_imageFileList!.length,
(i) => kIsWeb
? Container(child: Image.network(_imageFileList![index].path))
: Container(child: Image.file(File(_imageFileList![index].path))
),
Or ListView exactly how you have it without the Row. ListView is probably the widget you’re wanting to use. Row will overflow if the content is larger than the width while ListView will act as its own ScrollView in that situation.
I’d also double-check that you need that Expanded widget. That’s typically for use inside a Row (or similar widgets).
Managed to solve my issue. it was related to a height constraint which needed to be added. found the solution in this link
How to add a ListView to a Column in Flutter?

Widget on a widget with Centering

I want to put a widget onto other's view.
Here is what I did
In normal version without countdown timer, there is no whitespace inside the screen. It is %50 %50 divided by colours(red and blue).
What I want to do is adding that countdown timer without creating whitespace. Directly adding it onto those colours on the center.
I saw that with Stack it is possible to do. I tried it but couldn't remove the white area.
Here is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: new Column(
children: [
Expanded(
flex: 40,
child: new Container(
width: double.infinity,
child: new Column(
children: <Widget>[
box1 = new Expanded(
flex: boxSize1,
child: InkWell(
onTap: () {
clickBox1();
}, // Handle your callback
child: new Container(
alignment: Alignment.topCenter,
color: colorRandom,
),
),
),
TimeCircularCountdown(
unit: CountdownUnit.second,
countdownTotal: 3,
onUpdated: (unit, remainingTime) => print('Updated'),
onFinished: () {
setState(() {
visibility = false;
});
},
),
box2 = new Expanded(
flex: boxSize2,
child: InkWell(
onTap: () {
clickBox2();
}, // Handle your callback
child: new Container(
alignment: Alignment.topCenter,
color: color,
),
),
),
],
),
),
),
],
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Column(
children: [
Expanded(
child: Container(
color: Colors.blue,
)),
Expanded(
child: Container(
color: Colors.red,
)),
],
),
Center(
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Colors.white,
),
// use your countdown timer widget in child
),
)
],
),
);
}

flutter: how to customize cuperinoAlertDialog style?

I'm working with flutter. I want to make a CupertinoAlertDialog(iOS style is required). My problem is UI designers require the background color of the alert dialog should be #F0F0F0. But I can only adjust its theme into dark or light(e.g. following picture). The code I completed is placed below.
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return Theme(
data: ThemeData.dark(),
child: CupertinoAlertDialog(
title: Text('Title'),
content: Text('Some message here'),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancle'),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
}
);
Is that possible? Thanks for any advice.
If I recall correctly, the background color for CupertinoAlertDialog is hardcoded. However, you can create a custom dialog that can change the background color of it as well as the functions of the buttons.
You need to create a type Dialog for the showDialog function instead of showCupertinoDialog:
Dialog customDialog = Dialog(
backgroundColor: Color(0xfff0f0f0), // your color
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)), // change 40 to your desired radius
child: CustomAlertDialog(),
);
I also created a stateless widget called CustomAlertDialog, but if you don't want to, you can replace the CustomAlertDialog() with its content.
class CustomAlertDialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 150,
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey, width: 1),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: Center(
child: Text(
"Title",
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
Container(
child: Center(
child: Text("Some message here"),
),
),
],
),
),
),
Expanded(
flex: 1,
child: Row(
children: [
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(color: Colors.grey, width: 1),
),
),
child: Center(
child: Text("Cancel"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
child: Center(
child: Text("OK"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
],
),
),
],
),
);
}
}
Lastly, replace your whole showCupertinoDialog with this showDialog function:
showDialog(
barrierDismissible: true, // set false if you dont want the dialog to be dismissed when user taps anywhere [![enter image description here][1]][1]outside of the alert
context: context,
builder: (context) {
return customDialog;
},
);
Result: https://i.stack.imgur.com/cV13A.png

Flutter - How to fill remaining space in Stepper controls builder?

In the screenshot, I want to get the next and back buttons to the bottom of the screen.
The stepper has a parameter, controlsBuilder that allows you to build out the layout for the controls. If it's just a simple row, It's placed right underneath the content.
Apparently, the Stepper is a flexible wrapper. I'm not sure what that means. I think it means that the Stepper is considered a flex object because it contains a scrollable area (for the content). Having read the docs, if I'm understanding correctly, it says that I cannot use an Expanded or a Column with a max size in the mainAxis because the stepper is essentially a scrollable area, meaning any RenderBox inside it has unbounded constraints.
So, what are some ways the controls builder can be pushed down to the bottom?
Widget _createEventControlBuilder(BuildContext context, {VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: onStepCancel,
child: const Text('BACK'),
),
FlatButton(
onPressed: onStepContinue,
child: const Text('NEXT'),
),
]
);
}
I did try wrapping the above row in a LayoutBuilder as well as another attempt using a SizedBox, setting the height to MediaQuery.of(context).size.height;. It does push it near to the bottom (not quite as much as I like), but the problem is that now there is space beneath controls, causing the screen to scroll down into empty space.
Full code:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Create an Event"),
),
body: Form(
key: _eventFormKey,
child: Stepper(
type: StepperType.horizontal,
currentStep: _currentStep,
controlsBuilder: _createEventControlBuilder,
onStepContinue: () {
if (_currentStep + 1 >= MAX_STEPS)
return;
setState(() {
_currentStep += 1;
});
},
onStepCancel: () {
if (_currentStep + 1 >= MAX_STEPS)
return;
setState(() {
_currentStep -= 1;
});
},
steps: <Step>[
Step(
title: Text("Name"),
isActive: 0 == _currentStep,
state: _getStepState(0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 10.0),
child: Text(
"Give your event a cool name",
style: Theme.of(context).textTheme.title,
),
),
TextFormField(
maxLines: 1,
maxLength: 50,
maxLengthEnforced: true,
decoration: InputDecoration(
hintText: "e.g. Let's eat cheeseburgers!",
),
validator: (value) {
if (value.trim().isEmpty)
return "Event name required.";
},
)
],
)
),
Step(
title: Text("Type"),
isActive: 1 == _currentStep,
state: _getStepState(1),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 10.0),
child: Text(
"Select an event type",
style: Theme.of(context).textTheme.title,
),
),
Container(
margin: EdgeInsets.only(bottom: 10.0),
child: Row(
children: <Widget>[
Expanded(
child: DropdownButton<int>(
items: _stepTwoDropdownItems,
hint: Text("Select event type"),
isExpanded: true,
value: _eventTypeSelectedIndex,
onChanged: (selection) {
setState(() {
_eventTypeSelectedIndex = selection;
});
}),
)
],
)
)
],
)
),
]
),
),
);
}
I think you can create your own Stepper , or you can try this 'hack' :
Create two variables to store the callbacks:
VoidCallback _onStepContinue;
VoidCallback _onStepCancel;
Put your Form inside a Stack :
Stack(
children: <Widget>[
Form(
child: Stepper(
Change your createEventControlBuilder method:
Widget _createEventControlBuilder(BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
_onStepContinue = onStepContinue;
_onStepCancel = onStepCancel;
return SizedBox.shrink();
}
Add your custom buttoms :
Widget _bottomBar() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () => _onStepCancel(),
child: const Text('BACK'),
),
FlatButton(
onPressed: () => _onStepContinue(),
child: const Text('NEXT'),
),
]);
}
This is how your Stack will looks like :
Stack(
children: <Widget>[
Form(
child: Stepper(
....
), //Form
Align(
alignment: Alignment.bottomCenter,
child: _bottomBar(),
)
I know this is a little dirty, but you could try , otherwise I recommend you to create your own Widget.
You can also change the heights of the widgets in the contents of Steps to the same value, and make it a SingleChildScrollView if needed. e.g
Step(content: Container(
height: MediaQuery.of(context).size.height - 250, //IMPORTANT
child: SingleChildScrollView(
child: Column(children: <Widget>[
...
),