How to make flutter TextField at bottom of screen show over IME - flutter

My page is a SingleChildScrollView,it's has a column as child .And I have a TextField at bottom of the screen.
How can I make the TextField show over of IME when IME is expend.
now the TextField is covered by IME. And it is invisible,util scroll manually.
demo code
import 'package:flutter/material.dart';
class Demo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
elevation: 0.0,
title: new Text(
'title',
),
),
body: new Home(),
),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new SingleChildScrollView(
child: new Column(
children: <Widget>[
new ImageZone(),
new Div(),
new TextEditZone(),
new Div(),
],
),
);
}
}
class ImageZone extends StatefulWidget {
#override
State<StatefulWidget> createState() => new ImageZoneState();
}
class ImageZoneState extends State<ImageZone> {
#override
Widget build(BuildContext context) {
return new Material(
elevation: 1.0,
color: Colors.white,
child: new Container(
height: 380.0,
width: double.infinity,
child: new Icon(
Icons.access_time,
size: 360.0,
),
),
);
}
}
class Div extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new SizedBox(
height: 12.0,
);
}
}
class TextEditZone extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new TextEditZoneState();
}
}
class TextEditZoneState extends State<TextEditZone> {
#override
Widget build(BuildContext context) {
return new Material(
elevation: 1.0,
child: new Container(
width: double.infinity,
color: Colors.white,
padding: new EdgeInsets.all(16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new TextField(
style: new TextStyle(fontSize: 14.0),
textAlign: TextAlign.end,
),
new Div(),
new TextField(
style: new TextStyle(fontSize: 14.0),
textAlign: TextAlign.end,
),
new Div(),
new TextField(
style: new TextStyle(fontSize: 14.0),
textAlign: TextAlign.end,
),
],
),
),
);
}
}
screen Shot:
What I want:
TextField auto scroll over IME when I click one of TextField.

Your problem was solved in this example here
, Please go through and wrap all your TextField 's inside EnsureVisibleWhenFocused and this will bring the TextField just above the keyboard.
Regards,
Mahi

Related

How to enter a new line in a multiline Flutter TextField whose textinputaction is textinputaction.done?

The code below creates a Flutter simple application which contains 2 multi line TextField's. The left one uses a default keyboard with Enter button. Its onSubmitted: method is not called, so you can not execute a method once the user has finished editing the TextField. The right TextField replaces Enter by Done, which enables onDubmitted. Since Enter is no longer available on the keyboard, I am asking how can I add a new line on the right multi line widget.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter TextField Multiple Lines'),
),
body: const MyStatefulWidget());
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
late TextEditingController _controllerEnter;
late TextEditingController _controllerDone;
#override
void initState() {
super.initState();
_controllerEnter = TextEditingController();
_controllerDone = TextEditingController();
}
#override
void dispose() {
_controllerEnter.dispose();
_controllerDone.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Multiline TextField Enter',
style: TextStyle(fontSize: 20),
),
Focus(
child: TextField(
style: const TextStyle(fontSize: 20),
maxLines: 3,
controller: _controllerEnter,
onSubmitted: (String value) {
// method never called !
debugPrint('\n*** onSubmitted: $value ***\n');
},
),
onFocusChange: (value) {
// this method compensate the fact that the
// TextField onSubmitted: method is not called.
if (!value) {
debugPrint('\n*** onFocusChange: ${_controllerEnter.text} ***\n');
}
},
),
],
),
),
const SizedBox(
width: 25,
),
SizedBox(
width: 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Multiline TextField Done',
style: TextStyle(fontSize: 20),
),
TextField(
// How can Enter be used to add a new line to the TextField ?
style: const TextStyle(fontSize: 20),
maxLines: 3,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
controller: _controllerDone,
onSubmitted: (String value) {
debugPrint('\n*** onSubmitted: $value ***\n');
},
),
],
),
),
],
),
));
}
}
I don't think you can do both with native keyboards.
You can maybe build a custom keyboard. For example, you could use a package like https://pub.dev/packages/keyboard_actions

Flutter - How do I create this Signup Form?

I'm trying to place an input form field underneath my text which says please enter your email. Could anyone assist? The thing I'm having the biggest problem with right now is I don't know how to add anything else below the text. Ideally, I'd like a centred input field. Code is below:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:google_fonts/google_fonts.dart';
void main() {
runApp(MyApp());
}
class MyCustomForm extends StatefulWidget {
#override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
class MyCustomFormState extends State<MyCustomForm> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Enter your email'),
),
]),
);
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test Bench',
home: Stack(children: [
new Scaffold(
body: new Container(
decoration: BoxDecoration(color: Colors.pinkAccent),
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Text(
"Hello, Let's Get Started...",
style: TextStyle(
fontSize: 60.0,
fontWeight: FontWeight.bold,
fontFamily: 'Oswald',
color: Colors.black),
),
),
),
),
]));
}
}
You can wrap the text with a Column to append widgets underneath each other (Video). You can view more information Here. This video also helps with general layouts (link).
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyCustomForm extends StatefulWidget {
#override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
class MyCustomFormState extends State<MyCustomForm> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Enter your email'),
),
]),
);
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test Bench',
home: Stack(
children: [
Scaffold(
body: Container(
width: double.infinity,
decoration: BoxDecoration(color: Colors.pinkAccent),
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Hello, Let's Get Started...",
style: TextStyle(
fontSize: 60.0,
fontWeight: FontWeight.bold,
fontFamily: 'Oswald',
color: Colors.black,
),
),
MyCustomForm(),
],
),
),
),
),
],
),
);
}
}
You probably have trouble to find how to add multiples widgets as the child of your Scaffold.
I suggest you to check out the official documentation on layouts
You'll learn there how to create more complex layout and how you can add an input text field under a text widget.

How to dynamically generate and store state of a custom stateful widget in the parent class?

I am currently stuck with dynamic generation of widget and its state maintenance.
This is my code.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark().copyWith(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: <Widget>[
DescriptionTextField(),
DividerAddDescription(onPressed: () => print('Add another description'))
],
),
),
),
);
}
}
class DescriptionTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white38),
child: TextField(
minLines: 1,
maxLines: null,
style: TextStyle(
fontSize: 16,
),
decoration: InputDecoration(
hintText: 'Enter description',
hintStyle: TextStyle(
fontSize: 16,
),
contentPadding: EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: InputBorder.none,
),
),
);
}
}
class DividerAddDescription extends StatelessWidget {
DividerAddDescription({#required this.onPressed});
final Function onPressed;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Divider(
thickness: 1,
),
),
FloatingActionButton(
onPressed: onPressed,
child: Icon(
Icons.add,
color: Color(0xFF232F34),
),
backgroundColor: Colors.orange,
),
],
);
}
}
This is how the screen looks like.
What I am trying to achieve:
when clicking on the plus button, another DescriptionTextField will be added to the Column widget.
as a new DescriptionTextField is added, if the previous DescriptionTextField has description text in it, the text should be preserved.
What I don't know how to do:
where should the description text be stored? Is it in DescriptionTextField's state? i.e. do I need to make it a Stateful widget instead?
when I have multiple DescriptionTextField, how am I supposed to store the state? e.g. the description text
You should create a List variable in your State, add the new elements there and call the setState method when adding.
class _HomeScreenState extends State<HomeScreen> {
//Create a field which hold the elements
List<DescriptionTextField> myDescriptions = List<DescriptionTextField>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: <Widget>[
...myDescriptions, //Add the elements to the Column using the spread operator
DividerAddDescription(onPressed: () => setState(() => myDescriptions.add(DescriptionTextField(key: UniqueKey()))) //Adding new widget
],
),
),
),
);
}
}
I recommend you to use a key value in your DescriptionTextField widgets, because you will be adding widget dynamically and Flutter could struggle to match the respectively their states.
There are of course many improvements, but from my perspective and what I understand from your description, this may help you.

How to add custom widget when button is pressed

I used a couple other threads to create an app where you type in some text in a textfield and when you press the button a default container is added to a list with the text in one of the fields. However when I type the text and add the widget the text is changed for all entries instead of just for the one that was added. This is my code:
import 'dart:core';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int count = 0;
TextEditingController noteSend = TextEditingController();
#override
Widget build(BuildContext context) {
List<Widget> children = new List.generate(
count,
(int i) => new InputWidget(
i,
noteRec: noteSend.text,
));
return new Scaffold(
appBar: new AppBar(title: new Text('some title')),
body: Column(
children: <Widget>[
Container(
child: TextField(
controller: noteSend,
),
color: Colors.lightBlueAccent,
width: 150,
height: 50,
),
Expanded(
child: ListView(
children: children,
scrollDirection: Axis.vertical,
),
),
],
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: () {
setState(() {
count = count + 1;
});
},
));
}
}
class InputWidget extends StatefulWidget {
final int index;
final String noteRec;
InputWidget(this.index, {Key key, this.noteRec}) : super(key: key);
#override
_InputWidgetState createState() => _InputWidgetState();
}
class _InputWidgetState extends State<InputWidget> {
#override
Widget build(BuildContext context) {
return new Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.image,
size: 75,
)
],
),
Container(
margin: EdgeInsets.only(left: 80, right: 30),
child: Column(
children: <Widget>[
Text('Note'),
],
),
),
Column(
children: <Widget>[
Text("${widget.noteRec}"),
],
),
],
),
);
}
}
How can I make the Text different with every entry?
List<Widget> children = new List.generate(
count,
(int i) => new InputWidget(
i,
noteRec: noteSend.text,
));
In this code, you set the input text for all the elements in children. It's the reason all the entries are changed to the same text. You can save the text to a list of the string when you press the save button and call it in List.generate:
List<Widget> children = new List.generate(
count,
(int i) => new InputWidget(
i,
noteRec: listString[i],
));
Try this code
Container(
height: 200,
child: Column(
children: <Widget>[
Expanded(
child: buildGridView(),
)
],
),
),
Then call the buildGridView that will return Widgets
Widget buildGridView() {
return Text('text here'); // your future widget
}

How to make scrollable Drag and Drop in Flutter?

I am trying to make a scrollable and zoomable Stack using SingleChildScrollView in order to implement a canvas editor.
The Drag and Drop works perfectly when I put my dragabble item in the initial view but when I scroll down the view and I tried to drop my container is coming back in the initial view.
I'm new to the Flutter development so maybe I missunderstood in the implementation of a such thing.
Here's the code I currently have.
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: App(),
),
);
}
}
class App extends StatefulWidget {
#override
AppState createState() => AppState();
}
class AppState extends State<App> {
Color caughtColor = Colors.grey;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Stack(
children: <Widget>[
Container(
height: 2000,
),
DragBox(Offset(0.0, 0.0), 'Box One', Colors.blueAccent),
],
),
);
}
}
class DragBox extends StatefulWidget {
final Offset initPos;
final String label;
final Color itemColor;
DragBox(this.initPos, this.label, this.itemColor);
#override
DragBoxState createState() => DragBoxState();
}
class DragBoxState extends State<DragBox> {
Offset position = Offset(0.0, 0.0);
#override
void initState() {
super.initState();
position = widget.initPos;
}
#override
Widget build(BuildContext context) {
return Positioned(
left: position.dx,
top: position.dy,
child: Draggable(
data: widget.itemColor,
child: Container(
width: 100.0,
height: 100.0,
color: widget.itemColor,
child: Center(
child: Text(
widget.label,
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.none,
fontSize: 20.0,
),
),
),
),
onDraggableCanceled: (velocity, offset) {
setState(() {
position = offset;
});
},
feedback: Container(
width: 120.0,
height: 120.0,
color: widget.itemColor.withOpacity(0.5),
child: Center(
child: Text(
widget.label,
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.none,
fontSize: 18.0,
),
),
),
),
));
}
}
Any suggestions or code samples would be really helpful to me.
I solve the problem like this, wrap your draggable with a listener.
Listener listenableDraggable = Listener(
child: draggable,
onPointerMove: (PointerMoveEvent event) {
if (event.position.dy > MediaQuery.of(context).size.height) {
// 120 is height of your draggable.
scrollController.scrollTo(scrollcontroller.offset + 120);
}
},
);