Flutter showTextInputDialog usage - flutter

I'm new to Flutter and I'm stuck here.
I'm trying to use Dialog box to get user input but I don't know how to process the data after submitting the value.
I'm using adaptive_dialog: ^1.0.0 dependency here.
child: ListTile(
title: Text('Change Age'),
onTap: () {
showTextInputDialog(
context: context,
title: 'Enter your Age!',
textFields: [
DialogTextField(
keyboardType: TextInputType.number,
hintText: '18',
)
],
okLabel: 'Submit',
cancelLabel: 'Cancel',
);
},
),

Dialog box to get user input
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int age = 0;
TextEditingController ageController = new TextEditingController();
Future<void> _displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
ageController.text="";
return AlertDialog(
title: Text('Enter your age'),
content: TextField(
onChanged: (value) {
setState(() {
age = int.parse(value);
});
},
controller: ageController,
decoration: InputDecoration(hintText: "18"),
),
actions: <Widget>[
// ignore: deprecated_member_use
FlatButton(
//color: Colors.red,
//textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
// ignore: deprecated_member_use
FlatButton(
//color: Colors.green,
//textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
// age = int.parse(value);
Navigator.pop(context);
});
},
),
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: [
ListTile(
title: Text('Change Age'),
onTap: () {
_displayTextInputDialog(context);
},
),
Text(age.toString())
],
),
),
);
}
}

You can use .then and the index of the textField to get the value
showTextInputDialog(
context: context,
title: "Enter your Age!",
message: 'Age here',
okLabel: "Submit",
cancelLabel: "Cancel",
barrierDismissible: false,
textFields: [
const DialogTextField(
keyboardType: TextInputType.number,
hintText: '18',
)
],
).then((value) {
return debugPrint(value![0]);
}
);

Related

PopupMenuButton not able to change icon when clicked

I'm using the PopupMenuButton in flutter for a web based project and trying to change the popupmenubutton icon when it's clicked. So in its initial state it would show Icons.menu and when opened, it could would Icons.close and once clicked again revert back to Icons.menu.
I have tried onSelected which does not get called at all when clicked in an attempt to change the icon.
I have used an icon or a child IconButton per the docs and used onPressed to setState however that doesn't work either.
Currently the elevated button when clicked, does not show the dropdown menu, nor does it update the icon.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool menuClicked = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
PointerInterceptor(
intercepting: true,
child: PopupMenuButton<String>(
offset: const Offset(10.0, 50.0),
color: Colors.black,
child: ElevatedButton(
onPressed: () {
setState(() {
menuClicked = !menuClicked;
});
},
child: Icon((menuClicked = true)
? Icons.menu
: Icons.close),),
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
PopupMenuItem(
value: "close",
child: ListTile(
leading: Icon(Icons.close, color: Colors.white),
title: Text('Close',
style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
}),
),
],
),
],
),
),
body: Center(
child: Text('test'),
),
);
}
}
Equal sign will be ==
Icon((menuClicked == true) ? Icons.menu : Icons.close),
or you can do
Icon(menuClicked ? Icons.menu : Icons.close),
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool menuClicked = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
GestureDetector(
behavior: HitTestBehavior.translucent,
onPanDown: (details) {
setState(() {
menuClicked = true;
});
},
child: PopupMenuButton<String>(
offset: const Offset(10.0, 50.0),
color: Colors.black,
onSelected: (value) {
setState(() {
menuClicked = false;
});
},
padding: EdgeInsets.zero,
onCanceled: () {
setState(() {
menuClicked = false;
});
},
child: Icon(menuClicked ? Icons.close : Icons.menu),
itemBuilder: (BuildContext context) => [
PopupMenuItem(
value: "close",
child: ListTile(
leading: Icon(Icons.close, color: Colors.white),
title: Text(
'Close',
style: TextStyle(color: Colors.white),
),
onTap: () {
Navigator.pop(context);
},
),
),
],
),
),
],
),
);
}
}

TextFormField obscureText in AlertDialog don't change

I want to change the obscureText mode of a TextFormField in an AlertDialog but it doesn't work
Clicking the IconButton does not change
the obscureText to TextFormField in AlertDialog
I want to change the obscureText mode of a TextFormField in an AlertDialog but it doesn't work
Clicking the IconButton does not change
the obscureText to TextFormField in AlertDialog
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final username = TextEditingController(text: '');
final password = TextEditingController(text: '');
final formKey = GlobalKey<FormState>();
late bool obscure;
#override
void initState() {
obscure = true;
super.initState();
}
#override
void dispose() {
username.dispose();
password.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
IconButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) {
return AlertDialog(
title: const Text('Connection'),
content: SizedBox(
height: 400,
width: 400,
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
cursorColor: Colors.grey,
textInputAction: TextInputAction.next,
maxLines: 1,
controller: username,
validator: (value) {
return null;
},
decoration: const InputDecoration(
isDense: true,
prefixIcon: Icon(
Icons.person_outlined,
),
labelText: 'username',
),
),
const SizedBox(
height: 20.0,
),
TextFormField(
cursorColor: Colors.grey,
controller: password,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
isDense: true,
prefixIcon: const Icon(Icons.key),
labelText: 'password',
suffixIcon: IconButton(
icon: const Icon(
Icons.remove_red_eye_outlined),
onPressed: () {
// CHAGE OBSCURE
setState(() {
obscure = !obscure;
if (kDebugMode) {
print(obscure); // OK
}
});
}),
),
obscureText: obscure, // NOT OK
obscuringCharacter: '*',
validator: (String? value) {
return null;
},
),
],
),
)),
actions: [
TextButton(
child: const Text('Send'),
onPressed: () {
if (formKey.currentState!.validate()) {
Navigator.of(context).pop();
}
},
),
],
);
});
},
icon: const Icon(Icons.person_outline_outlined),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
);
}
}
For that you have to use StatefulBuilder to use setState inside Dialog and update Widgets only inside of it.
Reason: setState is having different context inside the AlertDialog, so If you want to maintain the state of AlertDialog you must have to use StatefulBuilder. It will maintain another state for your AlertDialog
Full Working Code:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final username = TextEditingController(text: '');
final password = TextEditingController(text: '');
final formKey = GlobalKey<FormState>();
late bool obscure;
#override
void initState() {
obscure = true;
super.initState();
}
#override
void dispose() {
username.dispose();
password.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
IconButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) {
return StatefulBuilder(
builder: (context, setState)
{
return AlertDialog(
title: const Text('Connection'),
content: SizedBox(
height: 400,
width: 400,
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
cursorColor: Colors.grey,
textInputAction: TextInputAction.next,
maxLines: 1,
controller: username,
validator: (value) {
return null;
},
decoration: const InputDecoration(
isDense: true,
prefixIcon: Icon(
Icons.person_outlined,
),
labelText: 'username',
),
),
const SizedBox(
height: 20.0,
),
TextFormField(
cursorColor: Colors.grey,
controller: password,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
isDense: true,
prefixIcon: const Icon(Icons.key),
labelText: 'password',
suffixIcon: IconButton(
icon: const Icon(Icons.remove_red_eye_outlined),
onPressed: () {
// CHAGE OBSCURE
setState(() {
obscure = !obscure;
if (kDebugMode) {
print(obscure); // OK
}
});
}),
),
obscureText: obscure,
// NOT OK
obscuringCharacter: '*',
validator: (String? value) {
return null;
},
),
],
),
)),
actions: [
TextButton(
child: const Text('Send'),
onPressed: () {
if (formKey.currentState!.validate()) {
Navigator.of(context).pop();
}
},
),
],
);
});
});
},
icon: const Icon(Icons.person_outline_outlined),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
);
}
}

Flutter - Change text input type and input formatters dynamically on tap

I want to change the text input type and input formatters of a text field dynamically on tap. But the problem is once the text input type is done it is not changed on tap whereas the label text acts as expected.
I have done like below
bool joinlinkname = false;
joinchanged() {
if (joinlinkname == false) {
setState(() {
joinlinkname = true;
});
} else {
setState(() {
joinlinkname = false;
});
}
}
TextField(
keyboardType: joinlinkname? TextInputType.text : TextInputType.phone,
labelText: joinlinkname ? 'num' : "text",
inputFormatters: [joinlinkname ?
FilteringTextInputFormatter.allow(RegExp('[azAZ09]')):FilteringTextInputFormatter.allow(RegExp('[0-9]')),
],
),
GestureDetector(
onTap: () {
joinchanged();
},
child: Text(joinlinkname ? 'number' : 'text',
style: TextStyle(
color: Colors.blue,
fontSize: 12,
),
),
),
Please can anyone tell how to do it?
You can copy paste run full code below
You can use ValueListenableBuilder and ValueNotifier
You also need FocusNode to control keyboard
You can see working demo below
code snippet
final ValueNotifier<bool> joinlinkname = ValueNotifier<bool>(false);
...
joinchanged() async {
FocusManager.instance.primaryFocus.unfocus();
joinlinkname.value = !joinlinkname.value;
await Future.delayed(Duration(milliseconds: 500), () {});
myFocusNode.requestFocus();
}
...
ValueListenableBuilder(
builder: (BuildContext context, bool value, Widget child) {
return Column(
children: [
GestureDetector(
onTap: () {
joinchanged();
},
child: Text(
joinlinkname.value ? 'number' : 'text',
style: TextStyle(
color: Colors.blue,
fontSize: 12,
),
),
),
TextField(
focusNode: myFocusNode,
keyboardType: joinlinkname.value
? TextInputType.phone
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<bool> joinlinkname = ValueNotifier<bool>(false);
FocusNode myFocusNode;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
#override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
joinchanged() async {
FocusManager.instance.primaryFocus.unfocus();
joinlinkname.value = !joinlinkname.value;
await Future.delayed(Duration(milliseconds: 500), () {});
myFocusNode.requestFocus();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: ValueListenableBuilder(
builder: (BuildContext context, bool value, Widget child) {
return Column(
children: [
GestureDetector(
onTap: () {
joinchanged();
},
child: Text(
joinlinkname.value ? 'number' : 'text',
style: TextStyle(
color: Colors.blue,
fontSize: 12,
),
),
),
TextField(
focusNode: myFocusNode,
keyboardType: joinlinkname.value
? TextInputType.phone
: TextInputType.text,
decoration: InputDecoration(
labelText: joinlinkname.value ? 'num' : "text",
),
inputFormatters: [
joinlinkname.value
? FilteringTextInputFormatter.allow(RegExp('[0-9]'))
: FilteringTextInputFormatter.allow(RegExp('[azAZ09]')),
],
),
],
);
},
valueListenable: joinlinkname,
),
),
);
}
}

TypeAhead different widgets flutter

I'm trying to create different widgets in TypeAhead suggestion depends on suggestion.subName.length
1. ListTile with a subTitle
2. ListTile without subTitle
TypeAhead(
...
itemBuilder: (context, suggestion) {
return ListTile(
dense: true,
title: AutoSizeText(
suggestion.primeName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
minFontSize: 20,
),
subtitle: suggestion.subName.length == 0 ? null:AutoSizeText(
suggestion.subName.join(', '),
maxLines: 1,
overflow: TextOverflow.ellipsis,
minFontSize: 15,
),
);
},
...
But everything comes back with a subtitle.
What could cause that? Is it possible to make 2 different types of widgets in TypeAhead?
You can copy paste run full code below
I use the following example to simulate this case
You can return Container() not null
subtitle: suggestion.subName.length == 0 ? Container() : AutoSizeText(
or put condition in itemBuilder, for more complex condition you can use if
itemBuilder: (context, suggestion) {
return suggestion.subName.length == 0 ? ListTile(...) : ListTile(...);
working demo
full code
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter_typeahead/flutter_typeahead.dart';
class BackendService {
static Future<List> getSuggestions(String query) async {
await Future.delayed(Duration(seconds: 1));
return List.generate(3, (index) {
return {'name': query + index.toString(), 'price': Random().nextInt(100)};
});
}
}
class CitiesService {
static final List<String> cities = [
'Beirut',
'Damascus',
'San Fransisco',
'Rome',
'Los Angeles',
'Madrid',
'Bali',
'Barcelona',
'Paris',
'Bucharest',
'New York City',
'Philadelphia',
'Sydney',
];
static List<String> getSuggestions(String query) {
List<String> matches = List();
matches.addAll(cities);
matches.retainWhere((s) => s.toLowerCase().contains(query.toLowerCase()));
return matches;
}
}
class NavigationExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(32.0),
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
),
TypeAheadField(
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
style: DefaultTextStyle.of(context)
.style
.copyWith(fontStyle: FontStyle.italic),
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'What are you looking for?'),
),
suggestionsCallback: (pattern) async {
return await BackendService.getSuggestions(pattern);
},
itemBuilder: (context, suggestion) {
return ListTile(
leading: Icon(Icons.shopping_cart),
title: Text(suggestion['name']),
subtitle: suggestion['price'] < 20
? Container()
: Text('\$${suggestion['price']}'),
);
},
onSuggestionSelected: (suggestion) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProductPage(product: suggestion)));
},
),
],
),
);
}
}
class ProductPage extends StatelessWidget {
final Map<String, dynamic> product;
ProductPage({this.product});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(50.0),
child: Column(
children: [
Text(
this.product['name'],
style: Theme.of(context).textTheme.headline,
),
Text(
this.product['price'].toString() + ' USD',
style: Theme.of(context).textTheme.subhead,
)
],
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
NavigationExample(),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Flutter v1.12.13+hotfix.5 FocusNode unexpected behaviour

I added focus node to textformfield. After i upgraded flutteer version to v1.12.13+hotfix.5 , flutter focusnode had unexpected bahaviour.
#override
void initState() {
super.initState();
focusNode.addListener(() async {
if(focusNode.hasFocus)
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
}
}
TextFormField(
style: TextStyle(color: Theme.of(context).brightness==Brightness.dark?Colors.white:Colors.grey),
readOnly: true,
validator: validateField,
focusNode: focusNode,
controller: controller,
);
I click to textformfield to open secondPage. but when i close secondPage, Second page is opened automatically. This behaviour occured after i upgraded version to v1.12.13+hotfix.5.
What is the true usage of focusNode in v1.12.13+hotfix.5?
You can copy paste run full code below
Because TextFormField still have foucs when you go back from SecondRoute, so you need to do unfocus
code snippet
focusNode.addListener(() async {
if (focusNode.hasFocus) {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
FocusScope.of(context).requestFocus(new FocusNode());
}
});
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final controller = TextEditingController();
FocusNode focusNode = new FocusNode();
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
super.initState();
focusNode.addListener(() async {
if (focusNode.hasFocus) {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
FocusScope.of(context).requestFocus(new FocusNode());
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
style: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.grey),
readOnly: true,
//validator: validateField,
focusNode: focusNode,
controller: controller,
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}