Flutter web: How to make horizontal scroll in stepper form? - android

I am trying to make a flutter web form using stepper and i am doing the experiment for small size screen. I have done the vertical scroll using the physics: ClampingScrollPhysics() method. However, I am unable to make horizontal scroll inside the stepper step. I want to make the radio button horizontally scroll able so that the error message will hide and i the text goes out of the screen, the user can scroll to that part. I already used SingleChildCcrollView(crollDirection: Axis.horizontal) but it didn't work. The image is
The code for the flutter program is as below: -
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Stepper Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Stepper Tutorial'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _currentStep = 0;
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
TextEditingController addressController = TextEditingController();
List<String> demoList = [];
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
),
Expanded(
child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
child: Stepper(
physics: ClampingScrollPhysics(),
steps: _mySteps(),
currentStep: this._currentStep,
onStepTapped: (step) {
setState(
() {
this._currentStep = step;
},
);
},
onStepContinue: () {
setState(
() {
if (this._currentStep < this._mySteps().length - 1) {
this._currentStep = this._currentStep + 1;
}
},
);
},
onStepCancel: () {
setState(
() {
if (this._currentStep > 0) {
this._currentStep = this._currentStep - 1;
} else {
this._currentStep = 0;
}
},
);
},
),
),
),
demoList.isEmpty
? Text("")
: Column(
children: demoList.map((e) {
return Text(e);
}).toList(),
),
ElevatedButton(
onPressed: () {
demoList = [];
viewList();
},
child: Text("Click to see List"),
),
],
),
);
}
viewList() {
if (nameController.text.isEmpty ||
emailController.text.isEmpty ||
addressController.text.isEmpty) {
setState(
() {
if (nameController.text.isEmpty) {
demoList.add("Name field is empty");
} else if (emailController.text.isEmpty) {
demoList.add("Email field is Empty");
} else if (addressController.text.isEmpty) {
demoList.add("Address field is empty");
}
},
);
} else {
demoList.add(nameController.text);
demoList.add(emailController.text);
demoList.add(addressController.text);
setState(
() {
demoList = demoList;
},
);
}
}
List<Step> _mySteps() {
List<Step> _steps = [
Step(
title: Text('Name'),
content: TextField(
controller: nameController,
),
isActive: _currentStep >= 0,
),
Step(
title: Text('Email'),
content: TextField(
controller: emailController,
),
isActive: _currentStep >= 1,
),
Step(
title: Text('Address'),
content: TextField(
controller: addressController,
),
isActive: _currentStep >= 2,
),
Step(
title: Text('Number'),
content: Row(
children: <Widget>[
SingleChildScrollView(
physics: ClampingScrollPhysics(),
),
SafeArea(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Form(
child: Row(
children: <Widget>[
Radio(
value: "1",
),
Text("1"),
Radio(
value: "2",
),
Text("2"),
Radio(
value: "3",
),
Text("3"),
Radio(
value: "4",
),
Text("4"),
Radio(
value: "5",
),
Text("5"),
Radio(
value: "6",
),
Text("6"),
Radio(
value: "7",
),
Text("7"),
Radio(
value: "8",
),
Text("8"),
Radio(
value: "9",
),
Text("9"),
],
),
),
),
)
],
),
isActive: _currentStep >= 2,
),
];
return _steps;
}
}

You can just use a ListView and set the scrollDirection to horizontal. The Container is there because it needs something to give it a size.
Step(
title: Text('Number'),
content: Container(
height: 100,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Radio(
value: "1",
),
Center(child: Text("1")),
Radio(
value: "2",
),
Center(child: Text("1")),
Radio(
value: "3",
),
Center(child: Text("3")),
Radio(
value: "4",
),
Center(child: Text("4")),
Radio(
value: "5",
),
Center(child: Text("5")),
Radio(
value: "6",
),
Center(child: Text("6")),
Radio(
value: "7",
),
Center(child: Text("7")),
Radio(
value: "8",
),
Center(child: Text("8")),
Radio(
value: "9",
),
Center(child: Text("9")),
],
),
),
isActive: _currentStep >= 2,
),

Related

Json is not responding

i am trying to initialize json data in my widget but for some reason, it is not responding. i am pretty new to dealing with json called locally and this is one of them. i have already done all the necessary things like creating the file to put the data and passing it through the pubspec. still it is not responding. here is the json data
[
{
"_id":"636e0ce55270d648e9a5248a",
"index":0,
"guid":"58e73438-27fa-48bf-8127-ff4e42beaac5",
"isActive":true,
"price":"$252.77",
"name":"James Lewis Blue Ledis",
"type":"dress",
"image":"https://images.unsplash.com/photo-1539008835657-9e8e9680c956?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"
},
{
"_id":"636e0ce573d4e1ce44e5a5a9",
"index":1,
"guid":"e1d93cfe-b15a-4969-97e0-3b6b9ae967d0",
"isActive":false,
"price":"$289.88",
"name":"Blue FLower Shoe",
"type":"apparel",
"image":"https://images.unsplash.com/photo-1543163521-1bf539c55dd2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80"
},
{
"_id":"636e0ce522bd392da7b43d2e",
"index":2,
"guid":"0ee56032-db50-44c3-9234-5e213b8fde22",
"isActive":false,
"price":"$452.81",
"name":"Yellow Blight Bag",
"type":"bag",
"image":"https://images.pexels.com/photos/934673/pexels-photo-934673.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"recommended":true
},
{
"_id":"636e0ce5fdf98a105a5c14cb",
"index":3,
"guid":"fee6217c-ee7f-4e3e-91cc-24dfd91d6cfc",
"isActive":true,
"price":"$244.91",
"name":"Black meter dress",
"type":"dress",
"image":"https://images.unsplash.com/photo-1550639525-c97d455acf70?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=726&q=80"
},
{
"_id":"636e0ce5036de010a96ab185",
"index":4,
"guid":"2d9e8b22-90c1-4979-b904-2cc164626e10",
"isActive":false,
"price":"$335.17",
"name":"Dynamic Pink Lobre",
"type":"bag",
"image":"https://images.unsplash.com/photo-1566150905458-1bf1fc113f0d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1171&q=80"
},
{
"_id":"636e0ce52e2a60eed71c79b6",
"index":5,
"guid":"32db02a5-a12d-4f3e-a601-787211734ab1",
"isActive":false,
"price":"$414.69",
"name":"Gucci Flems Onyx",
"type":"bag",
"image":"https://images.unsplash.com/photo-1548036328-c9fa89d128fa?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1169&q=80"
},
{
"_id":"636e0ce52f14c39bb8366650",
"index":6,
"recommended":true,
"guid":"1a0c388c-2ac7-4a49-85ba-50b12bc08f28",
"isActive":true,
"price":"$293.63",
"name":"705 California",
"type":"apparel",
"image":"https://images.unsplash.com/photo-1618354691229-88d47f285158?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=715&q=80"
},
{
"_id":"636e0ce56b57e56f54676302",
"index":7,
"guid":"956527b1-c9d8-4c18-a6ef-e4b1dcd76640",
"isActive":false,
"price":"$293.57",
"name":"Mid-week flavors",
"type":"apparel",
"image":"https://images.unsplash.com/photo-1560769629-975ec94e6a86?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80"
},
{
"_id":"636e0ce56c0ed15b28297895",
"index":8,
"guid":"119db62a-eaba-493f-b73a-5dcba04b69c1",
"isActive":false,
"price":"$348.63",
"name":"Hermes Coysx",
"type":"bag",
"image":"https://images.unsplash.com/photo-1594223274512-ad4803739b7c?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=757&q=80"
},
{
"_id":"636e0ce58d2cbb1e636f1829",
"index":9,
"guid":"40011d30-d06d-4a72-b119-0826dc79c138",
"isActive":true,
"price":"$337.91",
"name":"Kirsten Gilliam",
"type":"dress",
"image":"https://images.unsplash.com/photo-1543163521-1bf539c55dd2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80"
},
{
"_id":"636e0ce5713679af9a884699",
"index":10,
"guid":"f5dbfba4-fbe2-475b-98fc-36ff42daad91",
"isActive":false,
"price":"$436.62",
"recommended":true,
"name":"Outcast white",
"type":"t-shirt",
"image":"https://images.unsplash.com/photo-1527719327859-c6ce80353573?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80"
},
{
"_id":"636e0ce5578fa1d92624204f",
"index":11,
"guid":"805df707-3833-4e5f-9e09-0c59053750cb",
"isActive":false,
"price":"$493.15",
"name":"Peace Skull",
"type":"t-shirt",
"image":"https://images.unsplash.com/photo-1503341504253-dff4815485f1?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"
},
{
"_id":"636e0ce5bd29b6bd570aef00",
"index":12,
"guid":"32e75d5c-ea59-4c23-8d85-29dd37040a7d",
"isActive":false,
"price":"$350.71",
"name":"Louis Vuiton Brown bag",
"type":"bag",
"image":"https://images.pexels.com/photos/3661622/pexels-photo-3661622.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
},
{
"_id":"636e0ce505794be5900eb9ad",
"index":13,
"guid":"44aa2a9a-e1c9-4004-b681-ce246e5a8ee4",
"isActive":true,
"price":"$271.21",
"name":"Impulso Supreme",
"type":"t-shirt",
"recommended":true,
"image":"https://images.unsplash.com/photo-1627933540891-1fb6a397c89b?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80"
}
]
and this is where it is being called
class ExploreCollections extends StatefulWidget {
const ExploreCollections({Key? key}) : super(key: key);
#override
State<ExploreCollections> createState() => _ExploreCollectionsState();
}
class _ExploreCollectionsState extends State<ExploreCollections> {
final List _items = [];
Future<void> readJson() async{
final String response = await rootBundle.loadString('assets/model/clothes.json');
final data = await json.decode(response);
}
#override
void initState() {
_items.shuffle();
super.initState();
}
int _activeIndex = 0;
final List<Widget> _images = [
Stack(
children: [
Image.asset('assets/images/image 10.png'),
Padding(
padding: const EdgeInsets.only(left: 55.0, top: 230),
child: Text(
'Luxury \n Fashion \n &Accessories'.toUpperCase(),
style: TextStyle(
fontFamily: 'Bodoni',
fontSize: 40,
fontWeight: FontWeight.w500,
color: Colors.grey.shade700
),
),
),
Padding(
padding: const EdgeInsets.only(top: 400.0),
child: Center(
child:SvgPicture.asset('assets/iconImages/Button.svg'),
),
),
],
),
Stack(
children: [
Image.asset('assets/images/leeloo.jpeg'),
],
),
Stack(
children: [
Image.asset('assets/images/ayaka.jpeg'),
],
),
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 5,
child: Column(
children: [
Stack(
children: [
CarouselSlider.builder(
options: CarouselOptions(
viewportFraction: 1,
aspectRatio: 1.8,
height: MediaQuery.of(context).size.height*0.8,
autoPlay: false,
initialPage: 0,
enableInfiniteScroll: false,
enlargeCenterPage: true,
onPageChanged: (index, reason){
setState(() {
_activeIndex = index;
});
}
),
itemCount: _images.length,
itemBuilder: (BuildContext context, int index, int realIndex) {
return GestureDetector(
onTap: (){
Navigator.of(context).pushNamedAndRemoveUntil(BlackScreen.routeName, (route) => false);
},
child: _images[index]);
},
),
Padding(
padding: const EdgeInsets.only(top: 565.0),
child: Center(
child: buildIndicator(),
),
),
],
),
SvgPicture.asset('assets/images/Title.svg'),
const SizedBox(
height: 10,),
TabBar(
indicator: CircleTabIndicator(color: Colors.redAccent, radius: 3),
tabs: [
Tab(child: Text('All',style: TextStyle(color: Colors.grey.shade600),),),
Tab(child: Text('Apparel',style: TextStyle(color: Colors.grey.shade600),),),
Tab(child: Text('Dress',style: TextStyle(color: Colors.grey.shade600),),),
Tab(child: Text('Tshirt',style: TextStyle(color: Colors.grey.shade600),),),
Tab(child: Text('Bag',style: TextStyle(color: Colors.grey.shade600),),),
]
),
Container(
height: 60,
child: TabBarView(
children: [
All(items: _items),
Center(child: Text('Apparel'),),
Center(child: Text('Dress'),),
Center(child: Text('Tshirt'),),
Center(child: Text('Bag'),),
]
),
)
],
),
);
}
i finally passed it to the 'All class'
class All extends StatelessWidget {
final List items;
const All({Key? key, required this.items}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index){
return Text(items[index]['name']);
});
}
}
As a first step you should change the type of your _list variable to Map<String,dynamic>
And change readJson method return type
Future<Map<String,dynamic>> readJson() async{
final String response = await rootBundle.loadString('assets/model/clothes.json');
return await json.decode(response);
}
And call readJson in initState like so
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
readJson().then((value) =>_items = value);
});
super.initState();
}
This should do the trick

Flutter - Side menu (Navigation rail, Navigation drawer)

Can anyone advise me how to design a very specific Side menu in flutter.
It has 2 states
Collapsed (Small but icons are visible.)
Expanded (Big, Icons and text)
When collapsed it is like a Navigation rail. Only icons visible.
But when expanded, it should behave like Navigation drawer. It should blur the rest of the screen, and on click outside of it it should collapse back.
I would appreciate any help.
Thank you
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool is_expanded = false;
int selectedPage = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Row(
children: [
Stack(
children: <Widget>[
Container(
color: Colors.transparent,
margin: EdgeInsets.only(left: 120),
width: MediaQuery.of(context).size.width - 120,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 1, sigmaY: 1),
child: Opacity(
opacity: is_expanded ? 0.3 : 1,
child: Listener(
onPointerDown: (v) {
if (is_expanded) {
is_expanded = false;
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Click blocked'),
),
);
}
},
child: AbsorbPointer(
absorbing: is_expanded,
child: Row(
children: [
Expanded(
child: Container(
color: Colors.white,
child: PageHolder(selectedPage),
),
),
],
),
),
),
),
),
),
AnimatedContainer(
duration: Duration(milliseconds: 120),
height: double.infinity,
width: is_expanded ? 240 : 120,
color: Colors.blueGrey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text(
'Custom drawer',
style: TextStyle(
color: Colors.white,
),
),
],
),
const SizedBox(height: 20),
InkWell(
onTap: () {
setState(() => is_expanded = !is_expanded);
},
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"App",
style: TextStyle(
color: Colors.white,
),
),
Icon(
is_expanded ? Icons.arrow_right : Icons.arrow_left,
color: Colors.white,
)
],
),
),
const SizedBox(height: 20),
InkWell(
onTap: () {
selectedPage = 1;
is_expanded = false;
setState(() {});
},
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"Page 1",
style: TextStyle(
color: Colors.white,
),
),
],
),
),
const SizedBox(height: 20),
InkWell(
onTap: () {
selectedPage = 2;
is_expanded = false;
setState(() {});
},
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"Page 2",
style: TextStyle(
color: Colors.white,
),
),
],
),
),
],
),
),
],
),
],
),
);
}
PageHolder(selectedPage) {
switch (selectedPage) {
case 1:
{
return Page1();
}
case 2:
{
return Page2();
}
default:
{
return Page1();
}
}
}
}
class Page1 extends StatefulWidget {
const Page1({Key? key}) : super(key: key);
#override
State<Page1> createState() => _Page1State();
}
class _Page1State extends State<Page1> {
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Page 1 content',
style: TextStyle(fontSize: 32),),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Test click'),
),
);
},
child: const Text('Test click'))
],
),
);
}
}
class Page2 extends StatefulWidget {
const Page2({Key? key}) : super(key: key);
#override
State<Page2> createState() => _Page2State();
}
class _Page2State extends State<Page2> {
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Page 2 content',
style: TextStyle(fontSize: 32),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Test click'),
),
);
},
child: const Text('Test click'))
],
),
);
}
}```
Solution ^^
include NavigationRail widget in IntrinsicWidth widget
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
drawer: _NavigationRailExample(),
body: Container(),
);
}
}
class _NavigationRailExample extends StatefulWidget {
const _NavigationRailExample({Key? key}) : super(key: key);
_NavigationRailExampleState createState() => _NavigationRailExampleState();
}
class _NavigationRailExampleState extends State<_NavigationRailExample> {
int _selectedIndex = 0;
bool extended =false;
Widget build(BuildContext context) {
return SafeArea(
child: IntrinsicWidth(
child: NavigationRail(
selectedIndex: _selectedIndex,
destinations: _buildDestinations(),
extended: extended,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
),
),
);
}
List<NavigationRailDestination> _buildDestinations() {
return [
NavigationRailDestination(
icon: InkWell(
onTap: () {
setState(() =>
extended = !extended);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("App"),
Icon(extended ? Icons.arrow_right : Icons.arrow_left)
],
),
),
label: Container(width: 0,) ,
),
NavigationRailDestination(
icon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.favorite),
label: Text('Favorites'),
),
NavigationRailDestination(
icon: Icon(Icons.logout),
label: Text('Logout'),
),
];
}
}

GridView in Flutter

I'm working on a flutter project and I made a GridView with images and titles but I want the title to be outside the square, If I make padding they give this error BOTTOM OVERFLOWED BY 32 PIXELS. Any help is highly appreciated.
this is my code :
Card makeDashboardItem(String title, String img, int index) {
return Card(
elevation: 2,
margin: const EdgeInsets.all(3),
child: Container(
child: InkWell(
onTap: () {
setState(() {
isLoading = true;
});
_splitScreen2(index);
},
child: Column(
children: <Widget>[
const SizedBox(height: 10),
Center(
child: Image.asset(img,
alignment: Alignment.center),
),
const SizedBox(height: 1),
Center(
child: Text(
title,
style: const TextStyle(
fontSize: 13,
color: Colors.black,
),
),
),
],
),
),
),
);
}
Check DartPad
The Main problem was overflow so we wrap Expanded widget on Image widget.
Nb: Remove Expanded widget from Image widget You can see the difference
CardWidget
class ItemWidget extends StatelessWidget {
var data;
ItemWidget(this.data, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 150,
child: Card(
child: Column(
children: [
Expanded(
child: Container(
height: 125,
child: Image.network(
data["Image"],
alignment: Alignment.center,
fit: BoxFit.cover,
),
),
),
Center(
child: Text(
data["Name"],
style: TextStyle(fontSize: 12),
))
],
),
),
);
}
}
Fullcode
import 'package:flutter/material.dart';
runApp(
MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),
);
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
var list = [
{
"Name": "ElectroniQues",
"Image":
"https://ecommerce.ccc2020.fr/wp-content/uploads/2020/10/electronic-gadgets.jpeg"
},
{
"Name": "Accessories",
"Image":
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/classic-accessories-1516305397.jpg"
},
{
"Name": "Hommes",
"Image":
"https://teja12.kuikr.com/is/a/c/880x425/gallery_images/original/cf5d08bff955e71.gif"
},
{
"Name": "Femmes",
"Image":
"https://cdn.pixabay.com/photo/2013/07/13/14/08/apparel-162192_1280.png"
},
{
"Name": "Enfants",
"Image": "https://images.indianexpress.com/2019/09/toys.jpg"
},
{
"Name": "Sunglasses",
"Image": "https://m.media-amazon.com/images/I/51zEsraniRL._UX569_.jpg"
},
{
"Name": "ElectroniQues",
"Image":
"https://ecommerce.ccc2020.fr/wp-content/uploads/2020/10/electronic-gadgets.jpeg"
},
{
"Name": "Accessories",
"Image":
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/classic-accessories-1516305397.jpg"
},
{
"Name": "Hommes",
"Image":
"https://teja12.kuikr.com/is/a/c/880x425/gallery_images/original/cf5d08bff955e71.gif"
},
{
"Name": "Femmes",
"Image":
"https://cdn.pixabay.com/photo/2013/07/13/14/08/apparel-162192_1280.png"
},
{
"Name": "Enfants",
"Image": "https://images.indianexpress.com/2019/09/toys.jpg"
},
{
"Name": "Sunglasses",
"Image": "https://m.media-amazon.com/images/I/51zEsraniRL._UX569_.jpg"
},
];
var column = Column(mainAxisAlignment: MainAxisAlignment.start, children: [
...list.map((e) {
return GestureDetector(onTap:(){},child: ItemWidget(e));
}).toList()
]);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Row(
children: [
SideWidget(),
Expanded(
child: Scaffold(
bottomNavigationBar: buildBottomNavigationBar(),
body: Padding(
padding: const EdgeInsets.only(top: 18.0),
child:
// column
GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
children: [
...list.map((e) {
return InkWell(onTap:(){},child: ItemWidget(e));
}).toList()
],
),
),
),
),
],
),
),
);
}
BottomNavigationBar buildBottomNavigationBar() {
return BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: 0,
selectedItemColor: Colors.amber[800],
onTap: (v) {},
);
}
}
class SideWidget extends StatelessWidget {
const SideWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Material(
child: Container(
width: 63,
color: Colors.white,
child: ListView(
children: [
...[
Icons.headset,
Icons.pets,
Icons.watch,
Icons.color_lens,
Icons.today
]
.map((e) => Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 4.0),
child: TextButton(
onPressed: () {},
child: Icon(
e,
color: Colors.blueGrey,
size: 40,
),
),
))
.toList()
],
),
),
);
}
}
class ItemWidget extends StatelessWidget {
var data;
ItemWidget(this.data, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 150,
child: Card(
child: Column(
children: [
Expanded(
child: Container(
height: 125,
child: GridTile(
// footer:Text(data["Name"]) ,
child: Image.network(
data["Image"],
alignment: Alignment.center,
fit: BoxFit.cover,
),
),
),
),
Center(
child: Text(
data["Name"],
style: TextStyle(fontSize: 12),
))
],
),
),
);
}
}
GridView children size depends on aspect ratio, which is 1 by default. In your case, image is not getting proper height.
For your case, You can use fit on Image.asset.
Image.asset(
"",
fit: BoxFit.cover, // or the .width or the one you prefer
),
Also you can try GridTile
GridTile(
child: Image.asset(
"",
fit: BoxFit.cover,
),
footer: Text("title"),
),
More about GridTile and BoxFit.
Firstly, the way you have created the widget tree is not proper.
Currently, you have
Card -> Container -> Column -> 1. Image
2. Text
If you want the title to be out of your square (Card), it should be:
Column -> 1. Card -> Image
2. Text
This way your title will be out of the card.

How can i rebuild a listview.builder?

I need to rebuild my listview because it is only maintaining the first build, unless I reset the app. I have a bottom sheet pop up that lets me select times and navigate me to a new page where the listview.builder builds. If I back out of the page, select new options, and go back into the page, it does not update. Here is an example:
Relevant Code:
final selectTimesTextStyle = TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
);
final List classBools = [
checkedPreBallet,
checkedBeginningBallet,
checkedIntermediateBallet,
checkedAdvancedBallet,
checkedJazz,
checkedPC,
];
final List<String> preballetItems = [
'Wednesday 3:00-4:00',
'Friday 3:00-3:35',
];
final List<String> privateClassesItems = [
'Mondays, Schedule Via Email',
];
final List<String> intermediateBalletItems = [
'Tuesday 5:00-6:00',
'Thursday 5:00-6:00',
'Saturday 10:00-11:00',
];
final List<String> advancedBalletItems = [
'Tuesday 6:00-7:00',
'Thursday 6:00-7:00',
];
final List<String> beginningBalletItems = [
'Wednesday 3:45-4:45',
'Friday 3:45-4:45',
];
final List<String> jazzItems = [
'Thursday 4:00-5:00',
];
final List<List> listOfLists = [
preballetItems,
beginningBalletItems,
intermediateBalletItems,
advancedBalletItems,
jazzItems,
privateClassesItems,
];
List<String> valueChoose = [
'Wednesday 3:00-4:00',
'Wednesday 3:45-4:45',
'Tuesday 5:00-6:00',
'Tuesday 6:00-7:00',
'Thursday 4:00-5:00',
'Mondays, Schedule Via Email',
];
class TimeSelection extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: InkWell(
onTap: () => {
Navigator.of(context).pop(),
currentIndex = 2,
checkedPreBallet = false,
checkedBeginningBallet = false,
checkedIntermediateBallet = false,
checkedAdvancedBallet = false,
checkedJazz = false,
checkedPC = false,
},
child: Container(
child: Icon(Icons.arrow_back),
),
),
title: Text('Select Times'),
centerTitle: true,
),
body: StatefulBuilder(
builder: (context, setState) => Column(
children: [
Expanded(
child: ListView.builder(
itemCount: 6,
itemBuilder: (context, index) => Visibility(
maintainState: false,
visible: classBools[index],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
child: Text(
buttonTitles[index],
style: selectTimesTextStyle,
),
width: MediaQuery.of(context).size.width * 0.50,
),
Container(
width: MediaQuery.of(context).size.width * 0.40,
child: DropdownButton(
isExpanded: true,
underline: SizedBox(),
dropdownColor: Colors.white,
value: valueChoose[index],
onChanged: (newValue) => {
setState(() {
valueChoose[index] = newValue;
})
},
items: listOfLists[index]
.map((e) => DropdownMenuItem(
onTap: () => {
classBools[index] = true,
},
child: Text(e),
value: e,
))
.toList(),
),
),
],
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 120,
vertical: 15,
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [
0.00005,
1,
],
colors: [
Theme.of(context).secondaryHeaderColor,
Theme.of(context).primaryColor,
]),
boxShadow: [
BoxShadow(color: Colors.black54, offset: Offset(3, 3)),
],
color: Colors.purpleAccent,
borderRadius: BorderRadius.circular(15),
),
child: InkWell(
onTap: () => {},
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('PayPal'),
],
),
),
),
),
),
],
),
),
);
}
}
bool checkedPreBallet = false;
bool checkedBeginningBallet = false;
bool checkedIntermediateBallet = false;
bool checkedAdvancedBallet = false;
bool checkedJazz = false;
bool checkedPC = false;
final List<String> buttonTitles = [
'Pre-Ballet',
'Beginning Ballet',
'Intermediate Ballet',
'Advanced Ballet',
'Jazz',
'Private Classes',
];
class RegisterPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Divider(),
Text('hello'),
Divider(),
RegisterCards(),
],
),
);
}
}
class RegisterCards extends StatefulWidget {
#override
_RegisterCardsState createState() => _RegisterCardsState();
}
class _RegisterCardsState extends State<RegisterCards> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 30,
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [
0.00005,
1,
],
colors: [
Theme.of(context).secondaryHeaderColor,
Theme.of(context).primaryColor,
]),
boxShadow: [
BoxShadow(color: Colors.black54, offset: Offset(3, 3)),
],
color: Colors.purpleAccent,
borderRadius: BorderRadius.circular(15),
),
child: InkWell(
onTap: () => onButtonPressed(context),
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Register Here'),
],
),
),
),
),
);
}
}
class ClassListWidget extends StatefulWidget {
#override
_ClassListWidgetState createState() => _ClassListWidgetState();
}
class _ClassListWidgetState extends State<ClassListWidget> {
#override
Widget build(BuildContext context) {
return StatefulBuilder(
builder: (context, setState) => Column(
children: [
CheckboxListTile(
value: checkedPreBallet,
onChanged: (value) => {
setState(() {
checkedPreBallet = value;
})
},
title: Text('Pre-Ballet'),
checkColor: Theme.of(context).scaffoldBackgroundColor,
activeColor: Theme.of(context).primaryColor,
secondary: Icon(PokemonIcons.i004_charmander),
controlAffinity: ListTileControlAffinity.leading,
tristate: false,
),
CheckboxListTile(
value: checkedBeginningBallet,
onChanged: (value) => {
setState(() {
checkedBeginningBallet = value;
})
},
title: Text('Beginning Ballet'),
checkColor: Theme.of(context).scaffoldBackgroundColor,
activeColor: Theme.of(context).primaryColor,
secondary: Icon(PokemonIcons.i004_charmander),
controlAffinity: ListTileControlAffinity.leading,
tristate: false,
),
CheckboxListTile(
value: checkedIntermediateBallet,
onChanged: (value) => {
setState(() {
checkedIntermediateBallet = value;
})
},
title: Text('Intermediate Ballet'),
checkColor: Theme.of(context).scaffoldBackgroundColor,
activeColor: Theme.of(context).primaryColor,
secondary: Icon(PokemonIcons.i004_charmander),
controlAffinity: ListTileControlAffinity.leading,
tristate: false,
),
CheckboxListTile(
value: checkedAdvancedBallet,
onChanged: (value) => {
setState(() {
checkedAdvancedBallet = value;
})
},
title: Text('Advanced Ballet'),
checkColor: Theme.of(context).scaffoldBackgroundColor,
activeColor: Theme.of(context).primaryColor,
secondary: Icon(PokemonIcons.i004_charmander),
controlAffinity: ListTileControlAffinity.leading,
tristate: false,
),
CheckboxListTile(
value: checkedJazz,
onChanged: (value) => {
setState(() {
checkedJazz = value;
})
},
title: Text('Jazz'),
checkColor: Theme.of(context).scaffoldBackgroundColor,
activeColor: Theme.of(context).primaryColor,
secondary: Icon(PokemonIcons.i004_charmander),
controlAffinity: ListTileControlAffinity.leading,
tristate: false,
),
CheckboxListTile(
value: checkedPC,
onChanged: (value) => {
setState(() {
checkedPC = value;
})
},
title: Text('Private Classes'),
checkColor: Theme.of(context).scaffoldBackgroundColor,
activeColor: Theme.of(context).primaryColor,
secondary: Icon(PokemonIcons.i004_charmander),
controlAffinity: ListTileControlAffinity.leading,
tristate: false,
),
],
),
);
}
}
void onButtonPressed(context) {
showModalBottomSheet(
isScrollControlled: false,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
context: context,
builder: (context) => StatefulBuilder(
builder: (BuildContext context, setState) => Container(
child: Column(
children: [
ClassListWidget(),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15,
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [
0.00005,
1,
],
colors: [
Theme.of(context).secondaryHeaderColor,
Theme.of(context).primaryColor,
]),
boxShadow: [
BoxShadow(color: Colors.black54, offset: Offset(3, 3)),
],
color: Colors.purpleAccent,
borderRadius: BorderRadius.circular(15),
),
child: InkWell(
onTap: () => {
Navigator.push(context, MaterialPageRoute(
builder: (context) => TimeSelection(),
)),
},
child: Padding(
padding: EdgeInsets.all(14),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Select Times'),
],
),
),
),
),
),
],
),
),
),
);
}
check this out whether it fits your need.
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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: TimeSelection(),
);
}
}
// model class for your ballet
class Ballet {
final String balletName;
final List<String> timeSchedules;
final String description;
String selectedTime;
bool isSelected = false;
Ballet({
this.balletName,
this.timeSchedules,
isSelected,
this.description = '',
this.selectedTime
}) {selectedTime ??= this.timeSchedules[0];}
}
List<Ballet> balletItems = <Ballet>[
Ballet(
balletName: "Pre-Ballet",
timeSchedules: [
'Wednesday 3:00-4:00',
'Friday 3:00-3:35',
],
),
Ballet(
balletName: "Private Classes",
timeSchedules: [
'Mondays',
],
description: 'Scheduled Via Email'
),
Ballet(
balletName: "Intermediate Ballet",
timeSchedules: [
'Tuesday 5:00-6:00',
'Thursday 5:00-6:00',
'Saturday 10:00-11:00',
],
),
Ballet(
balletName: "Advance Ballet",
timeSchedules: [
'Tuesday 6:00-7:00',
'Thursday 6:00-7:00',
],
),
Ballet(
balletName: "Beginning Ballet",
timeSchedules: [
'Wednesday 3:45-4:45',
'Friday 3:45-4:45',
],
),
Ballet(
balletName: "Jazz Ballet",
timeSchedules: [
'Thursday 4:00-5:00',
],
)
];
class TimeSelection extends StatefulWidget {
#override
_TimeSelectionState createState() => _TimeSelectionState();
}
class _TimeSelectionState extends State<TimeSelection> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: Column(
children: [
Text('hello there', style: Theme.of(context).textTheme.headline4),
ElevatedButton(child: Text('Register Here',), onPressed: () {},),
],
),
),
Expanded(
child: ListView.builder(
itemCount: balletItems.length+1 ,
itemBuilder: (context, index){
if (index < balletItems.length) {
Ballet balletItem = balletItems[index];
return ListTile(leading: Checkbox(
value: balletItem.isSelected,
onChanged: (value) {
setState((){
balletItem.isSelected = value;
});
},),
title: Text(balletItem.balletName),
trailing: Icon(Icons.auto_awesome),
);}
else{
return Container(
margin: const EdgeInsets.symmetric(horizontal: 20.0),
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => SelectTimes(),));
},
child: Text('Select Times'),
),
);}
},
),
)
],
),
drawer: Drawer(),
appBar: AppBar(title: Text("Class Registration"),),
);
}
}
class SelectTimes extends StatefulWidget {
#override
_SelectTimesState createState() => _SelectTimesState();
}
class _SelectTimesState extends State<SelectTimes> {
List<Ballet> selectedBalletItems;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Select Times'),),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: selectedBalletItems.length,
itemBuilder: (context, index) {
Ballet selectedBalletItem = selectedBalletItems[index];
return _listTile(selectedBalletItem);
},
),
),
ElevatedButton(child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("PayPal", style: Theme.of(context).textTheme.headline4,
),
),
onPressed: () {},)
],
),
)
);
}
Widget _listTile(Ballet selectedBalletItem) {
return ListTile(
title: Text(selectedBalletItem.balletName),
subtitle: Text(selectedBalletItem.description , style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.grey[500])),
trailing: DropdownButton<String>(
value: selectedBalletItem.selectedTime,
items: selectedBalletItem.timeSchedules.map((timeSchedule) {
return DropdownMenuItem(value: timeSchedule, child: Text(timeSchedule));
} ).toList(),
onChanged: (value) {
setState(() {
selectedBalletItem.selectedTime = value;
});
},
)
);
}
#override
void initState() {
super.initState();
selectedBalletItems = balletItems.where((e) => e.isSelected).toList();
}
}

How to pass a list of maps as inital value to the FormBuilderFilterChip in flutter_form_builder package?

I have tried passing a list of the same 'value' field of the FormBuilderFieldOption to the initialValue argument.
Edit: Passing the list satisfies the 'required' validator but does not show the chips as 'marked'
Now if i'm not wrong this should return a set of chips that are all marked, but it does not.
List<Map<String,dynamic>> _allValues = [
{id: 1586762938154, name: 202, rate: 5000, type: 'ABYSS'},
{id: 1586759232569, name: 101, rate: 1000, type: 'DELUXE'},
{id: 1586849439323, name: 13, rate: 3434, type: 'DELUXE'},
{id: 1586759258120, name: 102, rate: 2000, type: 'EXECUTIVE'},
{id: 1586779416843, name: 103, rate: 2343, type: 'EXECUTIVE'},
]
FormBuilderFilterChip(
initialValue: _allValues.map((value) => value).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map((val) => FormBuilderFieldOption(
value: val,
child: Text(val['name']),
),
).toList(),
onChanged: (value) {
_selected = value;
print(_selected);
},
)
You can copy paste run full code below
Assume _allValues is List<Map<String, String>>
code snippet
List<Map<String, String>> _allValues = [
{"name": "abc"},
{"name": "def"},
{"name": "123"}
];
FormBuilderFilterChip(
initialValue:
_allValues.map((value) => value['name']).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map(
(val) => FormBuilderFieldOption(
value: val['name'],
child: Text(val['name']),
),
)
.toList(),
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter FormBuilder Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
inputDecorationTheme: InputDecorationTheme(
labelStyle: TextStyle(color: Colors.purple),
),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
MyHomePageState createState() {
return MyHomePageState();
}
}
class Data {
String name;
Data(this.name);
}
class MyHomePageState extends State<MyHomePage> {
var data;
bool autoValidate = true;
bool readOnly = false;
bool showSegmentedControl = true;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
final GlobalKey<FormFieldState> _specifyTextFieldKey =
GlobalKey<FormFieldState>();
ValueChanged _onChanged = (val) => print(val);
var genderOptions = ['Male', 'Female', 'Other'];
List<Map<String, String>> _allValues = [
{"name": "abc"},
{"name": "def"},
{"name": "123"}
];
List<dynamic> _selected;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FormBuilder Example"),
),
body: Padding(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(children: <Widget>[
FormBuilder(
// context,
key: _fbKey,
autovalidate: true,
initialValue: {
'movie_rating': 5,
},
readOnly: false,
child: Column(
children: <Widget>[
FormBuilderFilterChip(
initialValue: ["Test 1", "Test 3"],
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: [
FormBuilderFieldOption(
value: 'Test', child: Text('Test')),
FormBuilderFieldOption(
value: 'Test 1', child: Text('Test 1')),
FormBuilderFieldOption(
value: 'Test 2', child: Text('Test 2')),
FormBuilderFieldOption(
value: 'Test 3', child: Text('Test 3')),
FormBuilderFieldOption(
value: 'Test 4', child: Text('Test 4')),
],
),
FormBuilderFilterChip(
initialValue:
_allValues.map((value) => value['name']).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map(
(val) => FormBuilderFieldOption(
value: val['name'],
child: Text(val['name']),
),
)
.toList(),
onChanged: (value) {
_selected = value;
print(_selected);
},
)
],
),
),
]),
)));
}
}
I took a look under the hood and how the FormBuilderFilterChip marks the chips as selected is by using the List.contains() method.
In this method the equality used to determine whether [element] is equal to an element of the List defaults to the [Object.==] of the element.
So to tackle this i built my own custom FilterChipField (borrowing most of the necessary code from the FormBuilderFilterChip)
FormBuilderCustomField(
attribute: "name",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
enabled: true,
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
prefixIcon: Icon(Icons.vpn_key),
labelText: "Assign Room(s)",
contentPadding: EdgeInsets.only(top: 10.0, bottom: 0.0),
errorText: field.errorText,
),
child: Container(
child: _buildChipSelectField(field),
),
);
},
),
)
The _buildChipSelectField below contains two custom functions one (_selectedValuesContains) to check the equality
of the object in the lists and second (_selectedValuesRemove) to remove the object on toggling the chip
Widget _buildChipSelectField(FormFieldState<dynamic> field) {
return Wrap(
spacing: 3.0,
children: _allValues.map((item) {
return FilterChip(
label: Text("${item['name']} - ${item['type']}"),
selectedColor: Colors.black38,
selected: _selectedValuesContains(item),
onSelected: (value) {
setState(() {
if (_selectedValuesContains(item)) {
_selectedValuesRemove(item);
} else {
_selectedValues.add(item);
}
field.didChange(_selectedValues);
});
},
);
}).toList(),
);
}
(These methods are for my sample data (i.e _allValues), but the idea is very basic in nature.)
_selectedValuesContains
bool _selectedValuesContains(Map item) {
int index = _selectedValues.indexWhere((val) => val['id'] == item['id']);
return index >= 0 ? true : false;
}
_selectedValuesRemove
void _selectedValuesRemove(Map item) {
int index = _selectedValues.indexWhere((val) => val['id'] == item['id']);
_selectedValues.removeAt(index);
}

Categories

Resources