ListTile key not found in Flutter - flutter

I have a List defined as below and I'm trying to highlight one element of the list during the tutorial. I am currently using Tutorial Coach Mark. Every time I debug my app it shows me
KEY information could not be obtained
I don't know why this is happening as I've followed all the necessary steps for integration shown in the dependency.
This is my code:
class _SettingsState extends State<Settings> {
TutorialCoachMark tutorialCoachMark;
GlobalKey keyButton3 = GlobalKey();
List<TargetFocus> targets = List();
void initState() {
initTarget();
WidgetsBinding.instance.addPostFrameCallback(_afterLayouts);
super.initState();
}
void _afterLayouts(_) {
Future.delayed(Duration(milliseconds: 100), () {
showTutorial(context);
});
}
void showTutorial(context) {
tutorialCoachMark = TutorialCoachMark(context,
targets: targets,
colorShadow: Colors.red,
textSkip: "SKIP",
paddingFocus: 10,
opacityShadow: 0.8, onFinish: () {
print("finish");
}, onClickTarget: (target) {
print(target);
}, onClickSkip: () {
print("skip");
})
..show();
}
void initTarget() {
targets.add(
TargetFocus(
//claim reward
identify: "Target 2",
keyTarget: keyButton3,
color: Colors.purple,
contents: [
ContentTarget(
align: AlignContent.bottom,
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Click here",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 20.0),
),
],
),
))
],
shape: ShapeLightFocus.RRect,
radius: 6),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
iconTheme: IconThemeData(
color: Colors.white,
),
elevation: 0,
title: Text(
'Settings',
style: kTasksStyle,
),
backgroundColor: Color(0xff0C7368),
),
body: Stack(
children: [
Padding(
padding: const EdgeInsets.only(top: 8),
child: ListView.separated(
separatorBuilder: (context, index) => Divider(
height: 2,
color: Colors.grey.withOpacity(0.3),
),
itemCount: 5,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(5.0),
child: ListTile(
key: index == 0 ? keyButton3 : null,// to highlight the 0th index of the list only
title: Text(
"Hello",
style: kTasksStyle.copyWith(
fontSize: 15,
color: Colors.black,
fontWeight: FontWeight.normal),
),
leading: Icon(
Icons.supervised_user_circle,
color: Color(0xff0C7368),
),
),
);
}),
)
],
));
}
}
I am trying to achieve something similar to this:

Related

How do i return a container based on a list of item selected in flutter?

I have a list of items
List<String> items = [
"All",
"Jobs",
"Messages",
"Customers",
];
int current = 0;
And this list is directly responsible for my tab bar:
When i tap an item in the Tab bar i want to return a different container on each of them?
How do i go about this in flutter?
I tried returning an if statement just before the container but it seems i don't get the statement correctly.
this is the container i want to return if the item user select is All, and then put conditions in place for the rest items.
this is how i put the condition but it gives me this error
My return statement and code -
current = 0 ??
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 10,
),
Text(
items[current],
style: GoogleFonts.laila(
fontWeight: FontWeight.w500,
fontSize: 30,
color: Colors.deepPurple),
),
],
),
),
current = 1 ?? Text('hello')
FULL WIDGET ADDED
class NotificationsView extends StatefulWidget {
#override
State<NotificationsView> createState() => _NotificationsViewState();
}
class _NotificationsViewState extends State<NotificationsView> {
final controller = Get.put(NotificationsController());
List<String> items = [
"All",
"Jobs",
"Messages",
"Customers",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Notifications".tr,
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 16,
fontWeight: FontWeight.w600),
),
centerTitle: false,
backgroundColor: Colors.transparent,
elevation: 0,
automaticallyImplyLeading: false,
leadingWidth: 15,
leading: new IconButton(
icon: new Icon(Icons.arrow_back_ios, color: Color(0xff3498DB)),
onPressed: () => {Get.back()},
),
),
body: RefreshIndicator(
onRefresh: () async {
},
child: ListView(
primary: true,
children: <Widget>[
filter(),
],
),
),
);
}
Widget notificationsList() {
return Obx(() {
if (!controller.notifications.isNotEmpty) {
return CircularLoadingWidget(
height: 300,
onCompleteText: "Notification List is Empty".tr,
);
} else {
var _notifications = controller.notifications;
return ListView.separated(
itemCount: _notifications.length,
separatorBuilder: (context, index) {
return SizedBox(height: 7);
},
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
var _notification = controller.notifications.elementAt(index);
if (_notification.data['message_id'] != null) {
return MessageNotificationItemWidget(
notification: _notification);
} else if (_notification.data['booking_id'] != null) {
return BookingNotificationItemWidget(
notification: _notification);
} else {
return NotificationItemWidget(
notification: _notification,
onDismissed: (notification) {
controller.removeNotification(notification);
},
onTap: (notification) async {
await controller.markAsReadNotification(notification);
},
);
}
});
}
});
}
Widget filter() {
return Container(
width: double.infinity,
margin: const EdgeInsets.all(5),
child: Column(
children: [
/// CUSTOM TABBAR
SizedBox(
width: double.infinity,
height: 60,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, index) {
return Column(
children: [
GestureDetector(
onTap: () {
setState(() {
current = index;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: current == index
? Color(0xff34495E)
: Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(
left: 10.0, right: 10.0, top: 5, bottom: 5),
child: Text(
items[index],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: current == index
? Colors.white
: Colors.grey),
),
),
),
),
),
],
);
}),
),
/// MAIN BODY
current = 0 ??
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 10,
),
Text(
items[current],
style: GoogleFonts.laila(
fontWeight: FontWeight.w500,
fontSize: 30,
color: Colors.deepPurple),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0, bottom: 20),
child: Column(
children: [
Stack(
children: [
Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xffEFFAFF),
borderRadius:
BorderRadius.circular(20)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
'assets/icon/suitcase.png'),
),
),
SizedBox(
width: 15,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'New Job started ',
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xff151515)),
),
Text(
'Tailoring for John Cletus ',
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff151515)),
),
],
),
Spacer(),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xffFFE8E8),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Urgent',
style: GoogleFonts.poppins(
color: Color(0xffC95E5E)),
),
),
),
],
),
],
),
Divider(
height: 5,
color: Color(0xffEFFAFF),
),
],
),
),
],
),
),
current = 1 ?? Text('hello')
],
),
);
}
}
You can use Builder if want to display different type of widget based on the current index.
Builder(
builder: (context) {
switch (current) {
case 0:
return Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 10,
),
Text(
items[current],
style: GoogleFonts.laila(
fontWeight: FontWeight.w500,
fontSize: 30,
color: Colors.deepPurple),
),
],
),
);
case 1:
return Text('Hello');
default:
return SizedBox.shrink();
}
},
);
Below approach will solve your problem. If you need further assistance, please feel free to comment.
int _currentIndex = 0;
var _containers = <Widget>[
AllContainer(),
JobsContainer(),
MessagesContainer(),
CustomerContainer(),
];
Widget _bottomTab() {
return BottomNavigationBar(
currentIndex: _currentIndex,
onTap: _onItemTapped, //
type: BottomNavigationBarType.fixed,
selectedLabelStyle: const TextStyle(color: Colors.blue),
selectedItemColor: WAPrimaryColor,
unselectedLabelStyle: const TextStyle(color: Colors.blue),
unselectedItemColor: Colors.grey,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(label: 'All'),
BottomNavigationBarItem(
label: 'Jobs'),
BottomNavigationBarItem(
label: 'Messages'),
BottomNavigationBarItem( label: 'Customer'),
],
);
}
void _onItemTapped(int index) async {
print('bottom index::: $index');
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
bottomNavigationBar: _bottomTab(),
body: Center(child: _containers.elementAt(_currentIndex)),
),
);
}
You can use conditional if on widget level,
like
/// MAIN BODY
if (current == 0)
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
...
),
if (current == 1) Text('hello')
Also can be use else if
if (current == 0)
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
) //you shouldnt put coma
else if (current == 1) Text('hello')
],
),
);
But creating a separate method will be better instead of putting it here
Widget getWidget(int index) {
/// MAIN BODY
if (current == 0) // or switch case
return Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
); //you shouldnt put coma
else if (current == 1) return Text('hello');
return Text("default");
}
And call the method getWidget(current).
Also there are some widget like PageView, IndexedStack will help to organize the code structure

How do i correctly initialise a variable from a stateful widget to another widget in flutter and maintain state?

I have two widgets
JobsHeaderWidget
JobsView
JobsHeaderWidget is a stateful widget where i code all the logic and initialise int current = 0; in the state. In this same file, i have another class named CategoriesBuilder where i use switch cases to make sure at each switch case a different container is returned. ( a switch case for each tab )
This switch cases is now responsible for switching containers depending on the tab bar selected as seen in this image:
I will also drop the code snippet of the JobsHeaderWidget for better clarifications.
The problem is - when i use this CategoriesBuilder in same widget as the 'JobsHeaderWidget' it works.
But i don't want to use it in same widget cos of the logic of my design. I want to be able to use this builder in JobsView widget which is another dart file and it doesn't work maybe because of wrong approach.
I tried converting the JobsView to a stateful widget and initialising 'int current = 0;' but it doesn't work.
I also tried making int current = 0; global var, it worked but the state doesn't change when i select individual tab bars. ( I mean my switch cases don't seem to work ).
I have gone round stackoverflow for answers before asking this but can't find a solution.
Snippets of each widgets below.
JobsHeaderWidget
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({
Key key,
}) : super(key: key);
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
ValueChanged<int> onChange;
int current = 0;
List<DropdownMenuItem<String>> get dropdownItems {
List<DropdownMenuItem<String>> menuItems = [
DropdownMenuItem(
child: Text(
"Today",
),
value: "Today"),
];
return menuItems;
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jobs',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w600),
),
Row(
children: [
Text(
'View Insights ',
style: GoogleFonts.poppins(
color: Color(0xff3498DB),
fontSize: 12,
fontWeight: FontWeight.w500),
),
Icon(
Icons.arrow_forward_ios,
color: Color(0xff3498DB),
size: 12,
),
],
),
SizedBox(
height: 10,
),
filterJobs(),
],
),
),
);
}
Widget filterJobs() {
String selectedValue = "Today";
return Column(
children: [
Container(
constraints: const BoxConstraints(maxWidth: 600, maxHeight: 100),
width: double.infinity,
child: IntrinsicWidth(
child: FittedBox(
fit: BoxFit.fitWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < items.length; i++) ...[
GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 14.0, right: 14.0, top: 4, bottom: 4),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(50),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 15,
fontWeight: FontWeight.w500,
color:
current == i ? Colors.white : Colors.grey),
),
),
),
),
]
],
),
),
),
),
Divider(
color: Color(0xff34495E).withOpacity(0.2),
),
Row(
children: [
Text(
'All Jobs',
style:
GoogleFonts.poppins(fontSize: 9, fontWeight: FontWeight.w400),
),
SizedBox(
width: 5,
),
Text(
' * This Week',
style:
GoogleFonts.poppins(fontSize: 9, fontWeight: FontWeight.w400),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'25',
style: GoogleFonts.poppins(
fontSize: 20, fontWeight: FontWeight.w600),
),
Container(
height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xffF4F4F4)),
child: Padding(
padding: const EdgeInsets.only(
left: 8.0,
),
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xff34495E),
borderRadius: BorderRadius.circular(2)),
child: Icon(
Icons.tune,
size: 15,
color: Colors.white,
),
),
SizedBox(
width: 5,
),
DropdownMenuItem(
child: DropdownButtonHideUnderline(
child: Container(
child: DropdownButton(
isDense: true,
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color(0xff34495E),
),
onChanged: (value) {},
items: dropdownItems,
value: selectedValue,
),
),
),
),
],
),
),
),
],
),
//If i uncomment this line and use the category builder here, it works fine! CategoriesBuilder(current: current)
],
);
}
}
class CategoriesBuilder extends StatelessWidget {
const CategoriesBuilder({
Key key,
#required this.current,
}) : super(key: key);
final int current;
#override
Widget build(BuildContext context) {
return Builder(
builder: (context) {
switch (current) {
case 0:
return AllJobsListView();
case 1:
return CriticalJobsListView();
case 2:
return OpenJobsListView();
case 3:
return ClosedJobsListView();
case 4:
return OverdueJobsListView();
default:
return SizedBox.shrink();
}
},
);
}
}
JobsView
class JobsView extends StatefulWidget {
const JobsView({
Key key,
}) : super(key: key);
#override
State<JobsView> createState() => _JobsViewState();
}
class _JobsViewState extends State<JobsView> {
int current = 0;
#override
Widget build(BuildContext context) {
final controller = Get.put(EServicesController());
return Scaffold(
// floatingActionButton: new FloatingActionButton(
// child: new Icon(Icons.add, size: 32, color: Get.theme.primaryColor),
// onPressed: () => {Get.offAndToNamed(Routes.E_SERVICE_FORM)},
// backgroundColor: Get.theme.colorScheme.secondary,
// ),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
body: RefreshIndicator(
onRefresh: () async {
Get.find<LaravelApiClient>().forceRefresh();
controller.refreshEServices(showMessage: true);
Get.find<LaravelApiClient>().unForceRefresh();
},
child: CustomScrollView(
controller: controller.scrollController,
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: false,
slivers: <Widget>[
SliverAppBar(
backgroundColor: Color(0xffFFFFFF),
expandedHeight: MediaQuery.of(context).size.height * 0.4,
elevation: 0.5,
primary: true,
pinned: false,
floating: false,
//iconTheme: IconThemeData(color: Get.theme.primaryColor),
// title: Text(
// "Jobs".tr,
// style: Get.textTheme.headline6
// .merge(TextStyle(color: Get.theme.primaryColor)),
// ),
centerTitle: false,
automaticallyImplyLeading: false,
// leading: new IconButton(
// icon: new Icon(Icons.arrow_back_ios,
// color: Get.theme.primaryColor),
// onPressed: () => {Get.back()},
// ),
actions: [
SearchButtonWidget(),
],
//bottom: HomeSearchBarWidget(),
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: JobsHeaderWidget(),
)),
SliverToBoxAdapter(
child: Wrap(
children: [
//ServicesListWidget(),
// The state doesnt change here for some reasosns CategoriesBuilder(current: current)
],
),
),
],
),
),
);
}
}
Try this: keep your 'int current' within _JobsViewState as you have in your code.
When you call your JobsHeaderWidget , pass the function it will use to update the the value of the current variable; and rebuild the state from here.
Something like this:
class JobsHeaderWidget extends StatefulWidget {
final Function changeCurrentValue(int newValue);
const JobsHeaderWidget({
this.changeCurrentValue,
Key key,
}) : super(key: key);
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
#override
Widget build(BuildContext context) {
// Somewhere inside build, instead calling setState()
// call the function you passed to the widget
GestureDetector(
onTap: () {
changeCurrentValue(i);
},
)
}
}
class _JobsViewState extends State<JobsView> {
int current = 0;
void changeCurrentValue(int newValue) {
setState(() {
current = newValue;
});
}
#override
Widget build(BuildContext context) {
//somewhere inside build
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: JobsHeaderWidget(changeCurrentValue: changeCurrentValue),
)),
}
}
After hours and even sleeping overnight on this question i came up with a work-around that works. (minor refactoring)
This was my approach :
Convert my JobsView widget to a stateful widget and put all my controllers in place.
Copied all my variables from JobHeaderWidget and put it in the state of my JobsView widget.
Instead of returning a widget in the title of my sliver app as thus :
flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.parallax, title: JobsHeaderWidget(), )),
I copied all of my code from the widget tree from JobsHeaderWidget and put converted to a method and replaced it in my title.
My builder CategoryBuilder was put in a separate then imported as i used it in my SliverAppAdapter .
Of cos i got rid of the unnecessary dart file JobsHeaderWidget.
FULL CODE BELOW
class JobsView extends StatefulWidget {
#override
State<JobsView> createState() => _JobsViewState();
}
class _JobsViewState extends State<JobsView> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
List<DropdownMenuItem<String>> get dropdownItems {
List<DropdownMenuItem<String>> menuItems = [
DropdownMenuItem(
child: Text(
"Today",
),
value: "Today"),
];
return menuItems;
}
#override
Widget build(BuildContext context) {
final controller = Get.put(EServicesController());
return Scaffold(
// floatingActionButton: new FloatingActionButton(
// child: new Icon(Icons.add, size: 32, color: Get.theme.primaryColor),
// onPressed: () => {Get.offAndToNamed(Routes.E_SERVICE_FORM)},
// backgroundColor: Get.theme.colorScheme.secondary,
// ),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
body: RefreshIndicator(
onRefresh: () async {
Get.find<LaravelApiClient>().forceRefresh();
controller.refreshEServices(showMessage: true);
Get.find<LaravelApiClient>().unForceRefresh();
},
child: CustomScrollView(
controller: controller.scrollController,
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: false,
slivers: <Widget>[
SliverAppBar(
backgroundColor: Color(0xffFFFFFF),
expandedHeight: MediaQuery.of(context).size.height * 0.4,
elevation: 0.5,
primary: true,
pinned: false,
floating: false,
//iconTheme: IconThemeData(color: Get.theme.primaryColor),
// title: Text(
// "Jobs".tr,
// style: Get.textTheme.headline6
// .merge(TextStyle(color: Get.theme.primaryColor)),
// ),
centerTitle: false,
automaticallyImplyLeading: false,
// leading: new IconButton(
// icon: new Icon(Icons.arrow_back_ios,
// color: Get.theme.primaryColor),
// onPressed: () => {Get.back()},
// ),
actions: [
SearchButtonWidget(),
],
//bottom: HomeSearchBarWidget(),
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: mainHeader(),
)),
SliverToBoxAdapter(
child: Wrap(
children: [
//ServicesListWidget(),
CategoriesBuilder(current: current)
],
),
),
],
),
),
);
}
Padding mainHeader() {
return Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jobs',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w600),
),
Row(
children: [
Text(
'View Insights ',
style: GoogleFonts.poppins(
color: Color(0xff3498DB),
fontSize: 12,
fontWeight: FontWeight.w500),
),
Icon(
Icons.arrow_forward_ios,
color: Color(0xff3498DB),
size: 12,
),
],
),
SizedBox(
height: 10,
),
() {
String selectedValue = "Today";
return Column(
children: [
Container(
constraints:
const BoxConstraints(maxWidth: 600, maxHeight: 100),
width: double.infinity,
child: IntrinsicWidth(
child: FittedBox(
fit: BoxFit.fitWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < items.length; i++) ...[
GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 14.0,
right: 14.0,
top: 4,
bottom: 4),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(50),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 15,
fontWeight: FontWeight.w500,
color: current == i
? Colors.white
: Colors.grey),
),
),
),
),
]
],
),
),
),
),
Divider(
color: Color(0xff34495E).withOpacity(0.2),
),
Row(
children: [
Text(
'All Jobs',
style: GoogleFonts.poppins(
fontSize: 9, fontWeight: FontWeight.w400),
),
SizedBox(
width: 5,
),
Text(
' * This Week',
style: GoogleFonts.poppins(
fontSize: 9, fontWeight: FontWeight.w400),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'25',
style: GoogleFonts.poppins(
fontSize: 20, fontWeight: FontWeight.w600),
),
Container(
height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xffF4F4F4)),
child: Padding(
padding: const EdgeInsets.only(
left: 8.0,
),
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xff34495E),
borderRadius: BorderRadius.circular(2)),
child: Icon(
Icons.tune,
size: 15,
color: Colors.white,
),
),
SizedBox(
width: 5,
),
DropdownMenuItem(
child: DropdownButtonHideUnderline(
child: Container(
child: DropdownButton(
isDense: true,
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color(0xff34495E),
),
onChanged: (value) {},
items: dropdownItems,
value: selectedValue,
),
),
),
),
],
),
),
),
],
),
//CategoriesBuilder(current: current)
],
);
}(),
],
),
),
);
}
}

Flutter - codes not working correctly after putting inside setState

I am trying to add to an array list after user clicked. I am using InkWell, onTap function.
child: InkWell(
onTap: () {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
My debug console is printing these out,
enter image description here
However, when i put the codes inside a setState, this is what got printed
child: InkWell(
onTap: () {
setState(() {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
});
enter image description here
What i am trying to do, is to show/hide the 'trailing' icon in the ListTile, based on whatever user had selected the particular item.
My full codes (without the setState) are as follows,
import 'package:flutter/material.dart';
class Personal1Redo extends StatefulWidget {
#override
_Personal1RedoState createState() => _Personal1RedoState();
}
class _Personal1RedoState extends State<Personal1Redo> {
#override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
List<String> entries = [
'Residental Loan',
'Personal Loan',
'Car Loan',
'Renovation Loan',
'Savings Account',
];
List<String> tempArray = [];
final heading = Column(
children: [
const SizedBox(
height: 40,
),
SizedBox(
height: (mediaQuery.size.height - mediaQuery.padding.top) * 0.1,
child: const Align(
alignment: Alignment.center,
child: Text(
'What do you aspire to do?',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
const SizedBox(
height: 20,
),
],
);
return Scaffold(
appBar: AppBar(
title: Text('Borrower redo'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
heading,
ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (ctx, index) {
return Container(
width: mediaQuery.size.width * 0.9,
padding: const EdgeInsets.all(15),
child: InkWell(
onTap: () {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
},
child: Card(
margin: const EdgeInsets.all(10),
elevation: 8,
child: ListTile(
title: Text(
entries[index],
style: TextStyle(
color: Colors.grey.shade800,
fontSize: 20,
),
textAlign: TextAlign.center,
),
trailing: tempArray.contains(entries[index])
? Icon(Icons.check_box_outline_blank_outlined)
: null,
),
),
),
);
})
],
),
),
);
}
}
Any helps and guidance is very much appreciated, thanks!!
Define variables and functions outside build method.
As setState method, calls build, every time it is called.
Like this :
import 'package:flutter/material.dart';
class Personal1Redo extends StatefulWidget {
#override
_Personal1RedoState createState() => _Personal1RedoState();
}
class _Personal1RedoState extends State<Personal1Redo> {
List<String> entries = [
'Residental Loan',
'Personal Loan',
'Car Loan',
'Renovation Loan',
'Savings Account',
];
List<String> tempArray = [];
getHeadingWidget(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 40,
),
SizedBox(
height: (mediaQuery!.size.height - mediaQuery.padding.top) * 0.1,
child: const Align(
alignment: Alignment.center,
child: Text(
'What do you aspire to do?',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
const SizedBox(
height: 20,
),
],
);
}
#override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Borrower redo'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
getHeadingWidget(context),
ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (ctx, index) {
return Container(
width: mediaQuery.size.width * 0.9,
padding: const EdgeInsets.all(15),
child: InkWell(
onTap: () {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
},
child: Card(
margin: const EdgeInsets.all(10),
elevation: 8,
child: ListTile(
title: Text(
entries[index],
style: TextStyle(
color: Colors.grey.shade800,
fontSize: 20,
),
textAlign: TextAlign.center,
),
trailing: tempArray.contains(entries[index])
? Icon(Icons.check_box_outline_blank_outlined)
: null,
),
),
),
);
})
],
),
),
);
}
}

flutter problem: My FAQs ui is not what I want

I have this problem that I want to make my FAQs UI like Original UI but i cant making like that.
I have this problem that I want to make my FAQs UI like Original UI but i cant making like that.
I want like this UI.
But its creating like this.
My UI is not matching please help me How to make it like original.
This is my code.
import 'package:cwc/constants/constants.dart';
import 'package:flutter/material.dart';
import '../skeleton.dart';
class FAQPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return FAQPageState();
}
}
class FAQPageState extends State<FAQPage> {
bool isExpand = false;
var selected;
#override
void initState() {
// TODO: implement initState
super.initState();
isExpand = false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffffffff),
appBar: AppBar(
elevation: 0.5,
leading: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back,
color: Colors.black,
size: tSize24,
)),
centerTitle: true,
backgroundColor: Colors.white,
),
body: isFAQLoading == true
? ButtonSkeleton()
: ListView.builder(
itemCount: faqListData.length,
itemBuilder: (context, index) {
return Column(children: <Widget>[
Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.grey.shade200,
offset: Offset(1.0, 1.0),
spreadRadius: 0.2)
]),
child: Card(
elevation: 0,
shadowColor: Colors.grey,
margin: EdgeInsets.only(
bottom: 3,
),
child: ExpansionTile(
key: Key(index.toString()),
backgroundColor: Color(0xfff6f7f9),
initiallyExpanded: index == selected,
iconColor: Colors.grey,
title: Text(
'${faqListData[index]['question']}',
style: TextStyle(
color: Color(0xFF444444),
fontSize: tSize14,
fontWeight: FontWeight.w500),
),
children: <Widget>[
Padding(
padding: EdgeInsets.only(
top: 10.0, bottom: 10, left: 17, right: 17),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Text(
"${faqListData[index]['answer']}",
style: TextStyle(
color: Color(0xFF444444),
fontSize: 13,
),
textAlign: TextAlign.start,
),
),
],
))
],
onExpansionChanged: ((newState) {
isExpand = newState;
print(newState);
if (newState)
setState(() {
Duration(seconds: 20000);
selected = index;
// isExpand=newState;
});
else
setState(() {
selected = -1;
// isExpand=newState;
});
print(selected);
})),
),
),
]);
}),
);
}
}
Hi I checked your code and looks just small thing is missing. When you are passing key to the Exapnsion tile you need to pass same key to ListView.builder then it works fine.
ListView.builder(
key: Key('builder ${selected.toString()}'),
itemCount: faqListData.length,
...
...
);

How To Dynamically add Dropdown buttons or delete dropdown(s) in listview with flutter Web?

i have created a page where a user who will click a title to edit the contents and can add and delete devices that the article is attached to,
but i could not figure it out on how to program the drop down dynamically, to add more drop downs when a user press the add device button,
the additional function they want me to add as well is on the Dropdown list, when they select 'NONE' it should remove that dropdown as well,
i am planning to use mysql,xampp or sqlite for my database if im done with the UI,
import 'package:flutter/material.dart';
import 'package:surveyadminpanel/Contents/tabbar.dart';
import 'package:surveyadminpanel/widgets/button.dart';
import 'package:surveyadminpanel/widgets/simplewidgets.dart';
import 'homepage.dart';
import 'dart:ui';
class Item {
Item(this.name);
String name;
}
class editsurvey extends StatefulWidget {
#override
_editsurveyState createState() => _editsurveyState();
}
class _editsurveyState extends State<editsurvey>{
int surveyquestionnum = 1;
int surveyquestiontotal = 1;
List<Item> selectedUser = [null, null];
List<Item> selecteddata = [null, null];
List<Item> users;
int linkdevices = 1;
String dropdownvalue= "SELECT FROM DROPDOWN";
List data = [
'Sample Data 1',
'Sample Data 2',
'Sample Data 3',
'Sample Data 4',
'Sample Data 5',
'Sample Data 6',
];
#override
void initState() {
super.initState();
users = <Item>[
Item('Sample device 1'),
Item('Sample device 2'),
Item('Sample device 3'),
Item('Sample device 4'),
];
}
#override
Widget _dropdownbutton (List<Item> userlist, int index){
return Container(
padding: EdgeInsets.all(1),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
border: Border.all(),
borderRadius: BorderRadius.all(
Radius.circular(15.0) //
),
),
child: DropdownButton<Item>(
underline: SizedBox(),
isExpanded: true,
icon: Icon(Icons.arrow_drop_down),
hint: Text(" $dropdownvalue"),
value: selectedUser[index],
onChanged: (Item Value) {
setState(() {
selectedUser[index] = Value;
});
},
items: userlist.map((Item user) {
return DropdownMenuItem<Item>(
value: user,
child: Row(
children: <Widget>[
SizedBox(width: 10,),
Text(
user.name,
style: TextStyle(color: Colors.black),
),
],
),
);
}).toList(),
),
);
}
Widget _text(texthere,bold,size,color){
return Text(texthere,style: TextStyle(fontWeight: bold,fontSize: size,color: color),overflow: TextOverflow.ellipsis,maxLines: 1);
}
Widget _logo(){
return InkWell(
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => admincontent()),
);
},
child: Container(width: 500,height: 200,child: Image.asset("images/v2.jpg")));
}
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
double screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Padding(padding: EdgeInsets.only(left: 30),
child: RichText(
text: TextSpan(
text: 'Good Morning Welcome to Sample:',
style: TextStyle(
color: Colors.blueAccent, fontSize: 18),
children: <TextSpan>[
TextSpan(text: usernametitle,
style: TextStyle(
color: Colors.black, fontSize: 18),
)
]
),
)
),
elevation: 1,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
leading: _logo(),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.notifications),
color: Colors.blueAccent,
tooltip: 'Show Notification',
onPressed: () {
},
),
IconButton(
color: Colors.lightGreen,
icon: const Icon(Icons.account_circle),
tooltip: 'Check your Profile',
onPressed: () {
},
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_text("EDIT SURVEY", FontWeight.bold, 20,Colors.blue),
roundedRectButton("BACK", signInGradients),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: screenWidth/1.6,
height: screenHeight/1.6,
decoration: BoxDecoration(
color: Colors.orange[200],
borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_text("SURVEY TITLE", FontWeight.bold, 17,Colors.white),
_text(data[0], FontWeight.bold, 19, Colors.black),
_text("DATE CREATED", FontWeight.bold, 17,Colors.white),
_text(data[1], null, 19, Colors.black),
_text("CURRENT STATUS", FontWeight.bold, 17,Colors.white),
_text(data[2], null, 19, Colors.black),
_text("LANGUAGE VERSION", FontWeight.bold, 17,Colors.white),
_text(data[3], null, 19, Colors.black),
_text("NUMBERS OF ASSESSORS", FontWeight.bold, 17,Colors.white),
_text(data[4], null, 19, Colors.black),
_text("TOTAL RENDERED SURVEYS", FontWeight.bold, 17,Colors.white),
_text(data[5], null, 19, Colors.black),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
onTap: (){
},
child: Container(width: 100,height: 50,child: Text("EDIT SURVEY")),
),
_text("LINKED DEVICES : $linkdevices", FontWeight.bold, 17,Colors.white),
],
)
],
),
)
),
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 1.0,
style: BorderStyle.solid
)
),
width: screenWidth/1.6,
height: screenHeight/1.6,
child: Column(
children: <Widget>[
_text("DEVICES PINNED", FontWeight.bold, 20,Colors.blue),
ListView.separated(
shrinkWrap: true,
itemCount: linkdevices,
itemBuilder: (context, index){
return Padding(
padding: const EdgeInsets.all(8.0),
child: _dropdownbutton(users, index),
);
},
separatorBuilder: (context, index) => Container(height: 10),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
InkWell(
child: roundedRectButton("ADD DEVICE", signInGradients),
onTap: (){
},
),
InkWell(
child: roundedRectButton("CLEAR ALL DEVICE", signInGradients),
onTap: (){
},
),
],
),
],
),
),
],
)
],
),
),
),
);
}
}
The Plan
The Result
im still trying to figure this out, but if someone can give me a lift,, im gonna be very thankful to who can help me out here ,,
You can copy paste run full code below
You can increase linkdevices and selectedUser
code snippet
List<Item> selectedUser = [null];
...
InkWell(
child: Text("ADD DEVICE"),
onTap: () {
selectedUser.add(null);
linkdevices ++;
setState(() {
});
working demo
full code
import 'package:flutter/material.dart';
class Item {
Item(this.name);
String name;
}
class editsurvey extends StatefulWidget {
#override
_editsurveyState createState() => _editsurveyState();
}
class _editsurveyState extends State<editsurvey> {
int surveyquestionnum = 1;
int surveyquestiontotal = 1;
List<Item> selectedUser = [null];
List<Item> selecteddata = [null, null];
List<Item> users;
int linkdevices = 1;
String dropdownvalue = "SELECT FROM DROPDOWN";
List data = [
'Sample Data 1',
'Sample Data 2',
'Sample Data 3',
'Sample Data 4',
'Sample Data 5',
'Sample Data 6',
];
#override
void initState() {
super.initState();
users = <Item>[
Item('Sample device 1'),
Item('Sample device 2'),
Item('Sample device 3'),
Item('Sample device 4'),
];
}
#override
Widget _dropdownbutton(List<Item> userlist, int index) {
return Container(
padding: EdgeInsets.all(1),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
border: Border.all(),
borderRadius: BorderRadius.all(Radius.circular(15.0) //
),
),
child: DropdownButton<Item>(
underline: SizedBox(),
isExpanded: true,
icon: Icon(Icons.arrow_drop_down),
hint: Text(" $dropdownvalue"),
value: selectedUser[index],
onChanged: (Item Value) {
print(Value.toString());
print(index);
setState(() {
selectedUser[index] = Value;
});
},
items: userlist.map((Item user) {
return DropdownMenuItem<Item>(
value: user,
child: Row(
children: <Widget>[
SizedBox(
width: 10,
),
Text(
user.name,
style: TextStyle(color: Colors.black),
),
],
),
);
}).toList(),
),
);
}
Widget _text(texthere, bold, size, color) {
return Text(texthere,
style: TextStyle(fontWeight: bold, fontSize: size, color: color),
overflow: TextOverflow.ellipsis,
maxLines: 1);
}
Widget _logo() {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => admincontent()),
);
},
child: Container(
width: 500, height: 200, child: Image.asset("images/v2.jpg")));
}
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
double screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Padding(
padding: EdgeInsets.only(left: 30),
child: RichText(
text: TextSpan(
text: 'Good Morning Welcome to Sample:',
style: TextStyle(color: Colors.blueAccent, fontSize: 18),
children: <TextSpan>[
TextSpan(
text: "usernametitle",
style: TextStyle(color: Colors.black, fontSize: 18),
)
]),
)),
elevation: 1,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
leading: _logo(),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.notifications),
color: Colors.blueAccent,
tooltip: 'Show Notification',
onPressed: () {},
),
IconButton(
color: Colors.lightGreen,
icon: const Icon(Icons.account_circle),
tooltip: 'Check your Profile',
onPressed: () {},
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_text("EDIT SURVEY", FontWeight.bold, 20.0, Colors.blue),
//roundedRectButton("BACK", signInGradients),
Text("BACK"),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: screenWidth / 1.6,
height: screenHeight / 1.6,
decoration: BoxDecoration(
color: Colors.orange[200],
borderRadius:
new BorderRadius.all(new Radius.circular(20.0)),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_text("SURVEY TITLE", FontWeight.bold, 17.0,
Colors.white),
_text(data[0], FontWeight.bold, 19.0, Colors.black),
_text("DATE CREATED", FontWeight.bold, 17.0,
Colors.white),
_text(data[1], null, 19.0, Colors.black),
_text("CURRENT STATUS", FontWeight.bold, 17.0,
Colors.white),
_text(data[2], null, 19.0, Colors.black),
_text("LANGUAGE VERSION", FontWeight.bold, 17.0,
Colors.white),
_text(data[3], null, 19.0, Colors.black),
_text("NUMBERS OF ASSESSORS", FontWeight.bold, 17.0,
Colors.white),
_text(data[4], null, 19.0, Colors.black),
_text("TOTAL RENDERED SURVEYS", FontWeight.bold,
17.0, Colors.white),
_text(data[5], null, 19.0, Colors.black),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
onTap: () {},
child: Container(
width: 100,
height: 50,
child: Text("EDIT SURVEY")),
),
_text("LINKED DEVICES : $linkdevices",
FontWeight.bold, 17.0, Colors.white),
],
)
],
),
)),
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 1.0,
style: BorderStyle.solid)),
width: screenWidth / 1.6,
height: screenHeight / 1.6,
child: Column(
children: <Widget>[
_text("DEVICES PINNED", FontWeight.bold, 20.0,
Colors.blue),
ListView.separated(
shrinkWrap: true,
itemCount: linkdevices,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: _dropdownbutton(users, index),
);
},
separatorBuilder: (context, index) => Container(height: 10),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
InkWell(
child: Text("ADD DEVICE"),
onTap: () {
selectedUser.add(null);
linkdevices ++;
setState(() {
});
/*listWidget.add( ListView.separated(
shrinkWrap: true,
itemCount: linkdevices,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: _dropdownbutton(users, index),
);
},
separatorBuilder: (context, index) => Container(height: 10),
));
setState(() {
});*/
},
),
InkWell(
child: Text("CLEAR ALL DEVICE"),
onTap: () {},
),
],
),
],
),
),
],
)
],
),
),
),
);
}
}
class admincontent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: editsurvey(),
);
}
}