Related
How to implement a SliverAppBar with Tabs & Widgets above Tabs?
How to create a SliverAppBar like Talabat App:
Please, check the below - video.
How to solve it?
What can I do?
I am doing...
https://youtube.com/shorts/HeuOTpdRZYY
I tried the below code:
=========================================================
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
// return Scaffold(
// body: NestedScrollView(
// headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
// return <Widget>[
// const SliverAppBar(
// backgroundColor: Colors.red,
// flexibleSpace: FlexibleSpaceBar(),
// )
// ];
// },
// body: Container(
// child: Builder(builder: (context) {
// return Column(
// mainAxisAlignment: MainAxisAlignment.start, children: const []);
// }),
// ),
// ),
// );
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: 500,
toolbarHeight: AppSize.s60,
collapsedHeight: 200,
leading: GestureDetector(
onTap: () {},
child: Center(
child: Container(
width: AppSize.s50,
height: AppSize.s44,
decoration: const BoxDecoration(
color: Palette.kPrimaryColor,
borderRadius: BorderRadius.all(
Radius.circular(AppSize.s10),
),
),
child: Center(
child: SvgPicture.asset(
AppAssets.menu,
height: AppSize.s14,
),
),
),
),
),
title: const Text(
"FASDFASD F",
style: TextStyle(
color: Colors.black,
),
),
actions: [
const SizedBox(width: AppSize.s10),
IconButton(
onPressed: () {},
splashRadius: AppSize.s28,
icon: SvgPicture.asset(
AppAssets.shoppingCart,
height: AppSize.s32,
),
),
],
flexibleSpace: Container(
color: Colors.deepOrange,
// height: 250,
child: Column(
children: [
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black26,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black45,
margin: const EdgeInsets.all(10),
),
Container(
height: 120,
color: Colors.blueGrey,
),
],
),
),
bottom: const CustomAppBarBottom(),
backgroundColor: Palette.kWhiteColor,
),
SliverToBoxAdapter(
child: Column(
children: [
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.purple,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.green,
margin: const EdgeInsets.all(10),
),
Container(
height: 100,
color: Colors.black87,
margin: const EdgeInsets.all(10),
),
],
),
),
],
),
);
}
}
class CustomAppBarBottom extends StatelessWidget
implements PreferredSizeWidget {
const CustomAppBarBottom({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var outlineInputBorder = OutlineInputBorder(
borderRadius: AppRadius.bottomRadius,
borderSide: BorderSide.none,
);
return Container(
margin: EdgeInsets.symmetric(
horizontal: getUIPadding(context),
vertical: 10,
),
decoration: BoxDecoration(
color: Palette.kWhiteColor,
borderRadius: AppRadius.bottomRadius,
boxShadow: const [
BoxShadow(
color: Color.fromARGB(20, 0, 0, 0),
blurRadius: 7,
)
],
),
child: TextFormField(
style: const TextStyle(
height: 1.2,
),
decoration: InputDecoration(
hintText: "عن ماذا تبحث؟",
hintStyle: const TextStyle(
color: Palette.onboardingDescriptionColor,
),
prefixIcon: Align(
// alignment: Alignment.centerRight,
widthFactor: 1.0,
child: SvgPicture.asset(
AppAssets.search,
width: AppSize.s25,
),
),
isDense: true,
border: outlineInputBorder,
errorBorder: outlineInputBorder,
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
disabledBorder: outlineInputBorder,
focusedErrorBorder: outlineInputBorder,
),
),
);
}
#override
Size get preferredSize => const Size.fromHeight(AppSize.s60);
}
This widget give you some sample idea, Also check SliverPersistentHeader for custom header. You can check sliver_tools package for pinned header. Also TabBar can be replace with scroll_to_index.
class TestWidget extends StatefulWidget {
const TestWidget({Key? key}) : super(key: key);
#override
State<TestWidget> createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget>
with SingleTickerProviderStateMixin {
late final TabController tabController =
TabController(length: 10, vsync: this);
double itemHeight = 120;
double? appBarHeight;
late final ScrollController controller = ScrollController()
..addListener(() {
if (controller.hasClients) {
final moveTo =
((controller.offset - appBarHeight!) / itemHeight).toInt();
tabController.animateTo(moveTo < 0 ? 0 : moveTo);
setState(() {});
}
});
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
appBarHeight ??= constraints.maxHeight;
return CustomScrollView(
controller: controller,
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: constraints.maxHeight * .7,
bottom: PreferredSize(
child: TabBar(
controller: tabController,
tabs: List.generate(
10,
(index) => Container(
width: 100,
height: 40,
alignment: Alignment.center,
color: index == tabController.index
? Colors.deepOrange
: Colors.cyanAccent,
child: Text("$index"),
)),
),
preferredSize: Size.fromHeight(kToolbarHeight),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: itemHeight,
color: index.isEven ? Colors.green : Colors.pink,
width: constraints.maxWidth,
);
},
),
)
],
);
}),
);
}
}
See how the edges are faded and merged with the color of the button? How do you get something like that in flutter?
I have the button, don't know how to get that effect.
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 30),
child: Column(
children: [
//OUTER CIRCLE (BUTTON INSIDE)
Container(
height: 275,
width: 275,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(150),
border: Border.all(
width: 3,
color: Colors.grey.withOpacity(0.6),
style: BorderStyle.solid,
),
),
child: Padding(
padding: const EdgeInsets.all(40),
//SHADOW (Button inside)
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: const Color(0xfffd194b).withOpacity(0.7),
spreadRadius: 10,
blurRadius: 40,
offset: const Offset(0, 25),
),
],
),
//BUTTON
child: RecordButtonWithText(
buttonText: _buttonText,
startStopRecording: startStopRecording,
),
),
),
),
],
),
);
class RecordButtonWithText extends StatelessWidget {
const RecordButtonWithText({
Key? key,
required String buttonText,
required this.startStopRecording,
}) : _buttonText = buttonText,
super(key: key);
final String _buttonText;
final VoidCallback startStopRecording;
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
startStopRecording();
},
style: ElevatedButton.styleFrom(
elevation: 10,
padding: const EdgeInsets.all(30),
shape: const CircleBorder(),
shadowColor: const Color(0xfffd194b),
primary: const Color(0xfffd194b),
),
child: Text(
_buttonText.toUpperCase(),
style: const TextStyle(fontSize: 22, letterSpacing: 3),
),
);
}
}
If the you don't have to use the "ElevatedButton" widget, you can achieve what you want like that:
class RecordButtonWithText extends StatelessWidget {
final String _buttonText;
final VoidCallback startStopRecording;
final EdgeInsets padding;
final double size;
const RecordButtonWithText({
Key? key,
required String buttonText,
required this.startStopRecording,
this.padding = const EdgeInsets.all(30.0),
this.size = 275.0,
}) : _buttonText = buttonText,
super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: size,
width: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 2,
color: Colors.grey.withOpacity(0.4),
style: BorderStyle.solid,
),
),
child: Padding(
padding: EdgeInsets.all(size * 0.145),
//SHADOW (Button inside)
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: const Color(0xfffd194b).withOpacity(0.7),
spreadRadius: size * 0.03,
blurRadius: size * 0.145,
offset: Offset(0, size * 0.09),
),
],
),
//BUTTON
child: InkWell(
borderRadius: BorderRadius.circular(size / 2),
onTap: () {
startStopRecording();
},
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(size * 0.1),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black,
gradient: RadialGradient(colors: [
const Color(0xfffd194b),
const Color(0xfffd194b),
const Color(0xfffd194b).withOpacity(0.5),
], stops: const [
0,
0.8,
1
]),
),
child: Text(
_buttonText.toUpperCase(),
style: TextStyle(
color: Colors.white,
fontSize: size * 0.08,
),
),
),
),
),
),
);
}
}
I just want to overlap 2 Container by respecting first Container's width.
This is what I want to achieve.
Containers not occupying space When I use Stack Widget. So I think stack widget not working for me.
And It is not overlapping when I use Row. So Row is not working either.
In CSS I just give negative margin to the right element and it is done. But I couldn't figure out the way to achieve that in flutter.
I put these Containers in to the Stack. Because I have to overflow a Card widget with that Containers
Try below code hope its help to you
You can use Stack Widget for that
Container(
height: 60,
margin: EdgeInsets.symmetric(
horizontal: 4),
child: Stack(
children: [
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: Colors.yellow,
borderRadius: BorderRadius.only(
topRight: Radius.circular(6),
bottomRight: Radius.circular(6),
),
),
margin: EdgeInsets.symmetric(vertical: 4),
padding: EdgeInsets.symmetric(horizontal: 20),
alignment: Alignment.centerRight,
child: Text('Ends after 1 Hour'),
),
),
Positioned(
top: 0,
bottom: 0,
child: Container(
decoration: BoxDecoration(
color: Colors.redAccent,
borderRadius: BorderRadius.only(
topRight: Radius.circular(6),
bottomRight: Radius.circular(6),
),
),
alignment: Alignment.center,
padding: EdgeInsets.only(right: 8, left: 20),
child: Text('40% Discount'),
),
),
],
),
),
Your result screen ->
Here is my trial.
Using Stack and set 'clipBehavior: Clip.none' parameter.
Added 'addPostFrameCallback' method to get a left container's width.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#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> {
double firstContainerWidth = 0;
GlobalKey firstContainerKey = GlobalKey();
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
firstContainerWidth = firstContainerKey.currentContext.size.width;
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildBody() {
return Stack(
clipBehavior: Clip.none,
alignment: AlignmentDirectional.bottomStart,
children: <Widget>[
Positioned(
left: firstContainerWidth - 10,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 5),
decoration: BoxDecoration(
color: Colors.orange[400],
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Text(
'Ends after 1 hour',
style: TextStyle(
fontSize: 15,
color: Colors.white,
),
),
),
),
Container(
key: firstContainerKey,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Text(
'%40 Discount',
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
),
]);
}
}
It can be done in multiple ways. You can use CustomPainter, Stack or even Row to do this. Here is my approach using a Row only.
Result
Code : DartPad
class DiscountBadgeWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Row(mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
_buildRedSection(),
_buildMiddleSection(),
_buildYellowSection(),
],
);
}
Widget _buildMiddleSection() => Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.bottomCenter,
heightFactor: .5,
child: Container(
height: 80,
width: 10,
decoration: const BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.horizontal(right: Radius.circular(10)),
),
),
),
);
Widget _buildRedSection() => Container(
height: 80,
decoration: const BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.horizontal(left: Radius.circular(10)),
),
padding: const EdgeInsets.only(left: 16, right:6),
alignment: Alignment.centerRight,
child: Text('40% Discount'),
);
Widget _buildYellowSection() => Container(
height: 60,
decoration: const BoxDecoration(
color: Colors.yellow,
borderRadius: BorderRadius.horizontal(right: Radius.circular(10)),
),
padding: const EdgeInsets.only(right: 16, left:6),
alignment: Alignment.centerRight,
child: Text('Ends after 1 Hour'),
);
}
Widget i want to make:
Widget I made:
This is my code:
Stack(
alignment: Alignment.center,
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 16.0),
height: 70.0,
width: 70.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://www.themoviedb.org/t/p/original/wXSnajAZ5ppTKa8Z5zzWGOK85YH.jpg'),
fit: BoxFit.cover,
),
shape: BoxShape.circle,
border: Border.all(color: Colors.red, width: 4.0),
),
),
Container(
height: 70.0,
width: 70.0,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Colors.black87,
Colors.black45,
Colors.transparent,
],
stops: [0, 0.25, 1],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
shape: BoxShape.circle,
border: Border.all(color: Colors.red, width: 4.0),
),
),
Positioned(
left: 30,
right: -15,
bottom: -20,
child: SizedBox(
height: 35.0,
child: Text(
'12 Mart',
style: TextStyle(
color: Colors.white,
backgroundColor: Colors.red,
),
),
),
),
],
),
How do I make a circle around the text and edges under the round picture like the first Widget?
Here is a solution using a Stack and three nested CircleAvatars:
Minimal Working Example:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final radius = MediaQuery.of(context).size.shortestSide * .4;
final borderWidth = radius / 12;
return Scaffold(
body: Center(
child: Badge(
radius: radius,
borderWidth: borderWidth,
imageUrl:
'https://upload.wikimedia.org/wikipedia/commons/e/ea/Retrato_del_Maestro_Yoda.jpg',
),
),
);
}
}
class Badge extends StatelessWidget {
final double radius;
final double borderWidth;
final String imageUrl;
const Badge({
Key key,
#required this.radius,
#required this.borderWidth,
#required this.imageUrl,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
Container(height: 2.1 * radius),
Positioned(
top: 0,
child: CircleAvatar(
radius: radius,
backgroundColor: Colors.indigo,
child: CircleAvatar(
radius: radius - borderWidth,
backgroundColor: Colors.black,
child: CircleAvatar(
radius: radius - 2 * borderWidth,
backgroundImage: NetworkImage(imageUrl),
),
),
),
),
Positioned(
bottom: 0,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 2 * borderWidth,
vertical: borderWidth,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderWidth),
color: Colors.indigo,
),
child: Text(
'12 Mart',
style: TextStyle(color: Colors.white, fontSize: 3 * borderWidth),
),
),
),
],
);
}
}
Here you go:
Stack(
alignment: Alignment.center,
children: [
SizedBox(height: 75), // This container is needed only to set the overall stack height
// for Text to be a bit below Circleavatar
Container(
margin: const EdgeInsets.symmetric(horizontal: 16.0),
height: 70.0,
width: 70.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(35),
color: Colors.red,
border: Border.all(width: 4, color: Colors.red),
),
child: CircleAvatar(
backgroundImage: NetworkImage(
'https://www.themoviedb.org/t/p/original/wXSnajAZ5ppTKa8Z5zzWGOK85YH.jpg'),
),
),
Positioned(
bottom: 0,
child: Container(
padding: EdgeInsets.all(3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(35),
color: Colors.red,
),
child: Text(
'12 Mart',
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
),
],
),
Result:
I really need you because I don't have even start idea how to implement these, and also I am not sure how it is called.
Actually, I want to implement something similar like on image (this little circle in each of cards - that is like chain between two cards).
With help of key I have made image from up with this code:
class InfoPage extends StatefulWidget {
InfoPage();
#override
_InfoPageState createState() => _InfoPageState();
}
class _InfoPageState extends State<InfoPage> {
InfoItemModel infoData = dataSourceInfoUser;
double basicSize = 70;
#override
initState() {
super.initState();
}
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Container(
color: Colors.white,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
width: double.infinity,
height: 150,
child: AppCardField(
child: Text('Something'),
),
),
_buildCardWithCircle(
bgCircleX: 0.78,
bgCirceY: -2.0,
innerContainerX: 0.756,
innerContainerY: -1.78,
colorInner: Colors.orange
),
],
),
),
),
);
_buildCardWithCircle({double bgCircleX, double bgCirceY, double innerContainerX, double innerContainerY, Color colorInner}) => Container(
width: double.infinity,
height: 150,
child: Stack(
children: <Widget>[
Container(
width: double.infinity,
height: 150,
child: AppCardField(
child: Text('Something'),
),
),
Align(
alignment: Alignment(bgCircleX, bgCirceY),
child: Container(
height: basicSize,
width: basicSize,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50.0),
),
),
),
Align(
alignment: Alignment(innerContainerX, innerContainerY),
child: Container(
height: basicSize - 10,
width: basicSize - 10,
decoration: BoxDecoration(
color: colorInner,
borderRadius: BorderRadius.circular(50.0),
),
child: Icon(Icons.vertical_align_center),
),
),
],
),
);
}
class AppCardField extends StatelessWidget {
final Widget child;
final double height;
final double paddingVertical, paddingHorizontal;
final double paddingVerticalChild, paddingHorizontalChild;
AppCardField({
this.child,
this.height,
this.paddingVertical = 8,
this.paddingHorizontal = 16,
this.paddingVerticalChild = 8,
this.paddingHorizontalChild = 16,
Key key})
: super(key: key);
#override
Widget build(BuildContext context) => Padding(
padding: EdgeInsets.symmetric(
vertical: paddingVertical, horizontal: paddingHorizontal),
child: Container(
height: height,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.all(Radius.circular(8)),
boxShadow: [
BoxShadow(
color: Colors.red,
blurRadius: 15.0,
offset: Offset(0.0, 5.0),
),
],
),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: paddingVerticalChild,
horizontal: paddingHorizontalChild),
child: child,
),
));
}
But here, I have problem with shadow of the card and strongly white background of circle, OFC I need this shadow to be also in this white space, question is how to solve this?
Something like this
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Some Stuff"),
),
body: Column(
children: <Widget>[
Container(
width: double.infinity,
height: 150.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.red,
blurRadius: 20.0
)
]
),
child: Card(
elevation: 20.0,
color: Colors.blueGrey,
child: Text('Something'),
),
),
SizedBox(height: 10.0,),
Container(
width: double.infinity,
height: 150.0,
child: Stack(
children: <Widget>[
Container(
width: double.infinity,
height: 150.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.red,
blurRadius: 20.0
)
]
),
child: Card(
elevation: 20.0,
color: Colors.blueGrey,
child: Text('Something'),
),
),
Align(
alignment: Alignment(0.9,-1.5),
child: Container(
height: 50.0,
width: 50.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25.0),
),
),
),
Align(
alignment: Alignment(0.88,-1.35),
child: Container(
height: 40.0,
width: 40.0,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(25.0),
),
),
),
Align(
alignment: Alignment(0.85, -1.2),
child: Icon(Icons.access_alarms, color: Colors.white,)
),
],
),
),
],
),
),
);
then you just reaped the card for the other once with different alignment values.