Related
I am trying to put a Two Textfields on a row so that they align in one row but i seem to be getting the below error,i cant seem to get what i am doing wrong here.Help apreciated.
import "package:flutter/material.dart";
void main(){
runApp(
MaterialApp(
title: 'Planet',
home:Home()
)
);
}
class Home extends StatefulWidget{
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return HomeState();
}
}
class HomeState extends State<Home>{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text(
'Weight on Planet x',
),
centerTitle: true,
),
body:Container(
alignment: Alignment.topCenter,
child: ListView(
padding: const EdgeInsets.all(2.5),
children: <Widget>[
Image.asset('images/planet.png',height: 133.0,width: 200.0,),
Container(
margin: const EdgeInsets.all(3.0),
child: Row(
children: <Widget>[
TextField(
controller: null,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Your weight on Earth',
hintText: 'In Pounds',
icon: Icon(Icons.person_outline)
),
),
TextField(
controller: null,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Your weight on Earth',
hintText: 'In Pounds',
icon: Icon(Icons.person_outline)
),
)
],
),
)
],
),
)
);
}
I get the following error
Another exception was thrown: RenderBox was not laid out: _RenderDecoration#3373c relayoutBoundary=up10 NEEDS-PAINT
Try giving some finite width to the TextField parent Container. By default TextFields occupy the entire space made available by their parent which is in this case infinite.
Or, you can use individual Containers for each TextField if you want them to have custom widths.
I propose you to use Expanded to inform the horizontal size (maximum available).
Expanded(
child: Row(
children: <Widget>[
TextField(
controller: null,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Your weight on Earth',
hintText: 'In Pounds',
icon: Icon(Icons.person_outline)),
),
TextField(
controller: null,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Your weight on Earth',
hintText: 'In Pounds',
icon: Icon(Icons.person_outline)),
)
],
),
);
here in below code i have list of widgets and used in listview iam adding widgets with list.add()in setstate also the list not updating i dont know what's happening . why my list is not updating
Here is below code
class EditorPageState extends State<EditorPage> {
List<Widget> obj = List<Widget>();
GlobalKey formkey= GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
obj.add( TextFormField(
textCapitalization: TextCapitalization.sentences,
maxLength: 50,
decoration: InputDecoration(
labelText: "TITLE",
hintText: "UR ARTICLE NAME"
),
));
obj.add(TextFormField(decoration: InputDecoration(
labelText: "Article's Propic",
hintText: "Only image Url is Accepted"
),));
return Scaffold(
appBar: AppBar(title: Text("data"),),
body: Form(
key: formkey,
child:Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 50),
child: ListView(
shrinkWrap: true,
children: obj
),
),
Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(),
Container(
alignment: Alignment.bottomCenter,
height: 50,width: MediaQuery.of(context).size.width,
color: Colors.black38,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.format_bold),color: Colors.white,onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "heading"
),
));
});
},),
IconButton(icon: Icon(Icons.add),
onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "Start again here"
),
));
});
}
),
IconButton(icon: Icon(Icons.add_a_photo),
onPressed: (){
}
),
IconButton(icon: Icon(Icons.delete),
onPressed: (){
},
)
],
),
),
],
),
),
],
),
),
);
}
}
the above code is of statefulwidget ad it is fullscreen dialog
thats it can i know why my list is not updated
Well you will need implement a ListViewBuilder to do this and please, split your layout creation your build method isn't readable. I make some changes in your layout to be more readable and the source code has some comments to help you get what I changed. I hope it can help and also you can adapt this code to your needs.
class EditorPageState extends State<EditorPage> {
List<Widget> obj = List<Widget>();
GlobalKey formkey= GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
obj.add( TextFormField(
textCapitalization: TextCapitalization.sentences,
maxLength: 50,
decoration: InputDecoration(
labelText: "TITLE",
hintText: "UR ARTICLE NAME"
),
));
obj.add(TextFormField(decoration: InputDecoration(
labelText: "Article's Propic",
hintText: "Only image Url is Accepted"
),));
return Scaffold(
appBar: AppBar(title: Text("data"),),
//you can use this property to easily create a bottom navigation
bottomNavigationBar: _buildBottomNavigator(), // this method return BottomNavigation layout
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Form(
key: formkey,
/// here your question answer... you need implemet a listView builder
/// in every build this will create a new ListView getting itens of a especific list
child : ListView.builder(
itemCount: obj.length, // number of items in your list
//here the implementation of itemBuilder. take a look at flutter docs to see details
itemBuilder: (BuildContext context, int Itemindex){
return obj[Itemindex]; // return your widget
}),
),
),
);
}
//create your bottom navigation layout
Widget _buildBottomNavigator(){
return Container(
color: Colors.black54,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.format_bold),color: Colors.white,onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "heading"
),
));
});
},),
IconButton(icon: Icon(Icons.add),
onPressed: (){
print("on pressed");
setState(() {
obj.add( TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "Start again here"
),
));
});
}
),
IconButton(icon: Icon(Icons.add_a_photo),
onPressed: (){
}
),
IconButton(icon: Icon(Icons.delete),
onPressed: (){
},
)
],
),
);
}
I am trying to add done button in number type input for a TextFormField in flutter but I could not able to do that.
TextFormField(
key: Key(keyValue),
initialValue: valueBuilder,
onSaved: (text) {
fieldsController.text = text.trim();
},
inputFormatters: [inputFormatters],
keyboardType: TextInputType.phoneNumber,)
I want create a keyboard like the below. For the input text form field.
Change
keyboardType: TextInputType.number
to
keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true)
You don't need a done button just wrap MaterialApp with a GestureDetector
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
}
},
child: MaterialApp(
title: "My title",
home:MyHomeScreen(),
),
);
I've just created a package for add basic actions to the current keyboards .
You can take a look here :
https://pub.dartlang.org/packages/keyboard_actions
Usage :
import 'package:flutter/material.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
//...
FocusNode _nodeText1 = FocusNode();
FocusNode _nodeText2 = FocusNode();
FocusNode _nodeText3 = FocusNode();
FocusNode _nodeText4 = FocusNode();
FocusNode _nodeText5 = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Keyboard Actions Sample"),
),
body: FormKeyboardActions(
keyboardActionsPlatform: KeyboardActionsPlatform.ALL, //optional
keyboardBarColor: Colors.grey[200], //optional
nextFocus: true, //optional
actions: [
KeyboardAction(
focusNode: _nodeText1,
),
KeyboardAction(
focusNode: _nodeText2,
closeWidget: IconButton(
icon: Icon(Icons.close),
onPressed: () {},
),
),
KeyboardAction(
focusNode: _nodeText3,
onTapAction: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text("Custom Action"),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () => Navigator.of(context).pop(),
)
],
);
});
},
),
KeyboardAction(
focusNode: _nodeText4,
displayCloseWidget: false,
),
KeyboardAction(
focusNode: _nodeText5,
closeWidget: Padding(
padding: EdgeInsets.all(5.0),
child: Text("CLOSE"),
),
),
],
child: Padding(
padding: const EdgeInsets.all(15.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
keyboardType: TextInputType.number,
focusNode: _nodeText1,
decoration: InputDecoration(
hintText: "Input Number",
),
),
TextField(
keyboardType: TextInputType.text,
focusNode: _nodeText2,
decoration: InputDecoration(
hintText: "Input Text with Custom Close Widget",
),
),
TextField(
keyboardType: TextInputType.number,
focusNode: _nodeText3,
decoration: InputDecoration(
hintText: "Input Number with Custom Action",
),
),
TextField(
keyboardType: TextInputType.text,
focusNode: _nodeText4,
decoration: InputDecoration(
hintText: "Input Text without Close Widget",
),
),
TextField(
keyboardType: TextInputType.number,
focusNode: _nodeText5,
decoration: InputDecoration(
hintText: "Input Number with Custom Close Widget",
),
),
],
),
),
),
),
);
}
add this to your TextField
TextField(
...
keyboardType: TextInputType.numberWithOptions(signed: true),
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
...
),
This is how to add Done button to your TextFormField when keyboard is opened:
textInputAction: TextInputAction.done,
Please keep in mind that iOS doesn’t support Done on NUMERIC keyboards.
I used this way to handle done button in IOS
keyboardType: Platform.isIOS?
TextInputType.numberWithOptions(signed: true, decimal: true)
: TextInputType.number,
// This regex for only amount (price). you can create your own regex based on your requirement
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,4}'))],
There is no done button in ios keyboard. Solution is that use "keyboard_actions" plugin otherwise add layout top of keyboard check this
https://blog.usejournal.com/keyboard-done-button-ux-in-flutter-ios-app-3b29ad46bacc
I used the signed option to display the done button. Then I used a TextInputFormatter with a RegEx to limit what the user can input.
new TextFormField(
controller: myController,
keyboardType: TextInputType.numberWithOptions(signed:true, decimal: true),
textInputAction: TextInputAction.done,
onFieldSubmitted: (term) {
_showSnackBar(context, double.parse(myController.text));
},
onEditingComplete: () {
_showSnackBar(context, double.parse(myController.text));
},
decoration: const InputDecoration(
helperText: "Actual",
hintText: "Units used",
border: UnderlineInputBorder(),
icon: Icon(Icons.keyboard),
),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*$')),
],
),
There is no done button in iOS but we can check the length of the input and clear focus to hide the numberpad keyboard.
Implement like below,(it'll work with fix length of number value)
onChanged: (val) {
if (val.length == 10) { //10 is the length of the phone number you're allowing
FocusScope.of(context).requestFocus(FocusNode());
}
}
I'm using TextInputType.number in my TextField. But there is not any done or next button inside keyboard.TextInputAction.done isn’t working on number keyboard. What should I do for that ?
I've just created a package for add basic actions to the current keyboards .
You can take a look here :
https://pub.dartlang.org/packages/keyboard_actions
Sample code:
import 'package:flutter/material.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
//...
FocusNode _nodeText1 = FocusNode();
FocusNode _nodeText2 = FocusNode();
FocusNode _nodeText3 = FocusNode();
FocusNode _nodeText4 = FocusNode();
FocusNode _nodeText5 = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Keyboard Actions Sample"),
),
body: FormKeyboardActions(
keyboardActionsPlatform: KeyboardActionsPlatform.ALL, //optional
keyboardBarColor: Colors.grey, //optional
nextFocus: true, //optional
actions: [
KeyboardAction(
focusNode: _nodeText1,
),
KeyboardAction(
focusNode: _nodeText2,
closeWidget: IconButton(
icon: Icon(Icons.close),
onPressed: () {},
),
),
KeyboardAction(
focusNode: _nodeText3,
onTapAction: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text("Custom Action"),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () => Navigator.of(context).pop(),
)
],
);
});
},
),
KeyboardAction(
focusNode: _nodeText4,
displayCloseWidget: false,
),
KeyboardAction(
focusNode: _nodeText5,
closeWidget: Padding(
padding: EdgeInsets.all(5.0),
child: Text("CLOSE"),
),
),
],
child: Padding(
padding: const EdgeInsets.all(15.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
keyboardType: TextInputType.number,
focusNode: _nodeText1,
decoration: InputDecoration(
hintText: "Input Number",
),
),
TextField(
keyboardType: TextInputType.text,
focusNode: _nodeText2,
decoration: InputDecoration(
hintText: "Input Text with Custom Close Widget",
),
),
TextField(
keyboardType: TextInputType.number,
focusNode: _nodeText3,
decoration: InputDecoration(
hintText: "Input Number with Custom Action",
),
),
TextField(
keyboardType: TextInputType.text,
focusNode: _nodeText4,
decoration: InputDecoration(
hintText: "Input Text without Close Widget",
),
),
TextField(
keyboardType: TextInputType.number,
focusNode: _nodeText5,
decoration: InputDecoration(
hintText: "Input Number with Custom Close Widget",
),
),
],
),
),
),
),
);
}
When i select a Textfield, the keyboard is going to be shown but the keyboard hide my selected TextField. Does someone have a solution?
Scaffold(
resizeToAvoidBottomInset: true,
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
)
],
),
),
)
);
// resizeToAvoidBottomPadding: false isDeprecated
use resizeToAvoidBottomInset: true.
Compose an animation and move your TextField container up when a TextField gets focus.
For learning about composing animations refer to:
Composing Animations and Chaining Animations in Dart's Flutter Framework
Use Flutter's FocusNode to detect the focus on a TextField
Edit:
Here I've written an example that does exactly what you want:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Animation Demo',
theme: new ThemeData(
primaryColor: new Color(0xFFFF0000),
),
home: new FormDemo(),
);
}
}
class FormDemo extends StatefulWidget {
#override
_FormDemoState createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemo> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
FocusNode _focusNode = FocusNode();
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_animation = Tween(begin: 300.0, end: 50.0).animate(_controller)
..addListener(() {
setState(() {});
});
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
_controller.forward();
} else {
_controller.reverse();
}
});
}
#override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false, // this avoids the overflow error
appBar: AppBar(
title: Text('TextField Animation Demo'),
),
body: new InkWell( // to dismiss the keyboard when the user tabs out of the TextField
splashColor: Colors.transparent,
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
SizedBox(height: _animation.value),
TextFormField(
decoration: InputDecoration(
labelText: 'I move!',
),
focusNode: _focusNode,
)
],
),
),
),
);
}
}
Just cut and paste your body code in this -
SingleChildScrollView(
child: Stack(
children: <Widget>[
// your body code
],
),
),
A pretty short way to realize this is by simply using a MediaQuery for getting the bottom view insets. This would look as follows:
...
return Column(
children: <Widget>[
TextField(
decoration: InputDecoration.collapsed(hintText: "Start typing ..."),
controller: _chatController,
),
SizedBox(
height: MediaQuery.of(context).viewInsets.bottom,
),
],
);
...
Hope it helps!
In my case I had to combine answer given by #Javid Noutash which uses AnimationController along with scrollPadding property of TextFormField.
code:
Add this line in build method
double bottomInsets = MediaQuery.of(context).viewInsets.bottom;
Add scrollPadding property
return ListView(
children:[
...widgets,
Container(
margin:EdgeInsets.only(
top:1.0,
left:1.0,
right:1.0,
bottom:_focusNode.hasFocus && bottomInsets != 0?
_animation.value : 1.0),
child:TextFormField(
decoration: InputDecoration(
labelText: 'I move!',
),
focusNode: _focusNode,
scrollPadding: EdgeInsets.only(bottom:bottomInsets + 40.0),
),
),
]
);
Note: Combine this code with #Javid Noutash's code
I had the same problem where the parent widget is Material and the other widgets are inside a ListView. The problem was fixed when I changed the parent widget to Scaffold without any extra code and the TextField, TextFormField in my case, is being showed above the Keyboard automatically. So, if you encountered this problem just make sure to have Scaffold as the main widget.
The most simple way is to just wrap it with
SingleChildScrollView( ... )
When the textfield is on the page bottom and the keyboard appears, the textfield is automatically scrolled up. Then the text may be entered right above the keyboard.
My way here
Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/Bg img.png'), fit: BoxFit.fill)),
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
.............
This template has some advantages:
Move content up when the keyboard appears
Column using spaceBetween inside a scroll view
Background is sticked phone scren and never change event the keyboard ups
Wrap your widget into Padding and set padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
<activity
android:name="..ActivityName"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"/>
only for android
if you use FlutterFragment add configChanges and windowSoftInputMode for the Activity.
another way
add your TextField to a ListView
ListView(
children: <Widget>[
TextField(),
TextField(),
]
)
The above does not work if you have a CustomScrollview in a NestedScrollView.
First, you need to give the TextField a focusNode.
TextField(focusNode:_focusNode(),
...);
Use NestedScrollViewState to get access to the innerScrollController of the NestedScrollView. You can view the example here on how to get the innerScrollController. Declare a globalKey and assign it to NestedScrollView.
body: NestedScrollView(
key: globalKey,
...)
Setup the focusNode Listener to listen for when the textfield has been activated and animate the innerScrollController accordingly.
void initState() {
super.initState();
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
double innerOffSet = globalKey.currentState.innerController.offset;
if(innerOffSet < 100)
globalKey.currentState.innerController.jumpTo(innerOffSet+100);
}
});
}
var _contentController;
void _settingModalBottomSheet(BuildContext context, String initialText) {
_contentController = new TextEditingController(text: initialText);
showModalBottomSheet(
context: context,
isDismissible: true,
builder: (BuildContext bc) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: 40,
margin: EdgeInsets.only(left: 4, right: 4, bottom: 8),
decoration: BoxDecoration(
color: AppColor.bgTextFieldComment,
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 24),
child: TextField(
focusNode: _contentFocusNode,
autofocus: true,
controller: _contentController,
decoration: InputDecoration(
hintText: 'Enter Content',
border: InputBorder.none,
fillColor: AppColor.bgTextFieldComment,
),
keyboardType: TextInputType.multiline,
maxLines: null,
style: TextStyle(
color: Colors.black87,
fontSize: 16,
fontStyle: FontStyle.normal,
),
)),
),
InkWell(
child: Padding(
padding: EdgeInsets.only(left: 4, right: 4),
child: Icon(
Icons.send,
color: Colors.blue,
),
),
onTap: () {
// do ON TAP
},
),
],
),
),
SizedBox(
height: MediaQuery.of(bc).viewInsets.bottom,
),
],
);
},).then((value) {
print('Exit Modal');
});
print('request focus');
_contentFocusNode.requestFocus();
}
Instead of TextField, use TextFormField and wrap the widget with a list of TextFormField to Form:
Form(
child: Column(
children: <Widget> [
TextFormField(),
TextFormField(),
...
TextFormField(),
]
)
)
you can easily try to use Flexible widget just wrap your widget with it
Flexible(
child: Image(
image :
AssetImage('assets/logo.png'),
),
),
I had a very complex widget with Stack, Column and Single ChildChildScrollView, and I fixed it by adding a padding to the SCSV like this:
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: SingleChildScrollView(
child: Column(
children: [... a lot of children here, one of them is a TextField],
),
),
),
// a widget at the bottom of the stack that shows despite the size of the scrollable column
],
),
It's very easy in my case check out code
Column(
children: [
Expanded(
child:// Top View,
),
postSend // edittext. and button
],
)