Flutter - How do I create this Signup Form? - forms

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.

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 - richtext, textspan from a list

I don't have much experience with flutter.
I would like to use the language_tool library (https://pub.dev/packages/language_tool) for Dart and Flutter.
I'm trying to create a text where the errors found by the tool() function are clickable.
To do this I thought of using the RichText widget with TextSpan as described here: Make specific parts of a text clickable in flutter
For now I have written this code, but I don't know how to go on
import 'package:flutter/material.dart';
import 'package:language_tool/language_tool.dart';
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Chat(),
);
}
}
class Chat extends StatefulWidget {
const Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
String text = 'Henlo i am Gabriele';
List<WritingMistake> mistakes = [];
List<TextSpan> richtext = [];
void tool(String text) async {
var tool = LanguageTool();
var result = tool.check(text);
var correction = await result;
for (var m in correction) {
WritingMistake mistake = WritingMistake(
message: m.message,
offset: m.offset,
length: m.length,
issueType: m.issueType,
issueDescription: m.issueDescription,
replacements: m.replacements,
);
mistakes.add(mistake);
}
print(mistakes.length);
print(mistakes);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Container(
color: Colors.red,
height: 150.0,
width: double.infinity,
child: Center(
child: Text(text, style: const TextStyle(fontSize: 20.0))),
),
Container(
color: Colors.blue,
height: 150.0,
width: double.infinity,
child: Center(
child: Container(
child: RichText(
text: TextSpan(
text: '',
style: TextStyle(color: Colors.black),
children: richtext,
),
),
),
),
),
],
),
),
);
}
}
I hope I was clear and that someone can help me.
Thank you :)
Here is a small example of what your clickable words should look like in the content. Copy and paste into DartPad to play with it.
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Chat(),
);
}
}
class Chat extends StatefulWidget {
const Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
List<String> mistakes = ['bugs', 'error'];
String content = 'Your application status is error free'
' and no bugs were found.';
Future<void> onTap(String text) async {
print(text);
}
#override
Widget build(BuildContext context) {
String text = 'Henlo i am Gabriele';
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Container(
color: Colors.red,
height: 150.0,
width: double.infinity,
child: Center(
child: Text(text, style: const TextStyle(fontSize: 20.0)),
),
),
Container(
color: Colors.blue,
height: 150.0,
width: double.infinity,
child: Center(
child: RichText(
text: TextSpan(
text: 'App status: ',
style: const TextStyle(color: Colors.black),
children: [
for (String word in content.split(' '))
if (mistakes.contains(word)) ...[
TextSpan(
text: word + ' ',
style: const TextStyle(fontWeight: FontWeight.bold),
recognizer: TapGestureRecognizer()
..onTap = () {
// Do anything with the state on click.
onTap(word);
},
)
] else ...[
TextSpan(text: word + ' ')
],
],
),
),
),
),
],
),
),
);
}
}

Flutter - Validating User Input

So I'm trying to create a sign up page for my app in flutter. So far, I've got some welcome text and an input form where users can input their email. I've also got a button which will eventually change the page underneath the input field that says 'next'. The idea is to have the button disabled which was simple enough to do (just added OnPressed: null) however when the user enters at least one character, followed by an '#' and then a string list of '.com,.co.uk e.t.c) the next button will become enabled. I have tried to add a validate if else statement to the form but to no joy so have removed it from the code below. I guess what I'm asking is how do I:
Validate the input meets my requirements
Disable the button if it does not
Enable the button if it does
All responses / contributions to any of the above are greatly appreciated!
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(
children: [
Text(
"Hello, Let's Get Started...\n",
style: TextStyle(
fontSize: 60.0,
fontWeight: FontWeight.bold,
fontFamily: 'Oswald',
color: Colors.black,
),
),
MyCustomForm(),
ButtonTheme(
minWidth: 250.0,
child: RaisedButton(
onPressed: null,
child: Text("Next"),
),
),
],
),
),
),
),
],
),
);
}
}
Here is a possible solution. I used regex to validate the email entered.
You can learn more about validation from here:
https://flutter.dev/docs/cookbook/forms/validation
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _formKey = GlobalKey<FormState>();
bool isValidated = false;
#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(children: [
Text("Hello, Let's Get Started...\n",
style: TextStyle(
fontSize: 60.0,
fontWeight: FontWeight.bold,
fontFamily: 'Oswald',
color: Colors.black,
)),
Form(
key: _formKey,
child: Column(children: <Widget>[
TextFormField(
onChanged: (input) {
_formKey.currentState.validate();
},
validator: (input) {
var regex = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+");
if (!regex.hasMatch(input) && isValidated) {
setState(() {
isValidated = false;
});
return null;
} else {
setState(() {
isValidated = true;
});
return input;
}
},
decoration: InputDecoration(
labelText: 'Enter your email'),
),
])),
ButtonTheme(
minWidth: 250.0,
child: RaisedButton(
onPressed:
isValidated ? () => print('Signed In') : null,
child: Text("Next"),
),
),
]))))
]));
}
}

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 make flutter TextField at bottom of screen show over IME

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