Keyboard hides TextField in a PageView - flutter

I have a quite complex screen with a page view and a FutureBuilder. In the Pagebuilder I also have a TextFormField, when I now click into the text field the keyboard opens like expected. But it then hides the textfield and a button below the text field.
I already searched for solutions, things i tried:
setting resizeToAvoidBottomInset to true
putting the outer column or the pageview into a SingleChildScrollView
adding some padding (in the size of the keyboard) to the bottom
Any other ideas?
I only have ONE Scaffold.

What approach are you using to get the keyboard size? The best approach is to add a bottom padding that pushes the textfield upwards, you might also want to put the form fields inside the SingleChildScrollView that you've mentioned:
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom + 10

Make your page scrollable and add padding to the button like so:
SingleChildScrollView(
child: Column(
children:
textInput,
Padding(padding: ..., child: button)
...
This would allow user to scroll to the button after edit.
Another solution is to make button float - it would always be above keyboard
return Stack(
children: <Widget>[
Positioned(
child: SingleChildScrollView(
child: Column(
children: [textInput]
..add(Container(
height: 1111, // button heigh, so could scroll underlapping area
)))),
),
Positioned(
child: Align(
alignment: Alignment.bottomCenter,
child: button,
),
)
],
);

Have you tried this?
You should wrap your page with SingleChildScrollView so that you get scrolling in the case when your content grows bigger than the device height because of introduction of keyboard.
Soution
1)Use of WidgetsBindingObserver mixin
2)Adding scrollController to SingleChildScrollView
3)Listening the event of presence of keyboard using didChangeMetrics and scrolling as per the need.
class _SignInState extends State<SignIn> with WidgetsBindingObserver{
ScrollController _scrollController = new ScrollController();
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeMetrics() {
_scrollController.jumpTo(200); //as per your need
}
Inside Scaffold widget adding controller to SingleChildScrollView
body: SingleChildScrollView(
controller: _scrollController,
)

Related

AlignParentBottom a widget in SingleChildScrollView flutter

I am trying to align a button at bottom of a scrollable screen. For scrolling I used SingleChildScrollView and inside which I added all the widgets. Now the only issue I face is the button is not sticking at the bottom on scroll. Help would be appreciated.
As you can see in the image, the buy now button and add to cart button aligned at bottom. If we scroll the entire page, the button will not be scrollable, instead it will be sticking at bottom. I want to implement in this way.
You can use an stack and put All the widgets except button as its First child and then the button as another child of stack. Below it the example code -
class MyNewApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.center,
children:[
Container(
height:MediaQuery.of(context).size.height,
width:MediaQuery.of(context).size.width,
child:SingleChildScrollView(
child: Column(
// Provide Your Widget here
),
),
),
Positioned(
bottom:0,
child:Align(
alignment:Alignment.center,
child: RaisedButton(
child:Text("Button"),
onPressed:(){},
),
),
),
],
),
);
}
}

Any alternative to Expanded widgets using with ListView.builder

I need to design a screen that shows a different widget (selectedWidget) depending on which button is selected. Problem is that the content is dynamic and I have to use ListView.builder for all the APIs. And ListView.builder only works when the Row containing listview is wrapped in Expanded widget. I want to have two buttons just below my ListView, which I'm not able to achieve due to the Expanded widget which covers up the entire Column in which the ListView is present.
The code gives the basic structure which I've been using. selectedWidget is the ListView.builder widget which will be selected according to the FlatButton selected. Also the Column which contains the selectedWidget has dynamic height. It should adjust according to the size of the listview, so I cannot define a fixed height or even a maxHeight. I can only give minHeight here. And the two buttons below my ListView should be right below my ListView and take the width of the Column with flex 3.
I've also tried disabling the scroll for ListView and using SingleChildScrollView, but then my two buttons below the ListView also start scrolling, which I don't want. I need them to be static on the screen and only the ListView should scroll.
I need a solution for the above problem. I need a workaround for this Expanded widget which doesn't let me align my buttons right below my listview and gives white space. Please share if there is any alternative to ListView.builder because I don't think I can use ListView.builder without the Expanded widget. I've tried every possible structure with ListView and Expanded widget.
class MyScreen extends StatefulWidget {
#override
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
#override
Widget build(BuildContext context) {
return Column(
children:[
Expanded(
child: Row(
Expanded(flex: 2,
child: Column(
children: [
FlatButton(),
FlatButton(),
FlatButton(),
FlatButton(),
]
)
),
Expanded(flex: 3,
child: Column(
children: [
Expanded(selectedWidget),
Row(children: [FlatButton(), FlatButton()], )
]
)
),
)
)
],);
}
}
Maybe you can use Flexible and set shrinkWrap: true, inside ListView. The following 2 buttons may not need Expand widget after that.
child: Column(
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) => Text(index.toString()),
itemCount: 6,
),
),
Row(
... // 2 Buttons

Flutter side nav animation

I was trying to build to build slack mobile app like side nav where we can swipe right to reveal the drawer and also the main body moves right as drawer opens.
Layout:
Stack
-Drawer()
-Homepage()
On the hamburger icon click, I am using animated position to shift the HomePage() and reveal the drawer.
But how can I implement something like the pageview thing, where first child would be Drawer and second child would be Homepage and I can right to reveal the drawer, but the drawer's width will be only 0.5* viewportfraction so the homepage is also revealed and dimmed.
i faced the same problem and i used Stack to solve it, look at
the example:
Stack(
children: <Widget>[
buildPartnerList(context),
FilterDrawer(),
],
),
in the FilterDrawer i returned one animationBuilder
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, widget) => buildFilterDrawer(context, widget),
);
}
the buildFilterDrawer its something like this
Container(
color: Theme.of(context).accentColor,
width: widthAnimation.value,
child: Stack(
children: <Widget>[
...
and to make the animation, i have one GestureDetector, when clicked animate my side Bar
_moveFliterDrawerAnimation() {
setState(() {
_isExpanded
? _animationController.reverse()
: _animationController.forward();
_isExpanded = !_isExpanded;
});
}

How to keep the screen in a fixed position when the keyboard is opened in Flutter?

In my log in screen attached below, I want the view to stay fixed even when I open the keyboard.
If you see the screenshot of how my screen currently behaves, you can notice that it gets scrolled up(pay attention to the Logo TextField) when the keyboard is opened.
I am currently using SingleChildScrollView to avoid overflow, but even if i do not use a SingleChildScrollView, the screen still repositions after opening the keyboard, only this time, with a pixel overflow.
class LoginScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: <Widget>[
_logo(),
LoginForm(),
],
),
),
);
}
}
How can I keep the original positioning of the screen(as shown in the screenshot on the left) even when the keyboard is opened?
Edit: Already tried resizeToAvoidBottomInset, it still scrolls.
In your Scaffold, try putting resizeToAvoidBottomInset property to "false".
You can wrap your content in a Scaffold then set the property resizeToAvoidBottomInset to false so it will not resize your content when the device's Keyboard is shown. I've updated your code so you can use it.
class LoginScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: <Widget>[
_logo(),
LoginForm(),
],
),
),
)
);
}
}

How to align widget to another widget in Flutter?

I have a RaisedButton widget inside of a Center widget as one of the widgets in a Column of widgets. I want to add a CircularProgressIndicator to the right side of this button and show it when the button is pressed. Yet I want to leave the button centred when the progress bar is shown. In other words I want the button always be in the center and the progress bar aligned to this button.
I tried to use a Row here but this pushes the button and it becomes not centred any more.
EDIT1: Looking at the result of the solution provided by #Anil Chauhan (thanks for the answer):
Like I said before that I tried to use Row like he did, the problem is that in this case the button is not in the centred in the screen and is pushed by the progress bar. And I need it to stay in the middle of it's row.
EDIT2: #Anil Chauhan edited answer now works for a specific case in which the button is predetermined size. But if the size of the button is changed based on the language of the text (in apps that have several languages) this solution will not work.
This is the reason the question I asked is: "How to align widget to another widget". Because if I could that I don't have to worry about the button text size any more.
What would be the right way to handle this in Flutter?
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
bool _showIndicator = false;
void _onButtonClicked() {
setState(() {
_showIndicator = !_showIndicator;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
children: <Widget>[
const Expanded(child: SizedBox()),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: RaisedButton(
child: Text("I am Too Big"),
onPressed: _onButtonClicked,
),
),
Expanded(
child: _showIndicator
? const Align(
alignment: Alignment.centerLeft,
child: CircularProgressIndicator(),
)
: const SizedBox(),
),
],
),
),
);
}
}
Here is my explanation:
The RaisedButton size is depends on its child. If you add it to Row it will automatically align to left(or start).
Expanded widget will fill the remaining space in Flex widget(Row & Column are child classes of Flex). If you add more than one Expanded widgets, it will split equally. So I added two Expanded to both the side of button to make it center.
Now We should give child for Expanded Widget.
For the first one(left) we don't have anything to display so I added SizedBox.
For the second one(right) we need CircularProgressIndicator. so I added it.
The Expanded widget will try to make its child to fill the space inside of it. So the CircularProgressIndicator will become Ellipse shaped. We can avoid this by using Align Widget.
Try this:
Updated:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyAppOne(),
);
}
}
class MyAppOne extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyAppOne>{
bool show = false;
#override
Widget build(BuildContext context){
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
alignment: Alignment.center,
child: RaisedButton(
onPressed: () {
setState(() {
show =!show;
});
},
child: Text('Show'),
),
),
Positioned(
right: MediaQuery.of(context).size.width * .20,
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(10.0),
child: show ? CircularProgressIndicator() : Container(),
),
)
],
)
);
}
}
Flutter's Column and Row widgets have two convenient properties called mainAxisAlignment and crossAxisAlignment. I assume since you're using a Column and want the CircularProgressIndicator to the right of the button, you might be want to use crossAxisAlignment since the cross-axis of a Column is along the horizontal.
If possible, please share your code for better understanding and support of the issue.