Flutter DropdownButton - Custom title for selected value? - flutter

I using this model for my DropdownButtonFormField:
class MyItem {
final String fullName;
final String shortName;
}
This my UI code:
List<DropdownMenuItem<MyItem>> _getItems() {
return widget.items
.map((e) => DropdownMenuItem(
value: e,
child: Container(
color: AppColors.inputBackgroundColor,
alignment: Alignment.centerLeft,
child: Text(
'${e.fullName} (${e.shortName})',
style: AppStyles.bodyText1,
),
),
))
.toList();
}
DropdownButtonFormField2<MyItem>(
items: _getItems(),
),
I need to display "fullName + (shortName)" in the popup(items),
and only the "shortName" in the input field itself (when I selected the value).
Is this possible?

Try to use selectedItemBuilder:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) => MaterialApp(
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
class MyWidget extends StatelessWidget {
final items = const [
MyItem(shortName: 'shortName1', fullName: 'Long Name 1'),
MyItem(shortName: 'shortName2', fullName: 'Long Name 2'),
MyItem(shortName: 'shortName3', fullName: 'Long Name 3')
];
#override
Widget build(BuildContext context) => DropdownButtonFormField<MyItem>(
selectedItemBuilder: (context) =>
items.map((e) => Text(e.shortName)).toList(),
items: _getItems(),
onChanged: (item) {});
List<DropdownMenuItem<MyItem>> _getItems() => items
.map((e) => DropdownMenuItem(
value: e,
child: Container(
alignment: Alignment.centerLeft,
child: Text(
'${e.fullName} (${e.shortName})',
),
),
))
.toList();
}
class MyItem {
final String fullName;
final String shortName;
const MyItem({required this.fullName, required this.shortName});
}

Related

grouped multi select dropdown in flutter

after long search for create multi select dropdown in flutter i found tow solutions
first one with custom class :
Is there an equivalent widget in flutter to the "select multiple" element in HTML
scound one with the package :
multi_select_flutter
But what I want is how to make a grouped dropdown in either of these two ways Because giving a title to each option group is very important in my case like this:
In the items, list set the type to data to add checkbox or to sep to add a title. The output from the dialog will be a dictionary in the form of {2,3} where value 2 = Cordoba.
Full Code
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeScreen(),
);
}
}
class MultiSelectDialogItem<V> {
V value;
String name;
String type;
MultiSelectDialogItem(
{required this.name, required this.type, required this.value});
}
class MultiSelectDialog<V> extends StatefulWidget {
const MultiSelectDialog({
Key? key,
required this.items,
required this.initialSelectedValues,
}) : super(key: key);
final List<MultiSelectDialogItem<V>> items;
final Set<V> initialSelectedValues;
#override
State<StatefulWidget> createState() => _MultiSelectDialogState<V>();
}
class _MultiSelectDialogState<V> extends State<MultiSelectDialog<V>> {
final _selectedValues = <V>{};
#override
void initState() {
super.initState();
_selectedValues.addAll(widget.initialSelectedValues);
}
void _onItemCheckedChange(V itemValue, bool checked) {
setState(() {
if (checked) {
_selectedValues.add(itemValue);
} else {
_selectedValues.remove(itemValue);
}
});
}
void _onCancelTap() {
Navigator.pop(context);
}
void _onSubmitTap() {
Navigator.pop(context, _selectedValues);
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Select place'),
contentPadding: const EdgeInsets.all(20.0),
content: SingleChildScrollView(
child: ListTileTheme(
contentPadding: const EdgeInsets.fromLTRB(14.0, 0.0, 24.0, 0.0),
child: ListBody(
children: widget.items.map(_buildItem).toList(),
),
),
),
actions: <Widget>[
ElevatedButton(
onPressed: _onCancelTap,
child: const Text('CANCEL'),
),
ElevatedButton(
onPressed: _onSubmitTap,
child: const Text('OK'),
)
],
);
}
Widget _buildItem(MultiSelectDialogItem<V> item) {
final checked = _selectedValues.contains(item.value);
return item.type == "data"
? CheckboxListTile(
value: checked,
title: Text(item.name),
controlAffinity: ListTileControlAffinity.leading,
onChanged: (checked) => _onItemCheckedChange(item.value, checked!),
)
: Container(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
item.name,
style: TextStyle(color: Color.fromARGB(255, 91, 91, 91)),
),
),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
#override
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
void _showMultiSelect(BuildContext context) async {
final items = <MultiSelectDialogItem<int>>[
MultiSelectDialogItem(name: 'Argentina', type: 'sep', value: 1),
MultiSelectDialogItem(name: 'Cordoba', type: 'data', value: 2),
MultiSelectDialogItem(name: 'Chaco', type: 'data', value: 3),
MultiSelectDialogItem(name: 'Buenos Aires', type: 'data', value: 4),
MultiSelectDialogItem(name: 'USA', type: 'sep', value: 5),
MultiSelectDialogItem(name: 'California', type: 'data', value: 6),
MultiSelectDialogItem(name: 'Florida', type: 'data', value: 7),
];
final selectedValues = await showDialog<Set>(
context: context,
builder: (BuildContext context) {
return MultiSelectDialog(
items: items,
initialSelectedValues: [].toSet(),
);
},
);
print(selectedValues);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text("show dialog"),
onPressed: () {
_showMultiSelect(context);
},
),
),
);
}
}
Output
Hope this helps. Happy Coding :)

How I can change a text in a TextFormField when a ComboBox changes (in Flutter)?

I would like show the default user and password for a database when I select the DBMS.
But when I change the dropdown value the user and password is not changed even I have changed its value.
Look the code:
import 'dart:html';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final appTitle = 'Test App';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: MyForm(),
),
);
}
}
class MyForm extends StatefulWidget {
const MyForm({Key? key}) : super(key: key);
#override
MyFormState createState() => MyFormState();
}
class MyFormState extends State<StatefulWidget> {
String _dbms = 'PostgreSQL';
String _user = 'postgres';
String _pasw = 'postgres';
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text('DBMS'),
Container(
width: 150.0,
child: DropdownButton(
value: _dbms,
items: <String>['SQLite', 'Firebird', 'MySQL', 'PostgreSQL']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_dbms = newValue!;
switch (_dbms) {
case 'PostgreSQL':
_user = 'postgres';
_pasw = 'postgres';
break;
case 'MySQL':
_user = 'root';
_pasw = '';
break;
case 'Firebird':
_user = 'SYSDBA';
_pasw = 'masterkey';
break;
default:
_user = '';
_pasw = '';
break;
}
});
},
),
),
Text('User'),
Container(
width: 150.0,
child: TextFormField(
initialValue: '$_user',
onChanged: (value) => _host,
),
),
Text('Password'),
Container(
width: 150.0,
child: TextFormField(
initialValue: _pasw,
onChanged: (value) => _pasw,
),
),
],
),
),
],
);
}
}
I change the value of the properties but it is not reflected on components.
How I can do this?
Thanks.

EXCEPTION CAUGHT BY GESTURE No MediaQuery widget found. MyHomePage widgets require a MediaQuery widget ancestor

I was trying to add a BottomModelSheet to add new transcations in the transaction list, i follow the and this is the error i am getting, what am i missing here ?
this is my main.dart file
import 'package:expense_tracker/widgets/transaction_list.dart';
import './widgets/transaction_list.dart';
import 'package:flutter/material.dart';
import './widgets/new_transaction.dart';
import './models/transaction.dart';
void main() => runApp(MyHomePage());
class MyHomePage extends StatefulWidget {
// String titleInput;
// String amountInput;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final titleController = TextEditingController();
final amountController = TextEditingController();
final List<Transaction> _userTransactions = [
Transaction(
id: 't1',
title: 'New Shoes',
amount: 1000,
date: DateTime.now(),
),
Transaction(
id: 't2',
title: 'USB Cable',
amount: 600,
date: DateTime.now(),
),
];
void _addNewTransaction(String txTitle, double txAmount) {
final newTX = Transaction(
title: txTitle,
amount: txAmount,
date: DateTime.now(),
id: DateTime.now().toString());
setState(() {
_userTransactions.add(newTX);
});
}
void _startAddNewTransaction(BuildContext ctx) {
showModalBottomSheet(context: ctx,builder: (bCtx) {
return NewTransaction(_addNewTransaction);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
],
),
body: SingleChildScrollView(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: double.infinity,
child: Card(
color: Colors.blue,
child: Text('CHART'),
elevation: 10,
),
),
TransactionList(_userTransactions),
]),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
),
);
}
}
the same BottomModalSheet will be shown while clicking the icon on the appBar and the floatingActionButton in the bottom, they both dont work.
The BuildContext that you're passing to the _startAddNewTransaction method is that of the _MyHomePageState. Since _MyHomePageState contains the MaterialApp (and not the other way round), its BuildContext doesn't know about it.
You have 2 options:
Wrap the widgets that call that method with a Builder widget, whose BuildContext will know about the MaterialApp
Create a new widget (e.g. MyHomePageContent) and pass it to the body: parameter of the material app.
The first option is a quick fix, the second options is the better one.
It would be a good idea to separate your project into multiple files, like so:
main.dart
void main() => runApp(MyApp());
my_app.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
my_home_page.dart
class MyHomePage extends StatefulWidget {
// String titleInput;
// String amountInput;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final titleController = TextEditingController();
final amountController = TextEditingController();
final List<Transaction> _userTransactions = [
Transaction(
id: 't1',
title: 'New Shoes',
amount: 1000,
date: DateTime.now(),
),
Transaction(
id: 't2',
title: 'USB Cable',
amount: 600,
date: DateTime.now(),
),
];
void _addNewTransaction(String txTitle, double txAmount) {
final newTX = Transaction(
title: txTitle,
amount: txAmount,
date: DateTime.now(),
id: DateTime.now().toString());
setState(() {
_userTransactions.add(newTX);
});
}
void _startAddNewTransaction(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (bCtx) {
return NewTransaction(_addNewTransaction);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
],
),
body: SingleChildScrollView(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: double.infinity,
child: Card(
color: Colors.blue,
child: Text('CHART'),
elevation: 10,
),
),
TransactionList(_userTransactions),
]),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
);
}
}

How do i customize flappy_search_bar in flutter

whenever i enter a value in search bar i want to match it from the available list, for example if this is my list
List fooList = ['one', 'two', 'three', 'four', 'five']; and i enter e in search bar it should list those items which contains e in it. How can i do that, anybody please help.
class _HomeState extends State<HeaderWithSearchBox1> {
final SearchBarController<Post> _searchBarController = SearchBarController();
Future<List<Post>> _getALlPosts(String text) async {
List<Post> posts = [];
var random = new Random();
for (int i = 0; i < 10; i++) {
posts
.add(Post("$text $i", "body random number : ${random.nextInt(100)}"));
}
return posts;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SearchBar<Post>(
minimumChars: 1,
searchBarPadding: EdgeInsets.symmetric(horizontal: 10),
headerPadding: EdgeInsets.symmetric(horizontal: 10),
listPadding: EdgeInsets.symmetric(horizontal: 10),
onSearch: _getALlPosts,
searchBarController: _searchBarController,
placeHolder: Center(
child: Text(
"PlaceHolder",
style: TextStyle(fontSize: 30),
)),
cancellationWidget: Text("Cancel"),
emptyWidget: Text("empty"),
onCancelled: () {
print("Cancelled triggered");
},
mainAxisSpacing: 10,
onItemFound: (Post post, int index) {
return Container(
color: Colors.lightBlue,
child: ListTile(
title: Text(post.title),
isThreeLine: true,
subtitle: Text(post.body),
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Detail()));
},
),
);
},
),
),
);
}
}
class Detail extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Center(child: Text("Detail", style: TextStyle(fontSize: 30),)),
),
);
}
}
You can copy paste run full code below
You filter fooList with where and use contains
code snippet
Future<List<Post>> _getALlPosts(String text) async {
List<Post> posts = fooList
.where((element) =>
element.title.contains(text) || element.body.contains(text))
.toList();
return posts;
}
working demo
full code
import 'dart:math';
import 'package:flappy_search_bar/flappy_search_bar.dart';
import 'package:flappy_search_bar/scaled_tile.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Post {
final String title;
final String body;
Post(this.title, this.body);
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final SearchBarController<Post> _searchBarController = SearchBarController();
bool isReplay = false;
List<Post> fooList = [
Post('one', '1'),
Post('two', '2'),
Post('three', '3'),
Post('four', '4'),
Post('five', '5')
];
Future<List<Post>> _getALlPosts(String text) async {
List<Post> posts = fooList
.where((element) =>
element.title.contains(text) || element.body.contains(text))
.toList();
return posts;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SearchBar<Post>(
minimumChars: 1,
searchBarPadding: EdgeInsets.symmetric(horizontal: 10),
headerPadding: EdgeInsets.symmetric(horizontal: 10),
listPadding: EdgeInsets.symmetric(horizontal: 10),
onSearch: _getALlPosts,
searchBarController: _searchBarController,
placeHolder: Center(
child: Text(
"PlaceHolder",
style: TextStyle(fontSize: 30),
)),
cancellationWidget: Text("Cancel"),
emptyWidget: Text("empty"),
onCancelled: () {
print("Cancelled triggered");
},
mainAxisSpacing: 10,
onItemFound: (Post post, int index) {
return Container(
color: Colors.lightBlue,
child: ListTile(
title: Text(post.title),
isThreeLine: true,
subtitle: Text(post.body),
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Detail()));
},
),
);
},
),
),
);
}
}
class Detail extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
Text("Detail"),
],
),
),
);
}
}

Flutter rebuild parent widget

I need help. I have a Dropdown widget in LanguageDropdown class, where the user can select the language. And the widget is inside a settings page widget in Settings class. The language changes on other pages, but not on current one. How can I rebuild that specific page, so the language changes on this one also?
See the code below
import 'package:jptapp/features/settings/change_language/app_localization.dart';
class LanguageDropDown extends StatefulWidget {
#override
_LanguageDropDownState createState() {
return _LanguageDropDownState();
}
}
class _LanguageDropDownState extends State<LanguageDropDown> {
String _value = allTranslations.currentLanguage;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
items: [
DropdownMenuItem<String>(
child: Text('English'),
value: 'en',
),
DropdownMenuItem<String>(
child: Text('Magyar'),
value: 'hu',
),
DropdownMenuItem<String>(
child: Text('Srpski'),
value: 'rs',
),
],
onChanged: (String value) {
setState(() async{
_value = value;
await allTranslations.setNewLanguage(_value);
});
},
hint: Text(_value),
value: _value,
);
}
}
import 'package:jptapp/core/constants/colors.dart';
import 'package:jptapp/features/settings/change_language/app_localization.dart';
import 'package:jptapp/features/settings/widgets/widgets.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: MyColors.appBarColor,
title: Text(
allTranslations.text('settings'),
),
),
body: ListView(
children: ListTile.divideTiles(
context: context,
tiles: [
ListTile(
trailing: ThemeChangerAnimationButton(),
title: Text(
allTranslations.text('darkmode'),
),
),
ListTile(
trailing: LanguageDropDown(),
title: Text(
allTranslations.text('language'),
),
),
],
).toList(),
),
);
}
}
I'm not sure this will work but try this:
import 'package:flutter/material.dart';
import 'package:jptapp/features/settings/change_language/app_localization.dart';
class LanguageDropDown extends StatefulWidget {
#override
_LanguageDropDownState createState() {
return _LanguageDropDownState();
}
}
class _LanguageDropDownState extends State<LanguageDropDown> {
String _value = allTranslations.currentLanguage;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
items: [
DropdownMenuItem<String>(
child: Text('English'),
value: 'en',
),
DropdownMenuItem<String>(
child: Text('Magyar'),
value: 'hu',
),
DropdownMenuItem<String>(
child: Text('Srpski'),
value: 'rs',
),
],
onChanged: (String value) {
setState(() async {
_value = value;
await allTranslations.setNewLanguage(_value);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Settings()
));
});
},
hint: Text(_value),
value: _value,
);
}
}