I want to make it so that the elements in the to-do list do not get scrolled out of the screen when the soft keyboard is shown. Using SingleChildScrollView on the Scaffold body and doing nothing else causes the whole body to be scrolled up so that the TextField is visible.
The TaskList itself is a container that has a ListView.builder as a child by the way.
final usableHeight = MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top;
return Scaffold(
appBar: appBar,
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: usableHeight * 0.9,
child: TaskList(_userTasks),
),
Container(
height: usableHeight * 0.1,
child: NewTask(_addNewTask),
),
],
),
),
);
I tried changing the task list container height to this, to account for the size of the keyboard when it's visible:
Container(
height: (usableHeight - MediaQuery.of(context).viewInsets.bottom) * 0.9,
child: TaskList(_userTasks),
),
And that almost solved the problem but there's still a tiny bit of scrolling that hides part of the first task, and I don't know what's causing it.
How should I fix this? I'm okay to completely changing my layout logic.
You can simply remove the SingleChildScrollView then pass your widget for adding task to the floatingactionbutton property of scaffold.
final usableHeight = MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top;
return Scaffold(
appBar: appBar,
body:
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: usableHeight * 0.9,
child: TaskList(_userTasks),
),
Container(
height: usableHeight * 0.1,
child: NewTask(_addNewTask),
),
],
),
floatingactionbutton : New task()
);
There is also a floatingactionbuttonstyle property which you can use to style alignment and all of floatingactionbutton widget
Hope it work for you
I think you should probably use a Stack here, and position the new task view in the bottom. If you have a lot of tasks, they will then also scroll behind the card (you might want to add a container or sizedbox at the bottom of the list so you can always still see the last item.
body: Stack(
children: [
// the list of tasks, just put the ListView directly (or wrap it in an Expanded)
TaskList(...),
// position the add task
// it will automatically adjust when the keyboard appears
Positioned(
child: Newtask(...),
bottom: 0.0,
),
],
),
https://api.flutter.dev/flutter/widgets/Positioned-class.html
Related
I have this design, The first section in the red box is fixed height size, and The second section is the dynamic height (ListviewBuilder) which changed the content based on the tabBar.
My question is How can I use the TabBar view inside the scrollable widget (custom scroll view/listview etc..)
the solution That I currently found is to use a customScrollView and use SliverFillRemaining like that
SliverFillRemaining(
child: TabBarView(
children: [],
),
),
but that adds extra white space at the bottom of the list and I can't remove it by
making hasScrollBody property false
You could probably achieve what you want with this kind of template :
Scaffold(
body: Column(
children: [
Container(
height: MediaQuery.of(context).size.height * .33,
child: Container(/* Content of the first section */),
),
Expanded(
child: DefaultTabController(
length: 2,
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
height: 50,
child: TabBar(
tabs: [Text("Guest"), Text("Service")],
),
),
),
SliverFillRemaining(
child: TabBarView(
children: [
// Your ListView Builder here
],
),
),
],
),
),
),
],
),
);
Seeing the bit of code you posted, it is probably close to what you already have but after test it doesn't adds extra white space at the bottom.
If it continue to display the same behavior, adding a little more context could help us provide a more accurate answer.
I have 2 widget in stack. One of them is aligned in center. And the widget which is on the top is other stack. And I want show second widget with first widget's top and left position. Here is the explain:
The yellow area is my stack. And first widget is setted like Center(child: myFirstWidget). My second widget is referenced from here it's a resizable widget so it's an another stack and it's childs are "positioned". So I need to set top and left value for initialize. But my main stack filled page So when I set my second widget's top and left to 0. It's shown as below.
But I want to show align it to centered child's top like:
My code snip:
child: Container(
color: Colors.red,
child: Stack(
children: [
Center(
child: Image.file(
File("myfilepath"),
),
),
ResizableWidget(
child: Container(
color: Colors.blue,
),
),
],
),
),
You can adjust the position of the widgets with the Position widget like this:
Positioned(
child: ResizableWidget(
child: Container(
color: Colors.blue,
),
),
top: 80,
right: -5,
),
The value of top and right are just random values, you should check what works for you!
You should make Center the parent of the Stack.
The Stack will be positioned at the center of its parent because of Center, it will get the dimensions of its biggest childs (height and width) and will position other childs according to the alignment value.
Edit : I modified the code to include a placeHolder image. Here I gave it a 6000x2000 size but you can change it to whatever value you want. Code is working as expected, see capture below.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Stack(
alignment: AlignmentDirectional.topStart,
children: [
Image.network('https://via.placeholder.com/6000x2000'),
SizedBox(
height: 50,
width: 50,
child: Container(
color: Colors.green,
))
],
),
),
);
}
I am trying to build a widget like https://imgur.com/a/KRKj4SW which is an item of listview.builder.
The widget tree is like this:
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Divider(),
Container(
height: 100,
width: screenWidth,
child: Stack(
children: [
Positioned(
left: 45,
child: Row(
children: [
// circular button widget
Expanded(
child: Column(
// text title widget
//text subtitle widget
// text duration widget
// progress duration widget
),
)
],
),
),
//rotated day widget
Positioned(
left: 0,
top: 10,
child: Transform.rotate(
angle: -pi / 2,
child: Text('day'),
))
],
),
)
],
);
The problem is that if I remove the height=100 of parent of stack, error occurs and nothing is rendered in the entire screen.This error is so bad that hot reload/restart does not work afterwards. I do not want to provide static height because the texts and other widgets in column are conditionally rendered and giving static height would sometimes leave massive space at bottom or not enough space to render widget in the stack.
I am using Stack here because the Transform.rotate widget would occupy same horizontal space as if it was not rotated and the space between rotated test and circular button would be large.
What is the best way to build a "nested bottom sheet" which behaves like this:
https://dribbble.com/shots/14139422-Mobile-banking-app-interactions?
Do I have to use NestedScrollView or CustomScrollView, or a completely different approach?
Update :
This is my result using SlidingUpPanel, but I still have two problems:
When sliding up the panel, the green and red containers stay behind the panel and do not scroll out of view at the top.
In landscape mode the containers are higher than the device, so this approach does not work. I need the panel to be attached to the bottom of the containers, so it is only visible when scrolling down.
Code:
SafeArea(
child: Scaffold(
body: SlidingUpPanel(
minHeight: MediaQuery.of(context).size.height - 479,
maxHeight: MediaQuery.of(context).size.height - 79,
panel: SingleChildScrollView(
child: Column(
children: [Text('Sliding Panel')],
),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 100,
color: Colors.green,
),
Container(
height: 300,
color: Colors.red,
)
],
),
),
),
),
);
Result:
I believe there is a Widget for what you want to do, since there is a widget for everything in Flutter. here is the link of the package
NOTE : you can also set minimum height of the widget when collapsed in order to control how much of the widget you can show when it is collapsed.
And here is the demo :
TL;DR Need the container to fill the vertical space so that it can act as a ontap listener. Have tried most solutions but nothing seems to work.
So what I am trying to do is to make my container fill up the vertical space while still having a fixed width. Two first is what I have and third is what I want. The idea is to have the container transparent with a gesture ontap listener. If anyone have a better idea as for a different solution, feel free to suggest.
Widget build(BuildContext context) {
return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _handleDragEnd,
child: new Stack(
children: <Widget>[
new Positioned.fill(
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Container(
child: new IconButton(
padding: new EdgeInsets.only(top: 16.0, bottom: 16.0, left: 24.0, right: 24.0),
icon: new Icon(Icons.warning),
color: Colors.black12,
onPressed: () {},
)
),
],
),
),
new SlideTransition(
position: new Tween<Offset>(
begin: Offset(0.0, 0.0),
end: const Offset(-0.6, 0.0),
).animate(_animation),
child: new Card(
child: new Row(
children: <Widget>[
new Container(
width: 20.0,
height: 20.0,
color: Colors.amber,
),
new Expanded(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getListTile(),
_ifStoplineIsToBeShown()
],
),
)
],
)
),
),
],
)
);
}
I am quite sure that i have been missing something considering the fact that I have tried a lot of different things and nothing seems to work.
I have also uploaded an image with the debug painting here.
PS. I know I have set the height to a fixed value, but this is the only way to show the container.
The trick is to combine an IntrinsicHeight widget and a Row with crossAxisAlignment: CrossAxisAlignment.stretch
This force the children of Row to expand vertically, but Row will take the least amount of vertical space possible.
Card(
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: 20.0,
color: Colors.amber,
),
// Expanded(...)
],
),
)
)
To stretch the container to full height of the parent use property constraints:BoxConstraints.expand() in container widget. Container occupy the complete space independent of the of child widget
Container(
color: Colors.green,
child: Text("Flutter"),
constraints: BoxConstraints.expand(),
)
Please refer the link Container Cheat sheet for more about container
Simply pass in: double.infinity.
If you want a Container to fill all available space, you can just pass in:
width: double.infinity,
height: double.infinity
Explanation:
In Flutter, a child widget cannot exceed the "layout constraints" imposed by its parent widget. During the layout phase, Flutter engine uses a constraint solver to automatically correct "out-of-bound" values into what's allowed by its parent constraints.
For example, if you have a Container that's 50x50, and for its child, you pass in another Container that's 300x300, the inner container will be automatically corrected to "not exceed its parent", thus 50x50. Therefore, using sufficiently large values would always make sure you "fill parent".
In fact, even BoxConstraints.expand() exploits the same idea internally. If you open up the source code of expand(), you will see:
/// Creates box constraints that expand to fill another box constraints.
///
/// If width or height is given, the constraints will require exactly the
/// given value in the given dimension.
const BoxConstraints.expand({
double width,
double height,
}) : minWidth = width ?? double.infinity,
maxWidth = width ?? double.infinity,
minHeight = height ?? double.infinity,
maxHeight = height ?? double.infinity;
So if you are absolutely certain you want to fill all spaces, you can intuitively pass in a number bigger than the parent (or larger than the whole screen), like double.infinity.
As of Jan 2020 the simplest is to use an Expanded Widget
Expanded(flex: 1,
child: Container(..),
),
https://api.flutter.dev/flutter/widgets/Expanded-class.html
There are many answers which suggest using two things
constraints: BoxConstraints.expand(),
height: double.infinity,
But both these answer will give you an error like
BoxConstraints forces an infinite height.
We can avoid these by calculating the height of the screen like
App Bar
Top Bar Space(Exist on the above App Bar)
Remaining screen
1. Get the MediaQuery
final mediaQuery = MediaQuery.of(context);
2. Declare the AppBar Widget and same App Bar instance should be used in Scaffold App Bar
final PreferredSizeWidget appBar = AppBar(
title: Text('Home'),
);
3. Use calculated height
Container(
width: mediaQuery.size.width,
height: (mediaQuery.size.height -
appBar.preferredSize.height -
mediaQuery.padding.top),
color: Colors.red,
),
Output:
Set the height or width of a container to double.maxFinite
Container(
height: double.maxFinite,
width: 100,)
You can make your widget take the full size of a Container widget, and then set the container's height and/or width to double.maxFinite. This will make the Container take the height and/or width or its parent widget
I propose using Expanded widget (which allows us to avoid IntrinsicHeight widget), combine it with the Container's alignment property and therefore make it work properly even if the Container is not the only one at the screen.
Expanded(
child: Container(
alignment: Alignment.center,
child: Text('Your text', textAlign: TextAlign.center))),
That way one also avoids potential app's crash which occurs often when you accidentally expand to infinity some parts of the widget tree both horizontally and vertically (that is why you are not able to use BoxConstraints widget in many cases).
One can read more about the problems of passing constraints in Flutter here - a must read: https://medium.com/flutter-community/flutter-the-advanced-layout-rule-even-beginners-must-know-edc9516d1a2
This work works for me
height: MediaQuery.of(context).size.height,