I am tring to create ui as below image. but button hide behind the list. Also faces issue button not click when used Positioned widget for button.Please suggest how to create below UI using Stack widget with ListView & Floating button.
UI
Container(
color: Colors.grey,
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Column(
children: <Widget>[
Container(
height: 250.0,
width: MediaQuery.of(context).size.width,
child: Image.asset(
"images/1.jpg",
fit: BoxFit.cover,
),
)
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
height: 220.0,
),
Container(
padding: EdgeInsets.only(right: 15.0),
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.favorite),
),
),
],
),
Column(
children: <Widget>[
Container(
height: 250.0,
),
Container(
height: MediaQuery.of(context).size.height - 250.0,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("Title $index"),
leading: Icon(Icons.home),
),
);
},
itemCount: 15,
),
),
],
)
],
),
],
),
);
As per documentation (https://docs.flutter.io/flutter/widgets/Stack-class.html):
The stack paints its children in order with the first child being at the bottom
So your Stack children's order is wrong. Your current order is:
Header
Button
List
But it should be:
Header
List
Button
Otherwise list is overlapping button.
Related
Does anyone know how to make my stepper scrollable in vertically, it actually could scroll but it doesn't scrolling till the end of the page length
The stepper:
MainScaffold(
title: appBarTitle,
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
width: width,
child: Column(
children: <Widget>[
const SizedBox(
height: 8,
),
Row(
children: _lineViews(),
),
const SizedBox(
height: 8,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: _titleViews(),
),
const SizedBox(
height: 20,
),
Expanded(
child: ListView(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: stepPanels())
],
),
),
const SizedBox(
height: 20,
),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: _buttonControls(currentStep, context),
);
I put the stepper's content inside expanded listview, and I already add shrinkwrap & physics into it, when I call this customizable widget on another class, it can't be scrolled till the end of the page
Steps(
content: Obx(
() {
if (controller.loading.value) {
return const LoadingProgressIndicator();
} else {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: ListView(
physics: const ClampingScrollPhysics(),
children: [
controller.loading.value
? const LoadingProgressIndicator()
: _doctorProfile(),
const SizedBox(height: 10.0),
const ClinicTypeToggle(),
const SizedBox(height: 100.0),
],
),
);
}
},
),
),
that is the content that I want to scroll
I want to have a container with a flexible body (red) height and a fixed button height (gray).
The complete container should be as small as possible and have a max height.
If the content is overflowing the max height it should be scrollable.
I'm new to flutter, so I have no idea how to achieve this.
I tried it with a ConstraintBox with maxHeight, but then the whole container is bigger then it have to be, when the content is small.
return Container(
child: Column(
children: [
ConstrainedBox(
maxHeight: 400
child: //SomeWidget that could overflow
),
Container(
height: 150,
child: Center(
child: TextButton(child: Text('OK'))
),
)
],
),
);
Can someone help?
You can set constraints of your Container. Also you can use Flexible and SingleChildScrollView
Container(
constraints: BoxConstraints(
maxHeight: 300,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: Column(
children: [
//SomeWidget that could overflow
],
),
)),
Container(
color: Colors.amber,
height: 150,
child:
Center(child: TextButton(onPressed: () {}, child: Text('OK'))),
)
],
),
)
I've achieved it now, with that code:
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: //SomeWidget that could overflow
),
),
Container(
alignment: Alignment.bottomCenter,
child: TextButton(
child: Text('OK')
)
)
]
)
)
According to your UI i think this one will be perfect, and let me know if you need any changes. use constraints to change size.
final widgets = List.generate(
12,
(index) => Container(
height: 100,
color: index % 2 == 0 ? Colors.cyanAccent : Colors.greenAccent,
child: Text("item $index"),
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: SizedBox(
///* used 90% of screen for items
height: constraints.maxHeight * .9,
child: ListView(
children: [
Center(child: Text("inside listView")),
///your widgets
...widgets,
Center(child: Text("End of listView")),
],
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
color: Colors.grey.withOpacity(.3),
///* used 10% of screen for Button
height: constraints.maxHeight * .1,
child: Center(
child: TextButton(
child: Text('OK'),
onPressed: () {},
),
),
),
),
],
),
),
);
}
I have a list view with horizontal scroll and i have added CupertinoContextMenu to the image.
everything is works fine but the action buttons are not aligned center.
I have added the code. I tried with wrap scaffold too. same issue still.
I have to align the action buttons under the image center posisiton.
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Center(child: _invoiceImageSlider()),
);
// Image Slider List
Widget _invoiceImageSlider(){
return Container(
height: 250,
padding: EdgeInsets.fromLTRB(0, 0, 20, 0),
child: ListView(
// This next line does the trick.
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
Container(
width: 160.0,
child: _invoiceContextMenu(),
),
],
),
);
}
Widget _invoiceContextMenu(){
return Container(
child: CupertinoContextMenu(
child: Container(
child: _invoiceImage(),
),
previewBuilder: (BuildContext context, Animation<double> animation, Widget child) {
return FittedBox(
fit: BoxFit.cover,
child: ClipRRect(
borderRadius: BorderRadius.circular(64.0 * animation.value),
child: Image.asset('assets/invoices/'+_invoiceInfo.filename),
),
);
},
actions: <Widget>[
CupertinoContextMenuAction(
child: Row(
children: <Widget>[
Icon(
Feather.trash_2,
size: 25,
color: Colors.red,
),
SizedBox(width: 10),
Text("Delete")
]
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
);
}
You can do so by centering the whole ContextMenu like this:
Align(
alignment: Alignment.center,
child: CupertinoContextMenu(),
)
Hope this helped. Cheers
I am trying to build a registration screen, the concept that I have designed on adobe XD is that the registration Screen will have the app logo in the top center, a card with approximately 3-4 textfields/areas, a button in the bottom center. Since there will be multiple cards to fill I want a circular page indicator in the center to make it easier for the user to track the remaining data to fill as well as the user wont have to fill a really long list in a single screen.
What I have tried is
A SingleChildScrollView with a column inside it and the column has the first registration form to fill and another column inside it that has the button with the page indicator
A Stack and a pageviewbuilder this gave me the best results in terms of layout but the only issue is that when using the keyboard the widgets will throw a renderFlew overflow
and right now a listview with the form in it and a column that has the button and the page indicator
Things that I need:
the keyboard to not cause an issue with form
the code to be practical and consistent for multiple screen sizes
my latest code
#override
Widget build(BuildContext context) {
List<Widget> registrationForms = [EmailRegistrationForm()];
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: ListView(
children: <Widget>[
Align(alignment: Alignment.center, child: registrationForms[0]),
Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 5),
child: InkWell(
child: Text("Already have an account? Login!"),
),
),
PrimaryStyledButton(text: "Next", onPress: () {}),
CirclePageIndicator(
currentPageNotifier: _currentPageNotifier,
itemCount: registrationForms.length,
selectedDotColor: Theme.of(context).accentColor,
)
],
),
),
],
));
}
what is expected
so this is what ended up working for me, I realized that the list view is kinda useless so the structure became as follows:
SingleChildScrollView that has a sized box (size of the screen) and a column inside the sized box, the SingleChildScrollView is to stop the issue of the keyboard pushing things up as well giving the ability to scroll while filling the data
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 10),
child: landingScreen.getLogoWidget(),
),
Expanded(
child: Align(
alignment: Alignment.center, child: registrationForms[0]),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 5),
child: InkWell(
child: Text(ALREADY_REGISTERED_MSG),
),
),
PrimaryStyledButton(text: NEXT, onPress: () {
}, ),
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: CirclePageIndicator(
currentPageNotifier: _currentPageNotifier,
itemCount: registrationForms.length,
selectedDotColor: Theme.of(context).accentColor,
),
)
],
),
),
],
),
),
));
Try using SingleChildScrollView with expanded widget
#override
Widget build(BuildContext context) {
List<Widget> registrationForms = [EmailRegistrationForm()];
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: SingleChildScrollView(
child: Expanded(
child: Column(
children: <Widget>[
Align(alignment: Alignment.center, child: registrationForms[0]),
Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 5),
child: InkWell(
child: Text("Already have an account? Login!"),
),
),
PrimaryStyledButton(text: "Next", onPress: () {}),
CirclePageIndicator(
currentPageNotifier: _currentPageNotifier,
itemCount: registrationForms.length,
selectedDotColor: Theme.of(context).accentColor,
)
],
),
),
],
),
),
),
);
}
I am using the below code, where I have a ListView that had a switch.
I want to implement something like when I click on the RaisedButton - it will reload the ListView and all the values of switch.value should be changed to either true or false.
The user can either change the value of the switch from items in the ListView or from the button click.
I do not have an idea on how I should change the value or all the switches in the ListView.
return Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width / 2,
height: 100,
padding: EdgeInsets.all(20),
child: RaisedButton(
onPressed: () {
},
child: Text(
BTN_START_TRIP,
style: new TextStyle(
fontSize: 20.0,
),
),
textColor: buttonFontColor,
color: buttonColor,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(15.0))
),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(3.0),
// Let the ListView know how many items it needs to build.
itemCount: snapshot.data.results.length,
// Provide a builder function. This is where the magic happens.
// Convert each item into a widget based on the type of item it is.
itemBuilder: (context, index){
return Container(
height: 120,
child: Card(
elevation: 10,
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
print(snapshot.data.results[index].original_title);
},
child: Container(
height: 120,
child: Row(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 0, 5, 0),
width: MediaQuery.of(context).size.width -90,
child: Align(
alignment: Alignment.topLeft,
child: Text(snapshot.data.results[index].original_title,
textAlign: TextAlign.left,
style: TextStyle(fontSize: defaultTitleFontsize, color: defaultFontColor),
maxLines: 5),
),
),
Container(
padding: EdgeInsets.fromLTRB(20, 0, 5, 0),
child: Align(
alignment: Alignment.topLeft,
child: Text(snapshot.data.results[index].original_language,textAlign: TextAlign.left,style: TextStyle(fontSize: defaultsubTitleFontsize, color: defaultFontColor)),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
child: Switch(
value: false,
onChanged: (value){
setState(() {
print(value);
});
}
),
),
],
),
]
),
),
),
),
);
},
),
)
],
);
You'll need to have a variable to decide if the switch should be on or off. And during a certain event (click of button e.g) set the variable to appropriate value & re-trigger the build (re-painting of the UI) by calling setState. You'll need to have the above logic part of a stateful widget to accomplish that.