Display TickMark widget depending on String and boolean value in Dart - flutter

Need to display icon with checkmark based on a String value that comes dynamically.
Like
this image is its pending show first widget with tick and rest are blank.
if delivered show with tick and the rest are blank.
Facing problems in creating logic using enums.
Currently, it displays the icons on button clicks
based on four constants which is fine with the widget CheckStatus.
Need to make in a way based on a boolean check if it's true and pending that pending tick widget displayed
and similar with other values.
Here is the complete code for it currently.
import 'package:dotted_border/dotted_border.dart';
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:matab/models/order.dart';
import 'package:matab/ui/general_widgets/check_status.dart';
import 'package:matab/ui/pages/styles.dart';
import '../../general_widgets/custom_gradient_button.dart';
class TrackOrder extends StatefulWidget {
const TrackOrder({Key? key, required this.order}) : super(key: key);
final Order order;
#override
State<TrackOrder> createState() => _TrackOrderState();
}
enum Status { Pending, Confirmed, Shipped, Received }
class _TrackOrderState extends State<TrackOrder> {
static const darkGreyColor = Colors.grey;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('Track Order')),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Get.back(),
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(height: 50),
Text(
"Order ID:" + widget.order.orderID,
style: const TextStyle(
color: darkGreyColor,
fontSize: 18,
fontWeight: FontWeight.bold),
),
const SizedBox(height: 50),
const Text('Sat, 12 Mar 2022',
style: TextStyle(
color: darkGreyColor,
fontSize: 18,
fontWeight: FontWeight.bold)),
const SizedBox(
height: 15,
),
Container(
margin: const EdgeInsets.fromLTRB(15, 0, 0, 0),
child: const Text('Estimated Time: 07 Days',
style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold)),
),
const SizedBox(height: 30),
SizedBox(
width: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
OrderStatusBar(title: widget.order.orderStatus, status: true),
dottedLine(),
OrderStatusBar(
title: widget.order.orderStatus, status: false),
dottedLine(),
OrderStatusBar(
title: widget.order.orderStatus, status: false),
dottedLine(),
OrderStatusBar(
title: widget.order.orderStatus, status: false),
],
),
),
const SizedBox(
height: 40,
),
Container(
margin: const EdgeInsets.fromLTRB(15, 0, 0, 0),
child: const Text('Shipping Address',
style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold)),
),
Center(
child: Text(widget.order.deliveryAddress.address,
style: const TextStyle(
color: Colors.grey,
fontSize: 18,
fontWeight: FontWeight.bold)),
),
Center(
child: Padding(
padding: const EdgeInsets.all(
50.0,
),
child: CustomGradientButton(
buttonText: "Track Order".tr, buttonFunction: () => {}),
),
),
Center(
child: Padding(
padding: const EdgeInsets.only(top: 18.0),
child: GestureDetector(
child: Text(
'Back to Home'.tr,
style: TextStyle(
color: mainColor,
fontSize: 23,
fontWeight: FontWeight.bold),
),
onTap: () => {
Get.off(CheckStatus(
order: widget.order,
))
},
),
),
)
],
),
),
);
}
}
class OrderStatusBar extends StatefulWidget {
const OrderStatusBar({Key? key, required this.title, required this.status})
: super(key: key);
final String title;
final bool status;
#override
State<OrderStatusBar> createState() => _OrderStatusBarState();
}
class _OrderStatusBarState extends State<OrderStatusBar> {
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Row(
children: [
widget.status ? dottedCircleWithCheckMark() : dottedCircle(),
const SizedBox(width: 30),
Text(
widget.title.tr,
style: TextStyle(
fontSize: 20,
fontWeight: widget.status ? FontWeight.bold : null,
),
),
],
),
);
}
}
const size = 25.0;
const strokeWidth = 1.0;
const checkedColor = Color.fromRGBO(232, 113, 65, 1);
Widget dottedLine() {
return Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.topRight,
child: Container(
margin: const EdgeInsets.fromLTRB(0, 0, size / 2, 0),
child: const Padding(
padding: EdgeInsets.only(left: 27 / 2),
child: SizedBox(
height: size,
child: DottedLine(
dashColor: Colors.black,
direction: Axis.vertical,
lineLength: size,
lineThickness: strokeWidth,
dashLength: 5,
dashGapLength: 5,
),
),
),
),
),
);
}
dottedCircle() {
return DottedBorder(
borderType: BorderType.Circle,
dashPattern: const [5, 5],
child: Container(
height: size,
width: size,
decoration: const BoxDecoration(shape: BoxShape.circle),
));
}
dottedCircleWithCheckMark() {
return Container(
height: size + strokeWidth * 2,
width: size + strokeWidth * 2,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: checkedColor,
),
child: const Icon(
Icons.check,
color: Colors.white,
size: size / 4 * 3,
),
);
}
// ignore_for_file: constant_identifier_names
class CheckStatus extends StatefulWidget {
const CheckStatus({Key? key, required this.order}) : super(key: key);
final Order order;
#override
State<CheckStatus> createState() => _CheckStatusState();
}
class _CheckStatusState extends State<CheckStatus> {
int selectedItemIndex = 0;
var pending = Status.Pending;
List<bool> orderStatus = [true,true,true,false];
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
for (int i = 0; i < Status.values.length; i++)
ElevatedButton(
onPressed: () {
selectedItemIndex = i;
setState(() {});
},
child: Text("Order Status ${Status.values[i]}"),
),
Row(
children: [
for (int i = 0; i <= selectedItemIndex; i++)
Container(
height: size + strokeWidth * 2,
width: size + strokeWidth * 2,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: checkedColor,
),
child: const Icon(
Icons.check,
color: Colors.white,
size: size / 4 * 3,
),
),
ElevatedButton(onPressed: () {}, child: Text("Back"))
],
)
],
),
);
}
}

Related

How do i correctly position these items horizontally in flutter to avoid overflow?

I have a list of items that are responsible for a tab bar design, i want to make all the sizedboxes display at a go and not overflow horizontally.
I will give my code for better clarification.
This is what i could come up with after over an hour of tussle:
And this is what i am expecting
I will give my code snippets of the view below.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
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",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 10.0),
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,
),
],
),
filterJobs()
],
),
);
}
Widget filterJobs() {
return Container(
width: double.infinity,
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: 10,
fontWeight: FontWeight.w500,
color: current == index
? Colors.white
: Colors.grey),
),
),
),
),
),
],
);
}),
),
// Builder(
// builder: (context) {
// switch (current) {
// case 0:
// return AllNotificationItemsView();
// case 1:
// return JobsNotificationItemsView();
// case 2:
// return MessagesNotificationItemsView();
// case 3:
// return CustomersNotificationItemsView();
// default:
// return SizedBox.shrink();
// }
// },
// )
],
),
);
}
}
The reason for overflow is List View Builder. Remove it and add a Row widget instead. Iterate the list item in it and you will get your desired output.
Full Code : -
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const JobsHeaderWidget(),
);
}
}
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({super.key});
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10, top: 5),
child: Align(
alignment: Alignment.topCenter,
child: Container(
constraints: const BoxConstraints(maxWidth: 610, maxHeight: 100),
alignment: Alignment.center,
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: 15.0, right: 15.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 19,
fontWeight: FontWeight.w500,
color: current == i
? Colors.white
: Colors.grey),
),
),
),
),
]
],
),
),
),
),
),
),
);
}
}
Output : -
Hey there for making the appbar not overflowing, you must use expanded widget. try to wrap your gestureDetector or whatever widget that you create for making the design for each listview child like this
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: current == i ? Colors.white : Colors.grey),
),
),
),
),
),
as you can see when you doing this the design will look like this
the text inside of the design would gone because of overflowing issue, you can change the text widget into this widget https://pub.dev/packages/auto_size_text
this is the snipet
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < items.length; i++) ...[
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: AutoSizeText(
items[i],
maxLines: 1,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color:
current == i ? Colors.white : Colors.grey),
),
),
),
),
),
]
],
),
),
));
but surely the text would be some of big and some of small look like this, and this is the result

Dynamically created widgets using json Data in listvew builder the TextFeild not working in flutter

I have created a list of the widgets using JSON data, I have five types of widgets, and each widget is added to the list depending on the JSON data, but the issue is with the widget includes a text field, All widget displays ok but once I click on the text field the keyboard appears and disappears immediately and gives this error "Exception caught by widgets library" => "Incorrect use of ParentDataWidget."
I try removing everything and adding just this text field widget in the list, but it still not working right. Please guide me on where am doing wrong.
import 'dart:io';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:my_car/AppUI/CustomWidgets/DateQuestionBox.dart';
import 'package:my_car/AppUI/CustomWidgets/MultiSelectQuestionBox.dart';
import 'package:my_car/AppUI/CustomWidgets/RadioQuestionBox.dart';
import 'package:my_car/AppUI/CustomWidgets/SelectQuestionBox.dart';
import 'package:my_car/AppUI/CustomWidgets/TextQuestionBox.dart';
import 'package:my_car/LocalData/AppColors.dart';
import 'package:flutter/services.dart';
import 'package:my_car/Models/MyClaimQuestionsResponse.dart';
import 'package:my_car/Models/VehiclesResponse.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../Models/VehiclesResponse.dart';
class SubmitClaimQuestionsPage extends StatefulWidget {
String vehicle;
String coverage;
SubmitClaimQuestionsPage(this.vehicle, this.coverage, {Key? key})
: super(key: key);
#override
SubmitClaimQuestionsState createState() =>
SubmitClaimQuestionsState(this.coverage, this.vehicle);
}
class SubmitClaimQuestionsState extends State {
String vehicle;
String coverage;
SubmitClaimQuestionsState(this.coverage, this.vehicle);
Future getMyVehicles() async {
final prefs = await SharedPreferences.getInstance();
final String? action = prefs.getString('vehiclesList');
VehiclesResponse myVehiclesResponse =
VehiclesResponse.fromJson(jsonDecode(action!));
return myVehiclesResponse.vehicles;
}
static List<MyCarClaimType> myCarClaims = <MyCarClaimType>[];
// Fetch content from the json file
Future generateQuestionsFromJson() async {
final String response = await rootBundle
.loadString('lib/Assets/JsonDataFiles/MyCarDataClaimQuestions.json');
MyClaimQuestionsResponse myClaimQuestionsResponse =
MyClaimQuestionsResponse.fromJson(jsonDecode(response));
if (myClaimQuestionsResponse.myCarClaimTypes.isNotEmpty) {
myCarClaims.clear();
myCarClaims = myClaimQuestionsResponse.myCarClaimTypes
.where((element) =>
element.claimType.toLowerCase() == coverage.toLowerCase())
.toList();
}
if (myCarClaims.isNotEmpty) {
setState(() {
for (var i = 0; i < myCarClaims.length; i++) {
if (myCarClaims[i].questionType == "TEXT") {
allQuestions.add(TextQuestionBox(myCarClaims[i]));
} else if (myCarClaims[i].questionType == "SELECT") {
allQuestions.add(SelectQuestionBox(myCarClaims[i]));
} else if (myCarClaims[i].questionType == "RADIO") {
allQuestions.add(RadioQuestionBox(myCarClaims[i]));
} else if (myCarClaims[i].questionType == "MULTI_SELECT") {
allQuestions.add(MultiSelectQuestionBox(myCarClaims[i]));
} else if (myCarClaims[i].questionType == "DATE") {
allQuestions.add(DateQuestionBox(myCarClaims[i]));
}
}
});
}
return allQuestions;
}
#override
void initState() {
super.initState();
generateQuestionsFromJson();
}
bool isVehicleSelected = false;
// ignore: unused_field
List<Widget> allQuestions = <Widget>[];
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
fontFamily: 'Lato',
),
home: Scaffold(
backgroundColor: Color(AppColors.bgColor),
body: SafeArea(
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Container(
margin: const EdgeInsets.only(top: 30, bottom: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.only(
bottom: 15,
left: 20,
right: 20,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Align(
alignment: Alignment.centerLeft,
child: SvgPicture.asset(
'lib/Assets/Images/backarrow.svg',
height: 20,
)),
),
Expanded(
child: Column(
children: [
Align(
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.only(right: 20),
child: Text(
vehicle,
textAlign: TextAlign.start,
style: const TextStyle(
fontSize: 18,
letterSpacing: -0.5,
fontWeight: FontWeight.w700,
),
),
),
),
Align(
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.only(right: 20),
child: Text(
coverage,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Color(AppColors.primaryBlueColor)),
),
),
),
],
)),
],
),
),
Flexible(
fit: FlexFit.loose,
child: ListView.builder(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
key: UniqueKey(),
itemCount: allQuestions.length,
itemBuilder: (BuildContext context, int index) {
return allQuestions[index];
},
),
),
const SizedBox(
width: 20,
),
],
),
),
Container(
width: double.infinity,
margin: const EdgeInsets.only(
left: 20,
right: 20,
top: 15,
),
child: TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.symmetric(vertical: 16)),
backgroundColor: MaterialStateProperty.all(
Color(AppColors.primaryBlueColor)),
shape:
MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
)),
),
child: Text(
'Submit Claim',
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15,
color:
Color(AppColors.primaryWhiteButtomTextColor)),
),
onPressed: () {},
),
),
],
),
),
),
),
),
);
}
}
My TextFeild widget is this:
import 'package:flutter/material.dart';
import 'package:my_car/LocalData/AppColors.dart';
import 'package:my_car/Models/MyClaimQuestionsResponse.dart';
class TextQuestionBox extends StatefulWidget {
MyCarClaimType claimObj;
TextQuestionBox(this.claimObj, {Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return TextQuestionBoxState(claimObj);
}
}
class TextQuestionBoxState extends State<TextQuestionBox> {
MyCarClaimType claimObj;
TextQuestionBoxState(this.claimObj);
TextEditingController txtControler = TextEditingController();
Widget get questionTxtBox {
return Container(
//width: double.infinity,
//height: 200,
margin: const EdgeInsets.symmetric(horizontal: 10),
padding: const EdgeInsets.all(10),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${claimObj.order + 1}. ",
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Expanded(
child: Text.rich(
//softWrap: false,
//overflow: TextOverflow.fade,
TextSpan(
text: claimObj.question,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,
),
children: <InlineSpan>[
TextSpan(
text: claimObj.isMandatory == "YES" ? "*" : "",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,
color: Color(AppColors.primaryBlueColor)),
),
])),
),
],
),
const SizedBox(
height: 10,
),
Container(
height: 110,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(15))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: TextField(
controller: txtControler,
keyboardType: TextInputType.multiline,
//maxLines: null,
style: const TextStyle(
fontSize: 14, fontWeight: FontWeight.w500),
decoration: const InputDecoration(
border: InputBorder.none,
filled: true,
fillColor: Colors.transparent,
hintText: 'Description',
),
),
),
Container(
margin: const EdgeInsets.only(bottom: 10, right: 15),
child: Text(
'Min. 40 Letters',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color(AppColors.greyText)),
))
],
)),
],
),
);
}
#override
Widget build(BuildContext context) {
return questionTxtBox;
}
}
TextFields usually try to expand to the available width. This can be problematic in a Column where usually only height is fixed and the Textfield tries to expand into infinity. You should try wrapping the TextField in a Widget that gives it a fixed width like a SizedBox.

Flutter TabController late initializer

I am creating an app and I am working on the profile setup and am using a tabcontroller. I have my tabcontroller working to navigate my first 3 screens, but for some reason I get a "late initializtion" error for my last screen. I have a custom button that I use for each screen, and the error gets shown once I add the custom button to my last acrren. Could someone explain to me what I need to do to get it working for my last screen? I've attached my code for the tabcontroller, custom button, and my last screen:
Tabcontroller onboarding model:
class AccountOnboarding extends StatefulWidget {
const AccountOnboarding({Key? key}) : super(key: key);
#override
State<AccountOnboarding> createState() => _AccountOnboardingState();
}
class _AccountOnboardingState extends State<AccountOnboarding> {
static const List<Tab> tabs = <Tab>[
Tab(text: 'Name'),
Tab(text: 'Age and Profile'),
Tab(text: 'Bio and Interests'),
Tab(text: 'Selection')
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: tabs.length,
child: Builder(builder: (BuildContext context) {
final TabController tabController = DefaultTabController.of(context)!;
tabController.addListener(() {
if (!tabController.indexIsChanging) {}
});
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
title: Row(
children: [
Expanded(
child: Image.asset('assets/images/Logo_Strength.png',
height: 50),
),
Expanded(
flex: 2,
child: RichText(
text: TextSpan(
style: GoogleFonts.montserrat(
fontSize: 30),
children: <TextSpan> [
TextSpan(text: 'Stren',
style: GoogleFonts.montserrat(
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
])),
TextSpan(text: ';',
style: GoogleFonts.montserrat(
color: const Color(0xffef6a7a), fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
])),
TextSpan(text: 'th',
style: GoogleFonts.montserrat(
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
]))
],
),
),
),
],
)
),
body: TabBarView(
// physics: const NeverScrollableScrollPhysics(),
children: [
NamePage(tabController: tabController,),
ageAndPicture(tabController: tabController,),
bioAndInterests(tabController: tabController,),
SelectionPage(tabController: tabController,)
],
),
);
}));
}}
Custom Button:
class CustomButton extends StatelessWidget {
final TabController tabController;
const CustomButton({Key? key,
required this.tabController})
: super(key: key);
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
vertical: 16),
elevation: 0,
primary: Colors.transparent
),
onPressed: () {
tabController.animateTo(tabController.index + 1);
},
child: Container(
width: double.infinity,
child: Center(
child: Text('Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),),
),
)
),
);
}
}
Last Screen code:
class SelectionPage extends StatefulWidget {
final TabController tabController;
const SelectionPage({Key? key,
required this.tabController}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class _SelectionPageState extends State<SelectionPage>{
List <Item>listOfModel = [];
late TabController tabController;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
String retrieveString;
final data = ModalRoute.of(context)!.settings;
if (data.arguments == null) {
retrieveString = "empty";
} else {
retrieveString = data.arguments as String;
}
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Stress and anxiety management"));
listOfModel.add(Item(title: "Maintaing a better work-life balance"));
listOfModel.add(Item(title: "Personal growth and development"));
listOfModel.add(Item(title: "Being happier and more content in life"));
listOfModel.add(Item(title: "Mental and emotional well-being"));
double _height = MediaQuery.of(context).size.height;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.07,
bottom: _height * 0.05),
child: Column(
children: [
Column(
children: [
Column(
children: <Widget>[
Text('Hello there $retrieveString! What all would you like to focus on?',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 10),
Text("You can pick all that apply:",
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 14.5,
fontWeight: FontWeight.w600
),),
const SizedBox(height: 15,),
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: [
gridItem(listOfModel[0],MyFlutterApp.relationships),
gridItem(listOfModel[1],MyFlutterApp2.meditate),
gridItem(listOfModel[2],MyFlutterApp.balance),
gridItem(listOfModel[3],MyFlutterApp2.personal_growth),
gridItem(listOfModel[4],MyFlutterApp.happy),
gridItem(listOfModel[5],MyFlutterApp3.well_rounded),
],
),
const SizedBox(height: 18,),
],
),
CustomButton(tabController: tabController)
],
),
],
),
),
);
}
Widget gridItem(Item item, IconData icon){
return GestureDetector(
onTap: () {
setState(() {
item.isSelected = !item.isSelected;
});
},
child: Stack(
children: [Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: item.isSelected ? Color.fromARGB(255, 234, 188, 193) : Colors.white
),
child: Column(
children: [
Align(alignment: Alignment.topCenter,
child: Icon(
icon,
color: const Color(0xff31708c),
size: 45,
),
),
const SizedBox(height: 4,),
Text(item.title,
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,),
],
),
),
Positioned(
top: 0,
right: 0,
child: Offstage(
offstage: !item.isSelected,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 2.5),
shape: BoxShape.circle),
child: const Icon(
Icons.check,
color: Colors.green,
),
),
),
)
],
)
);
}
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
}
Remove
late TabController tabController;
in SelectionPage and change
CustomButton(tabController: tabController)
in SelectionPage to
CustomButton(tabController: widget.tabController)

How to create This Ui in - Flutter

Hello there I'm new to flutter and I want to achieve this certain UI. from the UI I can see -
At the top it has a custom search bar I don't know if it's an appbar or not.
It has a SizedBox or something similar below the searchbar.
It has A listview.builder (I already Know how to achieve this)
So I would like to ask how to achieve the first two contents of the app
here is a screenshot of the app
You can take this as an example. a similar design.
import 'package:flutter/material.dart';
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
children: [
const SizedBox(
height: 30,
),
buildTitleText(context),
const SizedBox(
height: 30,
),
buildSearchBar(context),
const SizedBox(
height: 30,
),
buildSecondTitle(context),
const SizedBox(
height: 10,
),
buildContent(context)
],
),
),
);
}
SizedBox buildSecondTitle(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width - 65,
child: Row(
children: const [
Text(
'Favorite Places',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
TextButton(
onPressed: null,
child: Text(
'See All',
style: TextStyle(color: Colors.blue, fontSize: 18),
)),
],
),
);
}
Container buildTitleText(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width - 50,
child: const Text(
"What you would like to find?",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 30,
),
),
);
}
SingleChildScrollView buildContent(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
const SizedBox(
width: 25,
),
buildCityCard(context,
photoName: 'img_istanbul.jpg',
cityName: 'İstanbul',
cityActivity: '98 Aktivite',
cityScore: '4.8'),
const SizedBox(
width: 25,
),
buildCityCard(context,
photoName: 'img_mugla.jpg',
cityName: 'Muğla',
cityActivity: '102 Aktivite',
cityScore: '4.7'),
const SizedBox(
width: 25,
),
buildCityCard(context,
photoName: 'img_antalya.jpg',
cityName: 'Antalya',
cityActivity: '98 Aktivite',
cityScore: '4.5'),
const SizedBox(
width: 25,
),
],
),
);
}
Container buildSearchBar(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width - 65,
child: TextField(
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.search,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(360),
borderSide: const BorderSide(
color: Colors.blueAccent,
width: 2,
)),
labelText: "Locaiton",
),
),
);
}
Container buildCityCard(BuildContext context,
{required String photoName,
required String cityName,
required String cityActivity,
required String cityScore}) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
height: MediaQuery.of(context).size.height / 2.5,
width: MediaQuery.of(context).size.height / 3.7,
child: Column(
children: [
Expanded(
flex: 5,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.blue,
image: DecorationImage(
image: AssetImage("assets/images/${photoName}"),
fit: BoxFit.fill,
),
),
),
),
const SizedBox(
height: 10,
),
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
width: 20,
),
Icon(Icons.location_on, color: Colors.blue),
Text(
"${cityName}",
style: const TextStyle(
fontSize: 16, fontWeight: FontWeight.bold),
),
],
),
),
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
width: 20,
),
const Icon(
Icons.star,
color: Colors.yellow,
),
Text(
"${cityScore}",
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const Padding(
padding: EdgeInsets.fromLTRB(95, 0, 0, 0),
child: Icon(Icons.arrow_forward_ios),
),
],
),
),
const SizedBox(
height: 10,
),
],
),
);
}
}
This is the home. If you want to use tabbar.
import 'package:circle_bottom_navigation_bar/circle_bottom_navigation_bar.dart';
import 'package:circle_bottom_navigation_bar/widgets/tab_data.dart';
import 'package:flutter/material.dart';
import 'package:inovatif/third_screen.dart';
import 'first_screen.dart';
import 'second_screen.dart';
class HomeView extends StatefulWidget {
HomeView({Key? key}) : super(key: key);
static String routeName = 'home';
#override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
int currentPage = 0;
final List<Widget> _pages = [
FirstScreen(),
SecondScreen(),
ThirdScreen(),
];
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final viewPadding = MediaQuery.of(context).viewPadding;
double barHeight;
double barHeightWithNotch = 67;
double arcHeightWithNotch = 67;
if (size.height > 700) {
barHeight = 70;
} else {
barHeight = size.height * 0.1;
}
if (viewPadding.bottom > 0) {
barHeightWithNotch = (size.height * 0.07) + viewPadding.bottom;
arcHeightWithNotch = (size.height * 0.075) + viewPadding.bottom;
}
return Scaffold(
appBar: AppBar(backgroundColor: Colors.transparent, elevation: 0),
body: _pages[currentPage],
bottomNavigationBar: buildCircleBottomNavigationBar(
viewPadding, barHeightWithNotch, barHeight, arcHeightWithNotch),
);
}
CircleBottomNavigationBar buildCircleBottomNavigationBar(
EdgeInsets viewPadding,
double barHeightWithNotch,
double barHeight,
double arcHeightWithNotch) {
return CircleBottomNavigationBar(
initialSelection: currentPage,
barHeight: viewPadding.bottom > 0 ? barHeightWithNotch : barHeight,
arcHeight: viewPadding.bottom > 0 ? arcHeightWithNotch : barHeight,
itemTextOff: viewPadding.bottom > 0 ? 0 : 1,
itemTextOn: viewPadding.bottom > 0 ? 0 : 1,
circleOutline: 15.0,
shadowAllowance: 0.0,
circleSize: 50.0,
blurShadowRadius: 50.0,
circleColor: Colors.purple,
activeIconColor: Colors.white,
inactiveIconColor: Colors.grey,
tabs: getTabsData(),
onTabChangedListener: (index) => setState(() => currentPage = index),
);
}
List<TabData> getTabsData() {
return [
TabData(
icon: Icons.home,
iconSize: 25.0,
title: 'Home',
fontSize: 12,
fontWeight: FontWeight.bold,
),
TabData(
icon: Icons.phone,
iconSize: 25,
title: 'Emergency',
fontSize: 12,
fontWeight: FontWeight.bold,
),
TabData(
icon: Icons.search,
iconSize: 25,
title: 'Search Place',
fontSize: 12,
fontWeight: FontWeight.bold,
),
// TabData(
// icon: Icons.alarm,
// iconSize: 25,
// title: 'Alarm',
// fontSize: 12,
// fontWeight: FontWeight.bold,
// ),
];
}
}
To create an page like this you will need to know about Text,SingleChildScrollView set scroll direction to horizontal,Bottom Navigation bar,Banner etc.

How to change the background color of an item in a list when using the function List.generate in flutter

function description: when an item is clicked, change the background color of this item 。
I defined the variable color in the List.generate function and used the setState function in onTapDown to modify this value, but it has no effect. what should I do?
my code is as follows
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class Homepage extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Homepage> {
final titles = ["AAA", "BBB", "CCC", "DDD"];
final subtitles = [
"我去,额度这么高?",
"XX,你上次给我兑换的烤箱还不错哦",
"抱歉,我觉得我们不是很合适",
"邻居你好,你家的租户最近有点吵"
];
final date = ["昨天 18:08", "星期二", "7月21日", "7月19日"];
final avatar = [
"WechatIMG325.jpeg",
"WechatIMG326.jpeg",
"WechatIMG327.jpeg",
"WechatIMG328.jpeg"
];
// final icons = [Icons.ac_unit, Icons.access_alarm, Icons.access_time];
#override
Widget build(BuildContext context) {
return Column(
children: [
...List.generate(titles.length, (index) {
var color = Colors.white;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (TapDownDetails details) {
setState(() {
color = Colors.grey;
});
debugPrint("presed GestureDetector");
},
onTapUp: (TapUpDetails details) {
setState(() {
color = Colors.white;
});
debugPrint("presed GestureDetector");
},
child: Container(
color: color,
margin: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(children: [
SizedBox(
width: 50,
child: Container(
margin: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.asset("assets/images/${avatar[index]}",
height: 50, width: 50),
),
),
),
//const SizedBox(width: 10),
IntrinsicWidth(
child: Container(
margin: const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
titles[index],
style: const TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.w300,
),
),
const SizedBox(height: 5),
Text(
subtitles[index],
style: const TextStyle(
fontSize: 15,
color: Colors.black54,
fontWeight: FontWeight.w300,
),
),
],
),
),
),
]),
),
);
}),
],
);
}
}
try this code will help you to start in OOP and make model to data in your app and you can add any thing to class like Icon ....
class FakeData {
final String title, subTitle, avatar, data;
bool onTapDown;
FakeData(
{required this.title,
this.onTapDown = false,
required this.subTitle,
required this.avatar,
required this.data});
}
this class collect data app and state for all item
class HomeState extends State<Homepage> {
final fakeData = [
FakeData(
title: 'AAA',
subTitle: '我去,额度这么高?',
avatar: "WechatIMG325.jpeg",
data: "昨天 18:08",
),
FakeData(
title: 'BBB',
subTitle: "XX,你上次给我兑换的烤箱还不错哦",
avatar: "WechatIMG326.jpeg",
data: "星期二",
),
FakeData(
title: 'CCC',
subTitle: "抱歉,我觉得我们不是很合适",
avatar: "WechatIMG327.jpeg",
data: "7月21日",
),
FakeData(
title: 'DDD',
subTitle: "邻居你好,你家的租户最近有点吵",
avatar: "WechatIMG328.jpeg",
data: "7月19日",
),
];
// final icons = [Icons.ac_unit, Icons.access_alarm, Icons.access_time];
#override
Widget build(BuildContext context) {
return Column(
children: [
...List.generate(fakeData.length, (index) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (TapDownDetails details) {
setState(() {
fakeData[index].onTapDown = !fakeData[index].onTapDown;
});
debugPrint("presed GestureDetector");
},
onTapUp: (TapUpDetails details) {
setState(() {
fakeData[index].onTapDown = !fakeData[index].onTapDown;
});
debugPrint("presed GestureDetector");
},
child: Container(
color: fakeData[index].onTapDown ? Colors.grey : Colors.white,
margin: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(children: [
SizedBox(
width: 50,
child: Container(
margin: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.asset(
"assets/images/${fakeData[index].avatar}",
height: 50,
width: 50),
),
),
),
//const SizedBox(width: 10),
IntrinsicWidth(
child: Container(
margin: const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
fakeData[index].title,
style: const TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.w300,
),
),
const SizedBox(height: 5),
Text(
fakeData[index].subTitle,
style: const TextStyle(
fontSize: 15,
color: Colors.black54,
fontWeight: FontWeight.w300,
),
),
],
),
),
),
]),
),
);
}),
],
);
}
}
The variable color needs to be outside the build method of the State, this code will reset the color to Colors.white on each build.
import 'package:flutter/material.dart';
class Homepage extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Homepage> {
final titles = ["AAA", "BBB", "CCC", "DDD"];
final subtitles = [
"我去,额度这么高?",
"XX,你上次给我兑换的烤箱还不错哦",
"抱歉,我觉得我们不是很合适",
"邻居你好,你家的租户最近有点吵"
];
final date = ["昨天 18:08", "星期二", "7月21日", "7月19日"];
final avatar = [
"WechatIMG325.jpeg",
"WechatIMG326.jpeg",
"WechatIMG327.jpeg",
"WechatIMG328.jpeg"
];
var color = Colors.white;
// final icons = [Icons.ac_unit, Icons.access_alarm, Icons.access_time];
#override
Widget build(BuildContext context) {
return Column(
children: [
...List.generate(titles.length, (index) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (TapDownDetails details) {
setState(() {
color = Colors.grey;
});
debugPrint("presed GestureDetector");
},
onTapUp: (TapUpDetails details) {
setState(() {
color = Colors.white;
});
debugPrint("presed GestureDetector");
},
child: Container(
color: color,
margin: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Row(children: [
SizedBox(
width: 50,
child: Container(
margin: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.asset("assets/images/${avatar[index]}",
height: 50, width: 50),
),
),
),
//const SizedBox(width: 10),
IntrinsicWidth(
child: Container(
margin: const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
titles[index],
style: const TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.w300,
),
),
const SizedBox(height: 5),
Text(
subtitles[index],
style: const TextStyle(
fontSize: 15,
color: Colors.black54,
fontWeight: FontWeight.w300,
),
),
],
),
),
),
]),
),
);
}),
],
);
}
}
The code above should work as our state is extracted outside of the build method and it would update correctly with each setState.