Why Information is Null when Clicking Button first-time? - flutter

Solved:
please check my own answer..It's working well..but Is that proper way to fix like this issue?
This is the registration details page. First-row display text-form-field and then dropdown and etc. User typing value and select dropdown and click button information value are showing. But user select dropdown value and then typing information and click the button, information value is null.
AND ALSO typing value on textFormField and click button first time value is null, then click again button value is showing. Why is that?
I added print('textfield is $details'), in onPressed() method.
scenario 1: typing information and click button value is null
scenarion 2: typing information and select dropdown/tap on screen and
click button value is showing
class _overview3 extends State<overview3> {
final detailsController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: overviewAppBar(
detailsController.text),
body: Scaffold(
body: Container(
child: Container(
child: Scaffold(
body: ListView(
children: <Widget>[
TextFormField(
controller: detailsController,
maxLength: 100,
maxLines: 2,
keyboardType: TextInputType.multiline,
validator: (value) {
if (value.length > 3) {
return '100 values';
}
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(20.0),
hintText: AppTranslations.of(context).text("additional_details"),
),
),
],
),
)))
));
}
in my OverviewAppBar method,
overviewAppBar(String details) =>
AppBar(
brightness: Brightness.dark,
backgroundColor: const Color(0xFFE27023),
centerTitle: true,
title: appBarIcon(context),
actions: <Widget>[
IconButton(
icon: _isButtonDisabled
? Icon(
Icons.check,
color: Colors.white30,
)
: Icon(Icons.check),
onPressed: () => _isButtonDisabled
? null
: globals.isButtonClick
? null
:{FocusScope.of(context).requestFocus(FocusNode()),
print('textfield is $details')
}
)
]
);

global.dart file
final globalDetailsController = TextEditingController();
in textformfield
TextFormField(
controller: global.globalDetailsController
)
in OverviewAppBar method in onPressed()
print('textfield is ${global.globalDetailsController}')

Related

Flutter web app not showing typed password when set to show password

On my flutter webapp I am trying to show the password if the user chose to show it. If I set my bool value to false it start by showing the normal text and then if I press the button to show or hide the password it will obscure the text but it will not un-obscure the text. I added a print function in one of my try's and it does change the bool value from false to true and back to false. I have it it a setState but no luck. I tryied many different examples online but can not get it to work with the web app.
The code
#override
Widget build(BuildContext context) {
c_width = MediaQuery.of(context).size.width*0.8;
return Scaffold(
appBar: AppBar(title: Text("App"),
),
body: signUpWidget(widget.signUpValue),
);
}
Widget signUpWidget(String? rl) {
switch(rl) {
case 'User': {
return SingleChildScrollView(
child: Container (
width: c_width,
padding: const EdgeInsets.all(16.0),
child: Column(
child: Column(
children: <Widget>[
TextFormField(
obscureText: isObscure,
decoration: InputDecoration(
suffix: TextButton(
child: isPasswordObscure
? Text(
'Show',
style: TextStyle(color: Colors.grey),
)
: Text(
'Hide',
style: TextStyle(color: Colors.grey),
),
onPressed: () {
setState(() {
isObscure = !isObscure;
isPasswordObscure = !isObscure;
});
},
),
),
),
Like I say it changes the text to hide and show and if I print the bool value it changes from true to false, but it does not unObscure the text in the field to show the password. Is it something to do with web? or am I missing something?
Thank you.
Actually you dont need to have two bool,
TextFormField(
obscureText: isObscure,
decoration: InputDecoration(
suffix: TextButton(
child: isObscure //< using
? Text(
'Show',
style: TextStyle(color: Colors.grey),
)
: Text(
'Hide',
style: TextStyle(color: Colors.grey),
),
onPressed: () {
setState(() {
isObscure = !isObscure;
// isPasswordObscure = !isObscure; // here it reverse the variable isPasswordObscure
});
},
),
),
)
It might be occurring due to this problem in setState((){}).
setState(() {
// assume isObscure is true initially
isObscure = !isObscure;
// now isObscure is false
isPasswordObscure = !isObscure;
// now isPasswordObscure is true, because isObscure's value has already changed.
});
To solve this, first save isObscure to a temporary variable.
setState(() {
var temp = isObscure;
isObscure = !temp;
isPasswordObscure = !temp;
});
Or,
Entirely avoid using two bools.
setState(() {
isObscure = !isObscure;
});
It seems like this occurs only in web.
Follow these steps to fix this,
https://github.com/flutter/flutter/issues/83695#issuecomment-1083537482
Or
Upgrade to the latest Flutter version.

Can a function accept two values in flutter/dart language? if yes than how?

Suppose I have a application with login function there are two text input field Username & Password. and there is on button called Login. Now if user enters Username and password and hit Login button then app will navigate him/her to next page like account page. But if user pressed login button with any or both field empty than a tooltip will called like "username & password cant be empty"...So i think login button will call a function (when pressed) which required two values username & password and if this values are empty then tooltip called otherwise navigate to next page...
Well, I am new to programming so maybe my whole logic can be wrong, and if logic is ok then what can I do??
Here is my code...
import 'package:flutter/material.dart';
import 'package:login_signup/accountpage.dart';
void main(List<String> args) {
runApp(logsign());
}
class logsign extends StatefulWidget {
#override
_logsignState createState() => _logsignState();
}
class _logsignState extends State<logsign> {
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'/account': (context) => AccountPage(),
},
theme: ThemeData(
primarySwatch: Colors.green,
),
title: "logsignApp",
home: homepage(),
);
}
}
class homepage extends StatefulWidget {
#override
_homepageState createState() => _homepageState();
}
class _homepageState extends State<homepage> {
String usrname;
String passwd;
void detailsmust (String usrname, passwd){
if (usrname == "" || passwd == ""){
Tooltip(message: "Username & Password field cant be empty");
}
else{
Navigator.pushNamed(context, '/account')
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Login/Signup"),
),
drawer: Text("Just a drawer", textScaleFactor: 2.0),
body:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
onChanged: (text){
usrname = text;
},
maxLength: 30,
decoration: InputDecoration(
prefixIcon: Icon(Icons.account_box),
labelText: 'Username',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)),
),
),
// Padding(
// padding: EdgeInsets.all(2.0),
// ),
TextField(
onChanged: (text){
passwd = text;
},
obscureText: true,
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock_outline),
labelText: 'Password',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MaterialButton(
onPressed: detailsmust,
child: Text("Login"),
color: Colors.green,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
),
Padding(
padding: EdgeInsets.all(5.0),
),
MaterialButton(
onPressed: (){},
child: Text("Exit"),
color: Colors.green,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
),
],
),
],
),
);
}
}
Welcome to programming, you're logic is right. There are many ways to check for this value and functionality that you want. In Flutter you can use TextFields or TextFormFields which have TextEditingControllers, and validators and lots of other functionalities that you should look into. And these functionalities can indeed validate user input, and enable or disable certain functions such as logging in users as your case. What ever you can think of can be done. Start reading and working.
edit1:
Regarding the general purpose of your app, I would advise you to use it like this, when working with TextFields, make sure to remember that you have TextEditingControllers that would come in handy, thus, you should modify your submit function to look something like this:
TextEditingController usrname = TextEditingController();
TextEditingController passwd = TextEditingController();
void detailsmust() {
if (usrname.text == "" || passwd.text == "") {
setState(() {//setState is needed in order for the UI to change.
Tooltip(message: "Username & Password field cant be empty");
});
} else {
Navigator.pushNamed(context, '/account'); //was missing a semicolon here
}
}
And in your textFields, you don't have to use the on changed now, just point to your controllers, like this:
//for userName
TextField(
maxLength: 30,
controller:usrname
//rest of your textfields as they were
)
//for password
TextField(
controller:passwd
)
You don't have to declare the variables String username or String passwd anymore, and the text editing controllers willbe listening to the inputs of the fields.
To capture the values being held inside the controllers, you use the property .text, as in username.text.

Flutter: Multiline TextField (TextFormField) simply won't work

I am fairly new at Flutter so I might have gotten things wrong but ... I can't get my head around this issue.
I have ready many posts on how allow multi-line text for TextField / TextFormField.
I have tried setting maxLines to null or to a big number, to enforce max lines (or not), but nothing works !
How come something as simple won't work ?
// in a Scaffold of a StatefulWidget
body: Padding(
padding: const EdgeInsets.all(50.0),
child: TextField(
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: 5,
),
I have tried on two different real Android devices and hitting the ENTER key does nothing. Unfortunately, I can't test the behavior on iOS as I don't have a Mac.
EDIT 1
Following solution offered by copsonroad, the following code
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.event.shortName == null || widget.event.shortName.isEmpty
? AppLocalizations.of(context).eventEditorTitleNewEvent
: AppLocalizations.of(context)
.eventEditorTitleEditEvent(widget.event.shortName)),
actions: <Widget>[
if (_canSave == true) ...[
IconButton(
icon: Icon(Icons.done),
onPressed: () => _saveEventAndPop(),
)
],
]),
body: Center(
child: Padding(
padding: const EdgeInsets.all(50),
child: SizedBox(
height: 5 * 50.0,
child: TextField(
decoration: InputDecoration(hintText: "Enter a message"),
keyboardType: TextInputType.multiline,
maxLines: 5,
),
),
),
),
);
}
Produce the following result:
Screenshot:
#override
Widget build(BuildContext context) {
var maxLines = 5;
return Scaffold(
appBar: AppBar(),
body: Center(
child: Padding(
padding: const EdgeInsets.all(50),
child: SizedBox(
height: maxLines * 50.0,
child: TextField(
decoration: InputDecoration(hintText: "Enter a message"),
keyboardType: TextInputType.multiline,
maxLines: maxLines,
),
),
),
),
);
}
Edit:
Testing it on Android:
There is actually a bug with TextInputType.multiline. It simply doesn't work with some custom keyboards (i.e. SwiftKey). There is an issue in flutter github where I described my workaround.
First of all, I've wrapped my TextFormField with RawKeyboardListener like this:
RawKeyboardListener(
focusNode: FocusNode(),
autofocus: false,
onKey: (rawKeyEvent) {
final isFormSkippedEnterEvent = rawKeyEvent is RawKeyDownEvent &&
rawKeyEvent.isKeyPressed(LogicalKeyboardKey.enter);
final needToInsertNewLine = isFormSkippedEnterEvent &&
keyboardType == TextInputType.multiline;
if (needToInsertNewLine) {
TextEditingControllerHelper.insertText(controller, '\n');
}
},
child: TextFormField(...)
...
When Gboard is used, RawKeyboardListener doesn't receive Enter event at all, it's sent directly to the text field. But when using for example SwiftKey, instead of inserting new line to the text, RawKeyboardListener receives an event RawKeyDownEvent#a5131(logicalKey: LogicalKeyboardKey#70028(keyId: "0x100070028", keyLabel: "Enter", debugName: "Enter"). I check if I need to insert a new line (no need for this if TextFormField is configured to be single line) and access TextEditingController to alter user's input. All the magic happens inside TextEditingControllerHelper.insertText():
class TextEditingControllerHelper {
static insertText(TextEditingController controller, String textToInsert) {
final selection = controller.selection;
final cursorPosition = selection.base.offset;
if (cursorPosition < 0) {
controller.text += textToInsert;
return;
}
final text = controller.text;
final newText =
text.replaceRange(selection.start, selection.end, textToInsert);
controller.value = controller.value.copyWith(
text: newText,
selection: TextSelection.collapsed(
offset: selection.baseOffset + textToInsert.length,
),
);
}
}
What I do is check cursor/ selection position. In case of an empty field I just attach a newLine (this helper can work with other inputs, i.e. emojis) and exit. Otherwise I insert a new line on place of existing selection (if there is no selection, text is just inserted where cursor is placed) and move cursor to be after the inserted text. Works fine in my tests (Pixel 3a with Gboard/SwiftKey, Galaxy S8 with Samsung keyboard, iPhone simulator).

Flutter using EditableText

I'm trying to figure out how to use the TextEditor in Flutter.
I have "Card Editor" (basically I want to be able to work on the equivalent of a paragraph of text)
new EditableText(
autofocus: true,
maxLines: null,
backgroundCursorColor: Colors.amber,
cursorColor: Colors.green,
style: TextStyle(),
focusNode: FocusNode(),
controller: controller,
onSubmitted: (val) {
_addCard(val);
Navigator.pop(context);
},
)
I adapted this from an example of a TextField.
But I have a couple of questions.
Firstly, it doesn't seem to show anything when I type. The cursor moves, but no text is visible. Is that the default when there's no explicit style?
Secondly, how do I trigger the submit? With a TextField, the CR / Enter button does this. Obviously I see why you don't necessarily want that with EditableText But what should I do instead?
Third, I need to be able to put default text into this widget. I tried adding a "value" attribute to the EditableText, but that doesn't seem to be right. What's the way to do this?
from TextField class - material library - Dart API :
EditableText, which is the raw text editing control at the heart of a TextField. The EditableText widget is rarely used directly unless you are implementing an entirely different design language, such as Cupertino.
here an example of TextField , from my app flutter listview CRUD app using nonsecure rest api
class _TaskEditPageWidgetState extends State<TaskEditPageWidget> {
TextEditingController _noteController;
#override
void initState() {
super.initState();
_noteController = TextEditingController.fromValue(
TextEditingValue(
text: widget.taskOpj.note,
),
);
}
#override
void dispose() {
_noteController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(),
body: _body(),
);
}
Widget _appBar() {
return AppBar(
title: new Text("Edit Task"),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.save),
onPressed: _save,
),
],
);
}
Widget _body() {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Text("Note:"),
TextField(
decoration: InputDecoration(border: InputBorder.none),
autofocus: true,
keyboardType: TextInputType.multiline,
maxLines: null,
controller: _noteController),
],
),
);
}
Future _save() async {
widget.taskOpj.note = _noteController.text;
await Tasks.updateTask(widget.taskOpj);
widget.notifyParent();
Navigator.pop(context);
}
}
Just add this line:
style: TextStyle(
decorationThickness: 0.001,
),

Insert into TextField using buttons from another widget - Flutter

I have a TextField that serves as a search bar where the user can use the built in Android/iOS keyboard to type but also has the possibility to insert a special characters in the search bar from a button. In a way the typing and the other insertion is combined into one string
use case: The user types hell in the search bar then presses the button widget the search bar value becomes : hellö
I set up everything but when I click the button nothing happens (the typing from the keyboard works fine)
Here's my code:
//I have this as a global variable
TextEditingController _searchInputControllor = TextEditingController();
//This is the TextField
class _SearchBarState extends State<SearchBar> {
#override
Widget build(BuildContext context) {
return TextField(
enableInteractiveSelection: false,
controller: _searchInputControllor,
cursorColor: primaryDark,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 15.0),
border: InputBorder.none,
hintText: "Search...",
suffixIcon: Material(
color: Colors.white,
elevation: 6.0,
borderRadius: BorderRadius.all(Radius.circular(6.0),),
child: InkWell(
splashColor: Colors.greenAccent,
onTap: () {},
child: Icon(Icons.search, color: primaryDark,),
),
),
),
);
}
}
//This is the button widget
//It is supposed to add to the search bar but nothing happens
class _SpecialCharState extends State<SpecialChar> {
#override
Widget build(BuildContext context) {
return ButtonTheme(
minWidth: 40.0,
child: FlatButton(
color: Colors.transparent,
textColor: Colors.black,
padding: EdgeInsets.all(8.0),
splashColor: Colors.blue,
onPressed: () {
setState(() {
_searchInputControllor.text = _searchInputControllor.text + widget.btnVal.toLowerCase();
});
},
child: Text(
widget.btnVal
),
)
);
}
}
A. No problem at all
I think your code is working well as I tried on my Android Phone Demo.
The text field is changed as I tap the buttons.
B. Change cursor position
Nonetheless, I add this code to make the cursor automatically placed on last character.
Rather than directly changed the text, we copy its value which contains selection.
Later we offset its selection by length of newText
void appendCharacters() {
String oldText = _searchInputControllor.text;
String newText = oldText + widget.btnVal.toLowerCase();
var newValue = _searchInputControllor.value.copyWith(
text: newText,
selection: TextSelection.collapsed(
offset: newText.length, //offset to Last Character
),
composing: TextRange.empty,
);
_searchInputControllor.value = newValue;
}
so we can trigger the method with code below :
Widget build(BuildContext context) {
return ButtonTheme(
minWidth: 40.0,
child: FlatButton(
onPressed: appendCharacters, // call a function
),
);
}
Working App Repository
You may look into this repo and build yourself. Github