I need a tab bar with the following effect:
Right now my code stands at:
SliverPersistentHeader(
pinned: true,
delegate: SliverAppBarDelegate(
TabBar(
isScrollable: true,
indicatorSize: TabBarIndicatorSize.tab,
indicator: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white70, Colors.grey],
),
borderRadius: BorderRadius.circular(20),
color: Colors.red,
),
labelColor: CustomColors.primary,
unselectedLabelColor: CustomColors.secondary,
tabs: categories
.map((category) => Tab(
text: category,
))
.toList(),
controller: _tabController,
),
),
),
And the delegate:
class SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
SliverAppBarDelegate(this._tabBar);
final TabBar _tabBar;
#override
double get minExtent => _tabBar.preferredSize.height;
#override
double get maxExtent => _tabBar.preferredSize.height;
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
height: 80,
color: CustomColors.white,
child: _tabBar,
);
}
#override
bool shouldRebuild(SliverAppBarDelegate oldDelegate) {
return false;
}
}
The current tab bar "tabs" are on default height. How can I achieve the same as the picture?
N.B: The SliverAppBarDelegate is in a separate file. Is it possible to move the TabBar() to another file as well?
This maybe works for you
tabController.index get the current index of the tab then you can decide what behavior show in any case
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
List<String> categories = [
'All',
'Food',
'Drink',
'Clothes',
'Electronics',
'Others'
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: DefaultTabController(
length: categories.length,
child: Builder(builder: (BuildContext context) {
final TabController tabController =
DefaultTabController.of(context)!;
tabController.addListener(() {
if (!tabController.indexIsChanging) {
int index = tabController.index;
setState(() {});
// Your code goes here.
// To get index of current tab use tabController.index
}
});
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
shape: const Border(
bottom: BorderSide(color: Colors.black12, width: 1),
),
backgroundColor: Colors.transparent,
elevation: 0,
bottom: TabBar(
labelColor: Colors.white,
indicatorColor: Colors.transparent,
isScrollable: true,
padding: const EdgeInsets.all(3),
tabs: categories
.map(
(category) => Tab(
icon: Container(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.06,
decoration: tabController.index ==
categories.indexOf(category)
? BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 10,
// offset: Offset(3, 6),
)
],
)
: const BoxDecoration(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.ac_unit,
color: Colors.black54,
),
Text(
category,
style: const TextStyle(
color: Colors.black54,
fontSize: 18,
),
)
],
),
),
),
)
.toList(),
),
),
body: TabBarView(
controller: tabController,
children: const [
Center(child: Text('All')),
Center(child: Text('Food')),
Center(child: Text('Drink')),
Center(child: Text('Clothes')),
Center(child: Text('Electronics')),
Center(child: Text('Others')),
],
),
);
})),
);
}
}
looks like
Related
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class TestDemo extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
TabController? controller;
int pos = 0;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
bottom: TabBar(
controller: controller,
onTap: (int) {
setState(() {
pos = int;
});
print("Pos" + int.toString());
},
unselectedLabelColor: Color(0xFF82868a),
labelColor: Colors.white,
indicatorSize: TabBarIndicatorSize.label,
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.black),
tabs: [
Tab(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: pos == 0
? Colors.transparent
: const Color(0xFFf6f6f6),
),
child: const Align(
alignment: Alignment.center,
child: Text("New"),
),
),
),
Tab(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color:
pos == 1 ? Colors.transparent : Color(0xFFf6f6f6),
),
child: Align(
alignment: Alignment.center,
child: Text(
"Confirmed",
),
),
),
),
Tab(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color:
pos == 2 ? Colors.transparent : Color(0xFFf6f6f6),
),
child: Align(
alignment: Alignment.center,
child: Text("In Transits"),
),
),
),
]),
),
body: TabBarView(controller: controller,
dragStartBehavior: DragStartBehavior.down,
children: [
Icon(Icons.apps),
Icon(Icons.movie),
Icon(Icons.games),
]),
));
}
}
Above code is for tabbar view. On click of tab selected tab color is highlighted and unselected color will update as in grey. but when I swipe tabbar, tab color is not updating. Indicator is just override below the container
I want to change tab color on tab click as well on tab swipe.
How to implemet same functionality on tap and swipe ?
You need to update your pos variable whenever controller.index updates. You can listen to it's changes like this:
late TabController controller = TabController(length: 3, vsync: this);
#override
void initState() {
controller.addListener(() {
setState(() {
pos = controller.index;
});
});
super.initState();
}
Just remove container decoration in every tab in your code, it will work for swipe and on-tap both
Tab(
child: Container(
child: Align(
alignment: Alignment.center,
child: Text("In Transits"),
),
),
),
I have studied about creating Tabbar in Flutter but as so far I know We can create Tabbar inside AppBar widget which is inside Scaffold widget.
But I want something like below :
So far I have as below:
I have created Tab screens but have to manage tab selections as above.
As you can see above, Appbar is different and tabbar is outside Appbar,
How can I manage this to customise this Tabs in Flutter? Thanks.
try this
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(
"Facilities",
style: TextStyle(color: Colors.black, fontSize: 20),
),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.search,
size: 26.0,
),
)),
],
backgroundColor: Colors.white,
elevation: 0,
bottom: TabBar(
unselectedLabelColor: Colors.redAccent,
indicatorSize: TabBarIndicatorSize.tab,
indicator: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.redAccent, Colors.orangeAccent]),
borderRadius: BorderRadius.circular(6),
color: Colors.redAccent),
tabs: [
Tab(
child: Align(
alignment: Alignment.center,
child: Text("Attraction"),
),
),
Tab(
child: Align(
alignment: Alignment.center,
child: Text("Events"),
),
),
Tab(
child: Align(
alignment: Alignment.center,
child: Text("Utils"),
),
),
]),
),
body: TabBarView(children: [
Icon(Icons.apps),
Icon(Icons.movie),
Icon(Icons.games),
]),
));
}
}
I want to make a custom tab widget and set a list of this widgets to a tab bar. But tab bar can't take all space and some space will remain. I try to wrap it with PreferredSize but it doesn't work .
The tab bar (ScrollTabBar) :
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black54,
blurRadius: 5.0,
offset: Offset(0.0, 0.75),
),
],
borderRadius: BorderRadius.circular(widget.borderRadiusT),
color: Colors.red,
),
height: widget.tabHeight,
child: PreferredSize(
preferredSize: Size.fromHeight(widget.tabHeight),
child: TabBar(
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: widget.indicatorColor,
width: widget.indicatorWheight,
),
insets: EdgeInsets.symmetric(
horizontal: widget.horizontalPadding,
),
),
indicatorWeight: widget.indicatorWheight,
indicatorColor: widget.indicatorColor,
labelPadding: EdgeInsets.only(
bottom: 0,
right: widget.horizontalPadding,
left: widget.horizontalPadding,
),
labelColor: widget.activeTextColor,
unselectedLabelColor: widget.diactiveTextColor,
controller: widget.tabController,
tabs: widget.tabList,
isScrollable: true,
),
),
),
Expanded(
child: TabBarView(
controller: widget.tabController,
children: [
for (var builder in widget.screenList) builder.call(context)
],
),
),
],
),
);
}
tabList is list of FTabComp :
FTabComp(
String title,
Key key,
ScrollTabBar parent, {
bool haveDivider = true,
}) {
return Tab(
key: key,
child: Container(
color: Colors.blue,
width: parent.tabLength,
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.center,
child: Text(title),
),
haveDivider
? Positioned.fill(
left: parent.tabLength * - 1.5,
child: SizedBox(
height: double.maxFinite,
child: VerticalDivider(
color: parent.outerBackgroundColor,
thickness: parent.dviderWidth,
),
),
)
: Center()
,
],
),
),
);
}
Container are red . Tabs are blue , if you solve this , I will say thank you.
Image
To make the TabBar use the maximum width of the screen you should remove the isScrollable property or set it to false. This way the TabBar is going to fill the entire width of the screen and resize each tab accordingly. From the docs, each tab gets an equal share of the available space). Also, the tabLength should be removed as it doesn't make sense anymore.
Now, the position of VerticalDivider should be calculated. It should take into account the screen width, the width of the tab, and also the padding between tabs. And it should be places in a Stack with the TabBar to make it the same height as the TabBar itself.
The algorithm to calculate the tab width can be something like this:
double width = MediaQuery.of(context).size.width;
double tabLength = (width -
horizontalPadding * (tabCount + 1) -
horizontalPadding * (tabCount - 1)) /
tabCount;
Below are the screenshots of the final result. Take a look also on the live demo on DartPad (Wait a little to run):
Small
Medium
Large
Take a look at the changed code below:
import 'package:flutter/material.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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
late TabController tabController;
late TabController tabController2;
#override
void initState() {
// TODO: implement initState
super.initState();
tabController = TabController(length: 4, vsync: this);
tabController2 = TabController(length: 3, vsync: this);
}
#override
Widget build(BuildContext context) {
double horizontalPadding = 8;
return Scaffold(
body: ScrollTabBar(
tabController: tabController,
horizontalPadding: horizontalPadding,
tabList: const [
FTabComp(
title: 'secKey',
key: ValueKey('tab1'),
),
FTabComp(
title: 'firstKey',
key: ValueKey('tab2'),
),
FTabComp(
title: 'otherKey',
key: ValueKey('tab3'),
),
FTabComp(
title: 'anotherKey',
key: ValueKey('tab4'),
),
],
screenList: [
(context) => const Text('Tab 1'),
(context) => const Text('Tab 2'),
(context) => const Text('Tab 3'),
(context) => const Text('Tab 4'),
],
),
);
}
}
class ScrollTabBar extends StatefulWidget {
final double borderRadiusT;
final double tabHeight;
final Color indicatorColor;
final Color activeTextColor;
final Color diactiveTextColor;
final double indicatorWheight;
final double horizontalPadding;
final Color outerBackgroundColor;
final double dviderWidth;
final TabController? tabController;
final List<Widget> tabList;
final List<Widget Function(BuildContext)> screenList;
final bool haveDivider;
const ScrollTabBar({
Key? key,
this.borderRadiusT = 4,
this.tabHeight = 48,
this.indicatorColor = Colors.blue,
this.activeTextColor = Colors.black,
this.diactiveTextColor = Colors.white38,
this.indicatorWheight = 8,
this.horizontalPadding = 8,
required this.tabController,
required this.tabList,
required this.screenList,
this.outerBackgroundColor = Colors.black,
this.dviderWidth = 4,
this.haveDivider = true,
}) : super(key: key);
#override
State<ScrollTabBar> createState() => _ScrollTabBarState();
}
class _ScrollTabBarState extends State<ScrollTabBar> {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double tabLength = (width -
widget.horizontalPadding * (widget.tabList.length + 1) -
widget.horizontalPadding * (widget.tabList.length - 1)) /
widget.tabList.length;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.black54,
blurRadius: 5.0,
offset: Offset(0.0, 0.75),
),
],
borderRadius: BorderRadius.circular(widget.borderRadiusT),
color: Colors.red,
),
height: widget.tabHeight,
child: Stack(
children: [
TabBar(
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: widget.indicatorColor,
width: widget.indicatorWheight,
),
insets: EdgeInsets.symmetric(
horizontal: widget.horizontalPadding,
),
),
indicatorWeight: widget.indicatorWheight,
indicatorColor: widget.indicatorColor,
labelPadding: EdgeInsets.only(
bottom: 0,
right: widget.horizontalPadding,
left: widget.horizontalPadding,
),
labelColor: widget.activeTextColor,
unselectedLabelColor: widget.diactiveTextColor,
controller: widget.tabController,
tabs: widget.tabList,
),
for (int i = 1; i < widget.tabList.length; i++)
Positioned.fill(
left: (widget.horizontalPadding + tabLength + widget.horizontalPadding) * i - (widget.dviderWidth / 2),
right: width,
child: SizedBox(
height: widget.tabHeight,
child: VerticalDivider(
color: widget.outerBackgroundColor,
thickness: widget.dviderWidth,
),
),
),
],
),
),
Expanded(
child: TabBarView(
controller: widget.tabController,
children: [
for (var builder in widget.screenList) builder.call(context)
],
),
),
],
),
);
}
}
class FTabComp extends StatelessWidget {
final String title;
const FTabComp({
Key? key,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Tab(
key: key,
child: Container(
color: Colors.blue,
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.center,
child: Text(title),
),
],
),
),
);
}
}
Inside the Stack, you use Positioned.fill. try removing it
I have a Row with two Expanded widgets as its children. There is no space/padding between a children, therefore. Each of the children contains a Container (with box decoration), which in turn contains a FlatButton. When the FlatButton is highlighted, a BoxShadow appears around the Container.
For the second button, the shadow appears just fine, overflowing part of the first button. However, when the first button is being highlighted, the right side of the BoxShadow, which is supposed to be "over" the second button, gets clipped. I assume it's because the second button (and its respective ancestors) are after the first button in the widget tree, thus being "higher".
Here is the DartPad instance I made to demonstrate the issue: https://dartpad.dev/3e1eaa23c2848ada0104bded02e1510a
My question is essentially how I could achieve, with exactly the same layout, ie. no space between the buttons, that the shadow of each button appears over the other one. That is, the shadow of "Button1" in the example is the same as that of "Button2";
Thanks!
Hi You can check the edited code.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Generated App',
theme: new ThemeData(
primarySwatch: Colors.blue,
primaryColor: const Color(0xFF2196f3),
accentColor: const Color(0xFF2196f3),
canvasColor: const Color(0xFFfafafa),
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('App Name'),
),
body: new Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: new Row(
children: [
Expanded(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 5, 0),
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.transparent,
blurRadius: 5.0,
),
]),
child: TestButton("Button1")),
),
)),
Expanded(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 5, 0),
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.transparent,
blurRadius: 5.0,
),
]),
child: TestButton("Button2")),
),
))
],
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
))),
padding: const EdgeInsets.all(0.0),
alignment: Alignment.center,
),
);
}
}
class TestButton extends StatefulWidget {
#required
final String title;
TestButton(this.title);
#override
_TestButtonState createState() => _TestButtonState();
}
class _TestButtonState extends State<TestButton> {
bool isHighlighted = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
height: 50,
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(isHighlighted ? 0.5 : 0.0),
spreadRadius: isHighlighted ? 5 : 0,
)
]),
child: FlatButton(
shape: ContinuousRectangleBorder(borderRadius: BorderRadius.zero),
splashColor: Colors.black12,
color: Colors.white,
hoverColor: Colors.black12,
highlightColor: Colors.black12,
mouseCursor: MouseCursor.uncontrolled,
child: Text(widget.title),
onPressed: () => null,
onHighlightChanged: (value) {
setState(() {
isHighlighted = value;
});
},
));
}
#override
void dispose() {
super.dispose();
}
}
How to create this beautiful curve shape divider in a flutter App.
Simply use this customDivider as your divider
customDivider(String title) {
return Row(
children: [
Expanded(
child: Container(
color: Colors.white,
height: 10,
),
),
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(13),
color: Colors.white,
),
child: Center(child: Text(title)),
),
Expanded(
child: Container(
color: Colors.white,
height: 10,
),
),
],
);
}
Here is an example
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: 5,
shrinkWrap: true,
itemBuilder: (context, index) => listItem(index),
),
);
}
customDivider(String title) {
return Row(
children: [
Expanded(
child: Container(
color: Colors.white,
height: 10,
),
),
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(13),
color: Colors.white,
),
child: Center(child: Text(title)),
),
Expanded(
child: Container(
color: Colors.white,
height: 10,
),
),
],
);
}
listItem(int index) {
return Column(
children: [
Container(
height: 200,
width: 200,
margin: EdgeInsets.all(10),
color: index.isEven ? Colors.orange : Colors.deepPurpleAccent,
),
customDivider("your title"),
],
);
}
}
OUTPUT:
There can be many ways to do this in flutter. This is one of the simplest approach.
main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: SO(),
),
);
}
}
class SO extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink.shade100,
appBar: AppBar(),
body: Center(
child: CapsuleWidget(
label: 'organizing data'.toUpperCase(),
ribbonHeight: 8,
),
),
);
}
}
class CapsuleWidget extends StatelessWidget {
final Color fillColor;
final Color textColor;
final String label;
final double ribbonHeight;
final double ribbonRadius;
const CapsuleWidget({
Key key,
this.fillColor = Colors.white,
this.textColor = Colors.black,
#required this.label,
#required this.ribbonHeight,
this.ribbonRadius = 1000,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Container(
height: ribbonHeight,
color: fillColor,
),
),
Container(
decoration: BoxDecoration(color: fillColor, borderRadius: BorderRadius.circular(ribbonRadius)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
label,
style: TextStyle(color: textColor, fontWeight: FontWeight.w500),
),
),
),
Expanded(
child: Container(
height: ribbonHeight,
color: fillColor,
),
),
],
);
}
}
it use Stack class
link url : https://api.flutter.dev/flutter/widgets/Stack-class.html
pseudo code
Stack {
Container(), // background
Contanier(), // white Line
Text() , // center Text
}