Flutter Pie chart with Image Widget - flutter

I'm Using fl_chart: ^0.12.2 for add PIE chart in to the my app. But i'm unable to add add image on very section
I want something similar to this

Working demo is modification of PieChartSample2
official example https://github.com/imaNNeoFighT/fl_chart/blob/master/example/lib/pie_chart/samples/pie_chart_sample2.dart
You can in PieChartSectionData use badgeWidget and set badgePositionPercentageOffset
/// If [badgeWidget] is not null, it draws a widget at the middle of section,
/// by default it draws the widget at the middle of section, but you can change the
/// [badgePositionPercentageOffset] to have your desire design,
/// the value works the same way as [titlePositionPercentageOffset].
code snippet
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
...
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
...
working demo
full code of modified PieChartSample2
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'indicator.dart';
class _Badge extends StatelessWidget {
final String svgAsset;
final double size;
final Color borderColor;
const _Badge(
this.svgAsset, {
Key key,
#required this.size,
#required this.borderColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: PieChart.defaultDuration,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(
color: borderColor,
width: 2,
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(.5),
offset: const Offset(3, 3),
blurRadius: 3,
),
],
),
padding: EdgeInsets.all(size * .15),
child: Center(
child: kIsWeb
? Image.network(svgAsset, fit: BoxFit.contain)
: SvgPicture.asset(
svgAsset,
fit: BoxFit.contain,
),
),
);
}
}
class PieChartSample2 extends StatefulWidget {
#override
State<StatefulWidget> createState() => PieChart2State();
}
class PieChart2State extends State {
int touchedIndex;
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData:
PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections()),
),
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
default:
return null;
}
});
}
}
full code for png
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'indicator.dart';
class _Badge extends StatelessWidget {
final String svgAsset;
final double size;
final Color borderColor;
const _Badge(
this.svgAsset, {
Key key,
#required this.size,
#required this.borderColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: PieChart.defaultDuration,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(
color: borderColor,
width: 2,
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(.5),
offset: const Offset(3, 3),
blurRadius: 3,
),
],
),
padding: EdgeInsets.all(size * .15),
child: Center(
child: kIsWeb
? Image.network(svgAsset, fit: BoxFit.contain)
: Image.asset(svgAsset, fit: BoxFit.contain) /*SvgPicture.asset(
svgAsset,
fit: BoxFit.contain,
)*/,
),
);
}
}
class PieChartSample2 extends StatefulWidget {
#override
State<StatefulWidget> createState() => PieChart2State();
}
class PieChart2State extends State {
int touchedIndex;
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData:
PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections()),
),
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
default:
return null;
}
});
}
}

Related

The argument type 'Future<List<PieChartSectionData>>' can't be assigned to the parameter type 'List<PieChartSectionData>?'

I want to display a chart that retrieve from firebase firestore but its says that
The argument type 'Future<List<PieChartSectionData>>' can't be assigned to the parameter type 'List<PieChartSectionData>?' on the line sections: showingSections();
. Here are my codes,
children: <Widget>[
const SizedBox(height: 18),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData: PieTouchData(
touchCallback:
(FlTouchEvent event,
pieTouchResponse) {},
),
borderData: FlBorderData(
//show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections(), // this is the error //
),
),
),
),
Column(
mainAxisAlignment:
MainAxisAlignment.end,
crossAxisAlignment:
CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Colors.blue,
text: 'Fiest',
isSquare: true,
),
],
),
],
this is my function,
Future<List<PieChartSectionData>> showingSections() async {
int count = await subuhPrayedOnTime();
int count2 = await subuhPrayedLate();
double percentage1 = count * 0.4;
double percentage2 = count2 * 0.10;
return [
PieChartSectionData(
color: Colors.blueAccent,
value: percentage1,
title: '${percentage1.toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
//shadows: shadows,
),
),
PieChartSectionData(
color: Colors.blueAccent,
value: percentage2,
title: '${percentage2.toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
//shadows: shadows,
),
),
];
}
Try changing return type of the function from
Future<List<PieChartSectionData>> showingSections() async {
int count = await subuhPrayedOnTime();
int count2 = await subuhPrayedLate();
double percentage1 = count * 0.4;
double percentage2 = count2 * 0.10;
return [
PieChartSectionData(
color: Colors.blueAccent,
value: percentage1,
title: '${percentage1.toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
//shadows: shadows,
),
),
PieChartSectionData(
color: Colors.blueAccent,
value: percentage2,
title: '${percentage2.toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
//shadows: shadows,
),
),
];
}
To
List<PieChartSectionData> showingSections() async {
int count = await subuhPrayedOnTime();
int count2 = await subuhPrayedLate();
double percentage1 = count * 0.4;
double percentage2 = count2 * 0.10;
return [
PieChartSectionData(
color: Colors.blueAccent,
value: percentage1,
title: '${percentage1.toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
//shadows: shadows,
),
),
PieChartSectionData(
color: Colors.blueAccent,
value: percentage2,
title: '${percentage2.toStringAsFixed(0)}%',
radius: 60,
titleStyle: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black,
//shadows: shadows,
),
),
];
}
showingSections is a future method, you need to await/FutureBuilder to fetch data.
For your case, create a future on state class[if stateFullWidget].
late final dFuture = showingSections();
and use like
Expanded(
child: FutureBuilder<List<PieChartSectionData>>(
future: dFuture,
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data != null) {
return AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData: PieTouchData(
touchCallback:
(FlTouchEvent event, pieTouchResponse) {},
),
borderData: FlBorderData(
//show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: snapshot.data!, // this is the error //
),
),
);
}
return CircularProgressIndicator();
}),
),
Find more about FutureBuilder

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)

Display TickMark widget depending on String and boolean value in Dart

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"))
],
)
],
),
);
}
}

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.

Why do I get a huge grey circle in the background of scaffold?

I have a PayBills() widget screen = that has 2 tabs which each display a separate tab dart file which I've specified, but I get a huge grey circle in the background of the first dart file and I get nothing in the second tab, but I don't know where the issue is.
PayBills() widget screen code :
import 'package:flutter/material.dart';
import '../../constans/constants.dart';
import 'first_tab.dart';
import 'second_tab.dart';
class PayBills extends StatefulWidget {
#override
_PayBillsState createState() => _PayBillsState();
}
class _PayBillsState extends State<PayBills>
with SingleTickerProviderStateMixin {
TabController _controller;
#override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: 2);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
elevation: 0,
title: Text(
'تسديد فاتورة',
style: TextStyle(
color: leaderLogo,
fontSize: 24,
fontFamily: 'Calibri',
),
),
bottom: TabBar(
controller: _controller,
tabs: [
Tab(
child: Text(
'فواتير مستحقة',
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 14,
color: Colors.black,
),
),
),
Tab(
child: Text(
'فواتير مدفوعة',
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 14,
color: Colors.black,
),
),
),
],
),
),
body: TabBarView(
controller: _controller,
children: [
PayBillsList(),
SecondTab(),
],
));
}
}
first_tab widget code :
import 'package:flutter/material.dart';
import '../../constans/constants.dart';
class BillDetails extends StatelessWidget {
final String billName;
final String billImage;
final String billDate;
const BillDetails({Key key, this.billName, this.billImage, this.billDate})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
top: 20,
right: 5,
left: 5,
),
width: 378,
height: 93,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(5),
),
child: ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage(billImage),
backgroundColor: Colors.white,
),
title: Text(
billName,
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 16,
color: Colors.black,
),
),
subtitle: Text(
billDate,
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 12,
color: Colors.black,
),
),
trailing: RaisedButton(
color: raisedButtonColor,
onPressed: () {},
child: Text(
"دفع",
style: TextStyle(
color: Colors.white,
),
),
),
));
}
}
class PayBillsList extends StatelessWidget {
final List<BillDetails> billsList = [
BillDetails(
billName: 'فاتورة كهرباء',
billImage: 'assets/images/electricity.png',
billDate: '30 / 4 / 2020',
),
BillDetails(
billName: 'فاتورة مياه',
billImage: 'assets/images/water.png',
billDate: '30 / 4 / 2020',
),
];
#override
Widget build(BuildContext context) {
return Container(
width: 378,
height: 93,
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: ListView.builder(
itemBuilder: (context, index) {
return BillDetails(
billName: billsList.elementAt(index).billName,
billImage: billsList.elementAt(index).billImage,
billDate: billsList.elementAt(index).billDate,
);
},
shrinkWrap: true,
itemCount: billsList.length,
scrollDirection: Axis.vertical,
),
);
}
}
class PayButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ButtonTheme(
minWidth: 20,
height: 20,
child: RaisedButton(
onPressed: () {},
color: raisedButtonColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Center(
child: Text(
//Login button text properties
'دفع',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontFamily: 'Calibri',
)),
),
),
);
}
}
You used a circle shape for BoxDecoration. Comment this line:
shape: BoxShape.circle,
Container(
width: 378,
height: 93,
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
// shape: BoxShape.circle,
),