In the screen below, I have the following text "By creating an account ...." that I would like to always keep at the bottom of the screen and should never scroll up with the keyboard.
Currently the text is placed in bottom sheet but unfortunately, the bottom sheet does scroll up with the keyboard.
Using resizeToAvoidBottomInset: false in the Scaffold will not help since it will make all screen ignore the keyboard.
Is there any way to keep the text at the bottom of the screen and have it ignore the keyboard?
I was able to find a basic solution to this.
I placed the terms and conditions text in the bottomNavigationBar property of the Scaffold like this.
Scaffold(
bottomNavigationBar: const TermsAndConditionsText(),
....
....
)
The trick is to use the MediaQuery.of(context).viewInsets.bottom
The value of .bottom will be updated whenever the Keyboard shows up.
To achieve what you want
1- Define the resizeToAvoidBottomInset: false in the Scaffold.
2- Wrap your "form" in a Stack widget.
3- Add your Widgets which should stick at the bottom of the screen at the same level of your "form" in an Align or Positioned
Stack(
children: [
child: Column(
... //Form
),
const Align(
alignment: Alignment.bottomCenter,
child: Text("Terms And Conditions"),
)
],
),
4- And now the magic trick : wrap your "form" in a Padding with the viewInsets.bottom value
Stack(
children: [
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Column(
...// Form
),
),
const Align(
alignment: Alignment.bottomCenter,
child: Text("Terms and Conditions"),
)
],
),
My solution looks more like a "hack" than a proper solution, but I never found any official documentation solving this kind of "problem".
Related
i have broadcast screen ( in full screen) . i have textField on the same broadcast screen on the bottom so we have here Stack like following
Scaffold(
body: Stack(
alignment: Alignment.bottomCenter,
children:[
broadCastScreen()
TextField()
]
)
)
so my layout looks like this
now when i tap on the text field all scaffold resize its self because of the keyboard show up
the good point in this part that my textfieldalways smoothly move to be up the keyboard visible
but the bad part that my broadcast screen resize its self inappropriately for the user experience
so i decide to prevent that annoying party with set resizeToAvoidBottomInset to false
well now everything sound good , but i noticed that my keyboard covering my text field
so How Can i use resizeToAvoidBottomInsetto all my widgets except my textfield part ?
i tried to wrap my textfield with another scaffold with set resizeToAvoidBottomInset to true
and scaffold color to transparent so others widgets be visible and tis work as expected but i completely faced problems with GestureDetector pointers in my first scaffold and thats because my second scaffold stack it
another solution i tried programmatically to set my textfield bottom padding to be the same of my keyboard height using EdgeInsets.fromWindowPadding(WidgetsBinding.instance.window.viewInsets,WidgetsBinding.instance.window.devicePixelRatio);
but that's not perfect way because there is some delay with height keyboard value like 900 millisecond to get the keyboard height Furthermore it i tested it on several difference phones and i got null height with some devices It does not guarantee the measurement of all phones
any other perfect way friend ?
Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
fit: StackFit.expand,
children: [
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Content()
]
Positioned(
bottom: 0,
child:
child: TextFormField(
decoration: InputDecoration(filled: true, fillColor:
Colors.red
),
),
)
],
),
);
Simply Wrap your content in SingleChildScrollView and wrap your TextField in Positioned widget set bottom parameter of Positioned to Zero, add
fit: StackFit.expand,
Note: Don't forget to add above code to your Stack Widget
Let's try to do something like this
Scaffold(
body: Stack(
alignment: Alignment.bottomCenter,
children:[
Positioned.fill(child:
broadCastScreen()),
Position(
bottom:0,
child: TextField())
]
)
)
I have a screen with a graph and some buttons and then some nav buttons...
in portrait, everything fits on the screen, but I want the nav buttons to be at the bottom of the screen, and the graph to be at the top of the screen
in landscape-phone, there's not enough room...
So I put the whole thing into a SingleChildScrollView(child:column(child: [stuff, navbuttons]), but that resulted in everything being close together and centered.
I tried SingleChildScrollView(child:column(child: [stuff, Spacer, navbuttons]), but that makes a RenderFlex children have non-zero flex but incoming height constraints are unbounded error.
What's the way to make a "SpacerBigEnough" class?
I've accomplished similar UI by using a CustomScrollView, like so:
CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
child: Column(
children: [stuff],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: navbuttons,
),
)
],
)
I have this view in my app
and this is the code for it:
return Container(
color: Colors.black,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
...
],
)
],
),
);
But if I click on my form I get stuck and the list of items is hidden by the keyboard, so I'd like to make my Container scrollable.
How can I do?
Instead of wrapping your Column with a ListView try with a SingleChildScrollView instead. You can also try adding a bottom padding equal to keyboard size MediaQuery.of(context).viewInsets.bottom.
I have problem setting the size of my CupertinoNavigationBar manually, and I know you would be able to do it for the appBar using the PreferredSize Widget by doing the following:
appBar: PreferredSize(
preferredSize: Size.fromHeight(60.0),
child: AppBar(
flexibleSpace: Widget(),
)
),
However if you try this for the CupertinoNavigationBar you get an error that states:
'AppBar' is not a subtype of type 'ObstructingPreferredSizeWidget'
Is there any known way that you could set the height of the CupertinoNavigationBar manually?
From digging around a little in the CupertinoNavigationBar it appears the size is predetermined but is also based off of the MediaQuery padding. Now, this is very much a "hack" but it does appear to give you kind of the behavior you're after. The main issue with this is that this solution uses the CupertinoSliverNavigationBar instead of the base one. Which means that as you scroll up the transform target gets placed above the "middle" section in a rather ugly fashion. You could probably figure some way around that. I tried the solution without it being a Sliver and it didn't work properly. I personally think that building your own version of the CupertinoNavigationBar is the simplest way to overcome the static heights the Flutter team implemented. What I've done is used the CompositedTransformFollower/Target widgets and forced the appbar height with the MediaQuery widget. Here's the code:
//outside of build method
final LinkLayer link = LinkLayer();
//within build method
MediaQuery (
data: MediaQuery.of (context).copyWith (
padding: MediaQuery.of (context).padding.copyWith (
top: MediaQuery.of (context).padding.top + 90
)
),
child: Stack(
children: <Widget>[
CustomScrollView(
slivers: <Widget>[
CupertinoSliverNavigationBar (
largeTitle: CompositedTransformTarget(
link: link,
child: SizedBox(
width: 130,
height: 110,
),
),
middle: Text('middle'),
)
],
),
CompositedTransformFollower(
link: link,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
Container(
alignment: Alignment.bottomCenter,
height: 110,
color: Colors.blueGrey,
)
],
),
)
],
),
)
If you choose to copy the CupertinoNavigationBar then the const you'll want to work around is: _kNavBarPersistentHeight.
wrap your child of CupertinoPageScaffold by SafeArea
I can't figure out what's giving this button extra width/padding. The image used is cropped so has no spacing to the left or right and you can see in the attached screenshot from the dev tools that it doesn't occupy the width. Somehow the button has extra width but I don't know where it's coming from.
I have another identical button next to it and with the added space it's causing overflow.
Changing the image size with the width parameter doesn't affect the amount of space the material button takes up either. It seems to be a fixed size.
This is the whole code:
Scaffold(
body: Row(
children: <Widget>[
MaterialButton(
child: Image.asset("images/male.png", width: 33)
)
],
),
);
I also tried other buttons like FlatButton and RaisedButton but they are the same with this additional width/padding. I also tried setting padding with on the button to EdgeInsets.all(0) but that doesn't change anything either.
The extra space is from the minWidth default value which is taken from the current ButtonTheme (you can see that from the MaterialButton source code). You can remove the extra space by adding minWidth to 0 and padding to 0 to your MaterialButton widget. Something like this:
Scaffold(
body: Row(
children: <Widget>[
MaterialButton(
padding: EdgeInsets.all(0),
minWidth: 0,
child: Image.asset("images/male.png", width: 33),
)
],
),
);
Use a container, where you can specify the width
Scaffold(
body: Row(
children: <Widget>[
new Container(
width: 33,
child : MaterialButton(
child: Image.asset("images/male.png")
),
],
),
);