hi i have json like this:
"data": {
"list_item": [
{
"item": "1",
"item_date": "1669189813143566825",
"item_id": "0",
"item_info": {},"
"item_status":"on",
}]}
this class with sample table worked for me!but my table in app used paginated table and not worked in.
class TableSamleNew extends StatefulWidget {
const TableSamleNew({Key? key}) : super(key: key);
#override
State<TableSamleNew> createState() => _TableSamleNewState();
}
class _TableSamleNewState extends State<TableSamleNew> {
final getListController = Get.put(GetListController());
late List<ListItem>? listItem=getListController.getListClient!.data!.listItem;
#override
Widget build(BuildContext context) {
return Scaffold(
body: GetBuilder<GetListController>(
builder: (_) => getListController.isLoading
? const Padding(
padding: EdgeInsets.only(top:50),
child: Center(child: CircularProgressIndicator()),
): DataTable(columns: [
DataColumn(label: Text("1")),
DataColumn(label: Text("1")),
DataColumn(label: Text("1")),
DataColumn(label: Text("1")),
DataColumn(label: Text("1"))
],rows: listItem!.map<DataRow>((e) => DataRow(cells: [
DataCell(Text(e.itemInfo!.clientMobile.toString())),
DataCell(Text(e.itemId.toString())),
DataCell(Text(e.itemId.toString())),
DataCell(Text("")),
DataCell(Text("")),
])).toList()),
),
);
}
}
this is my main table and not showing data..
table with paginated and sort data and search with one field in table but output showing me null
class DataTableWithSortTest extends StatefulWidget {
const DataTableWithSortTest({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<DataTableWithSortTest> createState() => _DataTableWithSortTestState();
}
class _DataTableWithSortTestState extends State<DataTableWithSortTest> {
final getListController = Get.put(GetListController());
late List<ListItem>? listItem=getListController.getListClient!.data!.listItem;
bool sort = true;
onsortColum(int columnIndex, bool ascending) {
if (columnIndex == 0) {
if (ascending) {
listItem!.sort((a, b) => a.itemStatus!.compareTo(b.itemStatus!));
} else {
listItem!.sort((a, b) => b.itemStatus!.compareTo(a.itemStatus!));
}
}
}
#override
void initState() {
listItem = listItem!.cast<ListItem>();
super.initState();
}
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
print(listItem);
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
borderRadius: const BorderRadius.all(Radius.circular(10)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: Theme(
data: ThemeData.light()
.copyWith(cardColor: Theme.of(context).canvasColor),
child: PaginatedDataTable(
sortColumnIndex: 0,
sortAscending: sort,
header: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(12)),
child: TextField(
controller: controller,
decoration: const InputDecoration(
hintText: "search with name"),
onChanged: (value) {
setState(() {
listItem = listItem!
.where((element) =>
element.itemStatus!.contains(value))
.toList();
});
},
),
),
source: RowSource(
listItem: listItem,
count: listItem?.length,
),
rowsPerPage: 5,
columnSpacing: 5,
columns: [
DataColumn(
label: const Text(
"1",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
onSort: (columnIndex, ascending) {
setState(() {
sort = !sort;
});
// onsortColum(columnIndex, ascending);
}),
const DataColumn(//
label: Text(
"2",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
const DataColumn(
label: Text(
"3",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
const DataColumn(
label: Text(
"4",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
const DataColumn(
label: Text(
"5",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
],
),
)),
const SizedBox(height: 20),
],
),
),
)),
);
}
}
class RowSource extends DataTableSource {
var listItem;
final count;
RowSource({
required this.listItem,
required this.count,
});
#override
DataRow? getRow(int index) {
if (index < rowCount) {
return recentFileDataRow(listItem![index]);
} else
return null;
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => count;
#override
int get selectedRowCount => 0;
}
DataRow recentFileDataRow(var listItem) {
return const DataRow(
cells: [
DataCell(Text("")),
DataCell(Text("")),
DataCell(Text("")),
DataCell(Text("")),
DataCell(Text("")),
],
);
}
You need to define these variable out of build methode:
late List<ListItem>? listItem =getListController.getListClient!.data!.listItem;
every time the widget rebuild you variable redefine and became empty.
class TableSamleNew extends StatefulWidget {
const TableSamleNew({Key? key}) : super(key: key);
#override
State<TableSamleNew> createState() => _TableSamleNewState();
}
class _TableSamleNewState extends State<TableSamleNew> {
final getListController = Get.put(GetListController());
ValueNotifier<List<ListItem>> listItemNotifier = ValueNotifier([]);
#override
Widget build(BuildContext context) {
listItemNotifier.value=getListController.getListClient!.data!.listItem;
return Scaffold(
body: ValueListenableBuilder(
valueListenable: listItemNotifier,
builder:(context,List<ListItem> items, child) =>
DataTable(columns: [
DataColumn(label: Text("1")),
DataColumn(label: Text("1")),
DataColumn(label: Text("1")),
DataColumn(label: Text("1")),
DataColumn(label: Text("1"))
],rows: items.map<DataRow>((e) => DataRow(cells: [
DataCell(Text(e.itemId.toString())),
DataCell(Text(e.itemId.toString())),
DataCell(Text(e.itemId.toString())),
DataCell(Text(e.itemId.toString())),
DataCell(Text(e.itemId.toString())),
])).toList()),
);
);
}
}
try to use ValueNotifier
Related
I have a widget FilterSearchBar used in 2 others widgets. The first one HomeScreen contains a list of Team. In this one, I would like to display the full list of teams when the user clicks on the suffix icon in the searchbar. In the second one PlayerScreen I have a default Text widget and a list of Player appears when the user type something in the search bar and I would like to display the default Text widget when he clicks on the suffix icon. How can I do that ?
Here is the code.
Team
class Team {
final int id;
final String name;
Team({required this.id, required this.name});
static List<Team> getNFCTeam() => [
Team(id: 0, name: "Arizona Cardinals"),
Team(id: 1, name: "Atlanta Falcons"),
Team(id: 2, name: "Carolina Panthers"),
Team(id: 3, name: "Chicago Bears"),
Team(id: 4, name: "Dallas Cowboys"),
Team(id: 5, name: "Detroit Lions"),
Team(id: 6, name: "Green Bay Packers"),
Team(id: 7, name: "Los Angeles Rams"),
Team(id: 8, name: "Minnesota Vikings"),
Team(id: 9, name: "New Orleans Saints"),
Team(id: 10, name: "New York Giants"),
Team(id: 11, name: "Philadelphia Eagles"),
Team(id: 12, name: "San Francisco 49ers"),
Team(id: 13, name: "Seattle Seahawks"),
Team(id: 14, name: "Tampa Bay Buccaneers"),
Team(id: 15, name: "Washington Commanders"),
];
}
Player
class Player {
final int id;
final String name;
final number;
final position;
Player({required this.id, required this.name, required this.number, required this.position});
static List<Player> getPlayer() => [
Player(id: 0, name: "Brock Purdy", number: "#13", position: "QB"),
Player(id: 1, name: "Christian McCaffrey", number: "#23", position: "RB"),
Player(id: 2, name: "George Kittle", number: "#85", position: "TE"),
Player(id: 3, name: "Deebo Samuel", number: "#19", position: "WR"),
Player(id: 4, name: "Nick Bosa", number: "#97", position: "DL"),
Player(id: 5, name: "Fred Warner", number: "#54", position: "LB"),
];
}
FilterSearchBar
class FilterSearchBar extends StatefulWidget {
final String filterType;
final TextEditingController searchController;
final TextInputType keyboard;
final ValueChanged<String>? onChanged;
const FilterSearchBar({Key? key, required this.filterType, required this.searchController,
required this.keyboard, this.onChanged}) : super(key: key);
#override
State<FilterSearchBar> createState() => _FilterSearchBarState();
}
class _FilterSearchBarState extends State<FilterSearchBar> {
bool isClearClicked = false;
#override
void initState() {
widget.searchController.addListener(() {
setState(() {
isClearClicked = widget.searchController.text.isNotEmpty;
});
});
super.initState();
}
#override
void dispose() {
widget.searchController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: TextFormField(
keyboardType: widget.keyboard,
controller: widget.searchController,
onChanged: widget.onChanged,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(90),
),
borderSide: BorderSide(
color: Colors.grey,
),
),
prefixIcon: Icon(
Icons.search,
color: Colors.grey,
),
hintText: widget.filterType,
hintStyle: TextStyle(
color: Colors.grey,
fontSize: 16,
fontWeight: FontWeight.bold,
),
suffixIcon: isClearClicked
? IconButton(
onPressed: () {
clearSearchBar();
},
icon: Icon(
Icons.clear,
color: Colors.grey,
),
)
: null,
filled: true,
fillColor: Colors.white,
),
),
);
}
void clearSearchBar() {
widget.searchController.clear();
}
}
HomeScreen
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TextEditingController searchController = TextEditingController();
List<Team> allTeams = Team.getNFCTeam();
List<Team> suggestions = Team.getNFCTeam();
List<Team> teams = Team.getNFCTeam();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("NFC"),
),
body: Column(
children: [
FilterSearchBar(
filterType: "Search team",
searchController: searchController,
keyboard: TextInputType.text,
onChanged: searchTeam,
),
showAllTeams(),
],
),
);
}
Widget showAllTeams() => Expanded(
child: ListView.builder(
itemCount: teams.length,
itemBuilder: (context, index) {
final team = teams[index];
return Column(
children: [
ListTile(
title: Padding(
padding: EdgeInsets.all(10),
child: Row(
children: [
Text(
team.name,
style: TextStyle(
color: Colors.black,
),
),
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PlayerScreen(team: team.name),
),
);
},
),
Divider(
height: 1,
color: Colors.grey,
),
],
);
},
),
);
void searchTeam(String query) {
suggestions = allTeams.where((team) {
final teamName = team.name.startsWith(query.toLowerCase());
return teamName;
}).toList();
setState(() => teams = suggestions.isEmpty ? allTeams : suggestions);
}
}
PlayerScreen
class PlayerScreen extends StatefulWidget {
final String team;
const PlayerScreen({Key? key, required this.team}) : super(key: key);
#override
State<PlayerScreen> createState() => _PlayerScreenState();
}
class _PlayerScreenState extends State<PlayerScreen> {
TextEditingController searchController = TextEditingController();
List<Player> allPayers = Player.getPlayer();
List<Player> suggestions = Player.getPlayer();
List<Player> players = Player.getPlayer();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.team),
),
body: Container(
color: Colors.grey,
child: Column(
children: [
FilterSearchBar(
filterType: "Search player",
searchController: searchController,
keyboard: TextInputType.text,
onChanged: searchPlayer,
),
searchController.text.isNotEmpty ? showAllPlayers() : Center(
child: Text(
"No player found",
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
)
);
}
Widget showAllPlayers() => Expanded(
child: ListView.builder(
itemCount: players.length,
itemBuilder: (context, index) {
final player = players[index];
return Column(
children: [
ListTile(
title: Padding(
padding: EdgeInsets.all(10),
child: Row(
children: [
Text(
player.number,
style: TextStyle(
color: Colors.black,
),
),
const SizedBox(width: 5,),
Text(
player.position,
style: TextStyle(
color: Colors.black,
),
),
const SizedBox(width: 5,),
Text(
player.name,
style: TextStyle(
color: Colors.black,
),
),
const SizedBox(width: 5,),
],
),
),
),
Divider(
height: 1,
color: Colors.grey,
),
],
);
},
),
);
void searchPlayer(String query) {
suggestions = allPayers.where((player) {
final playerName = player.name.startsWith(query.toLowerCase());
return playerName;
}).toList();
setState(() => players = suggestions.isEmpty ? allPayers : suggestions);
}
}
I'm a total beginner in Flutter. I try to integrate a textfield filter for my table, but the table is not filtered, but remains unchanged. I added a Provider because I need the current table of Students. after that the Table can't be filtered anymore. Can anyone help me?
here is my code:
class ResultPage extends StatefulWidget {
const ResultPage({Key? key}) : super(key: key);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
List<User>? myData = [];
List<User>? filterData;
_getData(BuildContext context){
myData = Provider.of<LoginService>(context).getStudentsList();
filterData = Provider.of<LoginService>(context).getStudentsList();
}
bool sort = true;
#override
void initState() {
filterData = myData;
super.initState();
}
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
_getData(context);
return Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: Theme(
data: ThemeData.light()
.copyWith(cardColor: Theme.of(context).canvasColor),
child: PaginatedDataTable(
sortColumnIndex: 0,
sortAscending: sort,
header: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(12)),
child: TextField(
controller: controller,
decoration: const InputDecoration(
hintText: "Enter name to filter"),
onChanged: (value) {
setState(() {
myData = filterData!
.where(
(element) => element.getName.contains(value))
.toList();
});
},
onSubmitted: (value) {
setState(() {
FocusScope.of(context).unfocus();
});
},
),
),
source: RowSource(
myData: myData,
count: myData!.length,
),
rowsPerPage: 16,
columnSpacing: 8,
columns: const [
DataColumn(
label: Text(
"Schüler",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
DataColumn(
label: Text(
"Anzahl Spiele",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
DataColumn(
label: Text(
"Score",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
],
),
)),
const SizedBox(height: 20),
],
),
)
);
}
}
class RowSource extends DataTableSource {
var myData;
final count;
RowSource({
required this.myData,
required this.count,
});
#override
DataRow? getRow(int index) {
if (index < rowCount) {
return recentFileDataRow(myData![index]);
} else {
return null;
}
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => count;
#override
int get selectedRowCount => 0;
}
DataRow recentFileDataRow(User data) {
return DataRow(
cells: [
DataCell(Text(data.getName)),
DataCell(Text(data.getSolvedGames().toString())),
DataCell(Text(data.getScore().toString())),
],
);
}
With my code the table always remains unchanged.
I'm trying to load content (Widget) dynamically (by a index).
However if I not use List all is working as expected:
class _MyHomePageState extends State<MyHomePage> {
final titleController = TextEditingController();
String titolo = '';
late Widget display; //This is the future widget
//List<Widget> display = <Widget>[];
//int displayIndex = 1;
initialize it:
#override
Widget build(BuildContext context) {
//display.add(calculator());
display = calculator();
and use it on body property:
body: display,
When I try to use a list:
class _MyHomePageState extends State<MyHomePage> {
final titleController = TextEditingController();
String titolo = '';
//late Widget display;
List<Widget> display = <Widget>[];
//int displayIndex = 1;
initialize:
#override
Widget build(BuildContext context) {
display.add(calculator());
//display = calculator();
and use it on body property:
body: display.first,
I get this error:
Exception has occurred.
_TypeError (type 'TabContainer' is not a subtype of type 'List' of 'function result')
Please note that TabContainer is the first Widget of calculator():
Widget calculator() => TabContainer(
selectedTextStyle: const TextStyle(
fontFamily: 'ThousandSunny',
This the entire code:
import 'package:cookedcalories/utils.dart';
import 'package:flutter/material.dart';
import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:tab_container/tab_container.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cooked Calories & Macros',
theme: ThemeData(
primarySwatch: Colors.pink,
),
home: const MyHomePage(title: 'Cooked Calories & Macros'),
);
}
}
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 titleController = TextEditingController();
String titolo = '';
//late Widget display;
List<Widget> display = <Widget>[];
//int displayIndex = 1;
#override
void initState() {
titleController.addListener(() => setState(() {}));
super.initState();
}
#override
Widget build(BuildContext context) {
display.add(calculator());
//display = calculator();
return Scaffold(
backgroundColor: Colors.yellow,
bottomNavigationBar: ConvexAppBar(
style: TabStyle.react,
items: const [
TabItem(icon: Icons.info_outline),
TabItem(icon: Icons.receipt_outlined),
TabItem(icon: Icons.calculate_outlined),
TabItem(icon: Icons.monetization_on_outlined),
TabItem(icon: Icons.settings_outlined),
],
initialActiveIndex: 1,
onTap: (int i) => print('click index=$i'),
),
appBar: AppBar(
title: Text(
widget.title,
style: const TextStyle(
fontFamily: 'ThousandSunny',
fontSize: 35,
),
),
),
body: display.first,
);
}
Widget calculator() => TabContainer(
selectedTextStyle: const TextStyle(
fontFamily: 'ThousandSunny',
fontSize: 35,
fontWeight: FontWeight.bold),
unselectedTextStyle: const TextStyle(
fontFamily: 'ThousandSunny',
fontSize: 35,
),
color: Colors.white,
radius: 50,
tabEdge: TabEdge.left,
tabs: const [
'A',
'B',
'C',
],
children: [
Align(
alignment: Alignment.topCenter,
child: SingleChildScrollView(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(5, 30, 0, 0),
child: createTitleField()),
),
const Padding(
padding: EdgeInsets.fromLTRB(10, 30, 5, 0),
child: Image(
width: 50,
height: 50,
image: AssetImage('assets/images/clean.png')),
),
],
),
],
)),
),
const Text('Child 2'),
const Text('Child 3'),
],
);
Widget createTitleField() => TextFormField(
style: const TextStyle(
fontFamily: 'ThousandSunny',
fontSize: 25,
),
controller: titleController,
validator: (value) {
if (value == null || value.trim().isEmpty) {
showSnackBar(
context,
"Attenzione: non hai inserito il Titolo dell'oggetto.",
Colors.pinkAccent.shade400);
return 'Inserisci il Titolo per questo oggetto';
} else if (value.trim().length < 3) {
showSnackBar(
context,
"Attenzione: Il Titolo deve contenere almeno 3 caratteri.",
Colors.pinkAccent.shade400);
return 'Lunghezza minima 3 caratteri';
} else if (value.trim().length > 30) {
showSnackBar(
context,
"Attenzione: Il Titolo non può essere più lungo di 30 caratteri.",
Colors.pinkAccent.shade400);
return 'Lunghezza massima 30 caratteri';
}
titolo = value;
return null;
},
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: 'Nome Ricetta',
labelText: 'Nome Ricetta',
labelStyle: const TextStyle(
fontFamily: 'ThousandSunny',
fontSize: 30,
),
hintStyle: const TextStyle(
fontFamily: 'ThousandSunny',
fontSize: 25,
),
suffixIcon: titleController.text.isEmpty
? Container(
width: 0,
)
: IconButton(
onPressed: () => titleController.clear(),
icon: const Icon(Icons.close),
)),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
);
}
Try Stop project, run flutter pub get and start project again.
I'm developing a fill-in-the-blanks quiz app.
There are 5 question statements in one quiz, but when I move on to the next question statement, the value entered in the text field remains. Could you please tell me what are the possible causes?
class PlayGame extends StatefulWidget {
final List document;
List correctList = [];
PlayGame({Key? key, required this.document}) : super(key: key);
#override
State<PlayGame> createState() => _PlayGameState();
}
class _PlayGameState extends State<PlayGame> {
int quizNum = 0;
int quizCount = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Center(
child: Text(
"$quizCount/5",
style: const TextStyle(
fontSize: 25,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold),
),
),
actions: [
Row(
children: [
IconButton(
onPressed: () {
setState(
() {
if (quizNum < 4) {
quizNum += 1;
quizCount += 1;
} else if (quizNum == 4) {
print(widget.correctList.length);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Result()),
);
}
},
);
},
icon: const Icon(
Icons.arrow_circle_right_outlined,
size: 40,
),
),
const SizedBox(
width: 10,
)
],
)
],
automaticallyImplyLeading: false,
),
body: SizedBox(
height: double.infinity,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(bottom: 30.0),
child: TextWithBlanks(
text: widget.document[quizNum],
correctList: widget.correctList),
),
),
),
);
}
}
This is the code I was taught here. Words surrounded by "{}" are BlankWord.
class TextWithBlanks extends StatefulWidget {
final String text;
static final regex = RegExp("(?={)|(?<=})");
List correctList = [];
TextWithBlanks({Key? key, required this.text, required this.correctList})
: super(key: key);
#override
State<TextWithBlanks> createState() => _TextWithBlanksState();
}
class _TextWithBlanksState extends State<TextWithBlanks> {
#override
Widget build(BuildContext context) {
final split = widget.text.split(TextWithBlanks.regex);
return Padding(
padding: const EdgeInsets.only(top: 30.0, right: 30.0, left: 30.0),
child: Text.rich(
TextSpan(
style: const TextStyle(fontSize: 15, height: 3.0),
children: <InlineSpan>[
for (String text in split)
text.startsWith('{')
? WidgetSpan(
child: blankWord(text.substring(1, text.length - 1),
widget.correctList),
)
: TextSpan(text: text),
],
),
),
);
}
}
This is the BlankWord.
class _blankWordState extends State<blankWord> {
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.answerWidth,
child: TextField(
maxLines: null,
cursorColor: Colors.grey,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
autofocus: false,
maxLength: widget.answerLength + 5,
onChanged: (enterWord) {
widget.value = enterWord;
if (enterWord == widget.answer) {
if (widget.answerBool == false) {
widget.answerBool = true;
widget.correctList.add(widget.answer);
}
} else {
if (widget.answerBool == true) {
widget.answerBool = false;
widget.correctList.remove(widget.answer);
}
}
},
decoration: InputDecoration(
counterText: "",
hintText: widget.answerHint,
hintStyle: const TextStyle(color: Colors.grey, fontSize: 12),
),
),
);
}
}
When you update the page by changing the quiz number also reset the value that you are sending to the blank widget. When the blank widget is updated the widget.value is being updated, and that value stays in the class and when a new blank widget is added the value is being sent to the blank widget again I think
widget.value = enterWord;
I am using DropdownButton and I am facing the following issue. I'm using a checkbox in elements, but when I click on an element, I don't get a checkmark indicating that the checkbox has been clicked. As a result, I need to close and reopen it, and then I will see the changes that were clicked on the "checkbox". The second problem is that when I select one element, all elements are selected for me. As a final result, I need to get so that I can select an element and the checkbox is immediately marked, if 2 elements are needed, then two, and so on. Tell me how to fix these problems, I will be grateful for the help?
dropdown
class DropdownWidget extends StatefulWidget {
List<String> items;
SvgPicture? icon;
double width;
DropdownWidget({
Key? key,
required this.items,
required this.icon,
required this.width,
}) : super(key: key);
#override
State<DropdownWidget> createState() => _DropdownWidgetState();
}
class _DropdownWidgetState extends State<DropdownWidget> {
String? selectedValue;
bool isChecked = false;
#override
void initState() {
super.initState();
if (widget.items.isNotEmpty) {
selectedValue = widget.items[1];
}
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
Checkbox(
checkColor: Colors.black,
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
dropdownWidth: 140,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
),
color: constants.Colors.greyDark,
),
selectedItemBuilder: (context) {
return widget.items.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
items
final List<String> items = const [
"All EV's",
'Main EV',
'<EV2>',
];
I hope this example explains the concept. For simplcity I made simple a new file, run it and see the results:
Then main idea in two lists, _checkList contain values of the CheckBox and _selectedList handles the main dropdown widget to show the selection.
Feel free to ask any questions and I'm happy to help
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const AnimationDemo(number: 5);
}
}
class AnimationDemo extends StatefulWidget {
const AnimationDemo({Key? key, this.number = 2}) : super(key: key);
final int number;
#override
State<AnimationDemo> createState() => _AnimationDemoState();
}
class _AnimationDemoState extends State<AnimationDemo> {
late List<bool> _checkList;
late List<int> _selectedIndex;
bool _isOpen = false;
#override
void initState() {
_checkList = List.filled(widget.number, false);
_selectedIndex = <int>[];
super.initState();
}
List<DropDownItem> generateItems() {
var tmp = <DropDownItem>[];
for (var i = 0; i < _checkList.length; i++) {
tmp.add(DropDownItem(
isChecked: _checkList[i],
onChanged: (value) {
setState(() {
_checkList[i] = value!;
if (value && !_selectedIndex.contains(i)) {
_selectedIndex.add(i);
} else {
_selectedIndex.remove(i);
}
});
},
));
}
return tmp;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text((_selectedIndex.isEmpty)
? 'Nothing Selected'
: _selectedIndex.join(',')),
),
GestureDetector(
onTap: () {
setState(() {
_isOpen = !_isOpen;
});
},
child: const Icon(Icons.arrow_downward),
),
],
),
AnimatedOpacity(
opacity: (_isOpen) ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: Column(
mainAxisSize: MainAxisSize.min,
children: generateItems(),
),
)
],
),
);
}
}
class DropDownItem extends StatelessWidget {
final bool isChecked;
final Function(bool?)? onChanged;
const DropDownItem({Key? key, this.onChanged, this.isChecked = false})
: super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
const Expanded(child: Text('Demo item')),
Checkbox(value: isChecked, onChanged: onChanged)
],
);
}
}
Here's how to achieve the Multiselect dropdown with DropdownButton2:
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}
Also, I've added it as an example to the package doc "Example 4" so you can get back to it later.