How to overlap widgets by respecting their sizes at Flutter? - flutter

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

Related

How to implement a Sliver App Bar with Tabs & other widgets above Tabs?

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

Shaping for circular cylinder UI

I'm having trouble with doing the UI for the Parcel shape. Tried using Stack but the background for the Text just gets in the way of the Icon. Below are my code and the image for the Parcel UI that I want to achieve.
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
final _mediaQuery = MediaQuery.of(context);
final _height = _mediaQuery.size.height - _mediaQuery.padding.top;
final _width = _mediaQuery.size.width;
final _roundBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: BorderSide.none,
);
final _deliveryContainer = _width * 0.25;
return SafeArea(
child: Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: Container(
decoration: const BoxDecoration(
color: Constants.orangeColor,
),
child: Row(
children: [
Expanded(
flex: 3,
child: Padding(
padding: EdgeInsets.fromLTRB(
_width * 0.02,
_height * 0.01,
_width * 0.02,
_height * 0.01,
),
child: TextField(
decoration: InputDecoration(
prefixIcon: const Icon(
FeatherIcons.search,
color: Colors.black,
),
filled: true,
fillColor: Colors.white,
enabledBorder: _roundBorder,
errorBorder: _roundBorder,
disabledBorder: _roundBorder,
focusedBorder: _roundBorder,
focusedErrorBorder: _roundBorder,
),
),
),
),
Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Container(
width: _deliveryContainer,
color: Color(0xFF05004E),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 2.0,
),
child: Text(
'Parcel',
),
),
),
const Positioned(
left: 0.1,
child: Material(
shape: const CircleBorder(),
color: Color(0xFF05004E),
child: Icon(
Icons.toys,
color: Colors.white,
size: 34,
),
),
),
],
),
],
),
),
),
),
);
}
}
You can include decoration on _deliveryContainer.
Container(
width: _deliveryContainer,
decoration: BoxDecoration(
color: Color(0xFF05004E),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(_height * 0.01),
bottomLeft: Radius.circular(_height * 0.01),
),
),
Try this (:
Row(
children: [
CircleAvatar(
radius: 25,
child: Icon(Icons.train),
backgroundColor: Colors.blue,
),
Container(
height: 30,
width: 100,
color: Colors.blue,
transform: Matrix4.translationValues(-10.0, 00.0, 0.0),
child: Center(
child: Text("Parcel"),
),
)
],
)

How to make Sliding up Panel city circular from only one side FLUTTER

I'm a beginner and want to make Sliding up Panel like this. Your help will be appreciated
try this:
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15.0),
topRight: Radius.circular(15.0)),
),
builder: (context) {
return Stack(
overflow: Overflow.visible,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(
10,
(int index) => ListTile(
leading: Icon(Icons.email, color: Colors.black),
title: Text('$index',
style: TextStyle(color: Colors.black)),
onTap: () {},
),
),
),
Positioned(
top: -50,
left: 20,
child: ClipOval(child: Container(
width: 100,
height: 100,
color: Colors.red,
),)
),
],
);
});
},
I think this will get you what you want:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatelessWidget(),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body:
Stack(
children: [
Center(
child: Container(
height: 300,
width: 300,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(50),
topLeft: Radius.circular(50))),
)),
),
Positioned(
// You can change top and left values based on the layout or device
top: 140,
left: 70,
child: Container(
height: 100,
width: 100,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
child: Column(
children: [
SizedBox(
height: 20,
),
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
'https://icon-library.com/images/avatar-icon-images/avatar-icon-images-4.jpg')),
Text('Patrick')
],
)),
),
),
],
),
);
}
}

How to stop ColorFiltered blending?

I followed the answer of this question to create a widget with a transparent hole. My problem now is that any other widgets I place on the screen have a blend effect as well. I would
like this to not be the case, if possible. Here's my code:
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,
),
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 Material(
child: Stack(
fit: StackFit.expand,
children: [
Image.network(
'https://wallpaperplay.com/walls/full/8/3/a/35405.jpg',
fit: BoxFit.cover,
),
ColorFiltered(
colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.8),
BlendMode.srcOut), // This one will create the magic
child: Column(
children: [
Expanded(
child: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: BoxDecoration(
color: Colors.black,
backgroundBlendMode: BlendMode
.dstOut), // This one will handle background + difference out
),
Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.only(top: 80),
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(10),
),
),
),
],
),
),
Text("Test",
style: TextStyle(
color: Colors.red,
fontSize: 64,
fontWeight: FontWeight.bold)),
],
),
),
Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.only(top: 80),
height: 200,
width: 200,
decoration: BoxDecoration(
//color: Colors.red,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.red,
width: 2,
),
),
),
),
],
),
);
}
}
And the result:
I want the text widget "Test" to be in red and not show the image below. Any widget placed above the color filter should not be blended with the background. I've tried wrapping the text in a ColorFiltered widget and setting the BlendMode to "src" which should discard the destination image (if I understand the documentation correctly), but that did not work.
since you are using a stack, just pull out the text wsidget from the ColoredFilter widget and place it after the widget. This way it will appear on top.
something like this (not tested):
Stack(
fit: StackFit.expand,
children: [
Image.network(
'https://wallpaperplay.com/walls/full/8/3/a/35405.jpg',
fit: BoxFit.cover,
),
ColorFiltered(
colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.8),
BlendMode.srcOut), // This one will create the magic
child: Column(
children: [
Expanded(
child: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: BoxDecoration(
color: Colors.black,
backgroundBlendMode: BlendMode
.dstOut), // This one will handle background + difference out
),
Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.only(top: 80),
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(10),
),
),
),
],
),
),
],
),
),
// I just moved text widget here, you may need to apply any Position, align, padding, margin you wish, since it is now outside of the Expand widget
Text("Test",
style: TextStyle(
color: Colors.red,
fontSize: 64,
fontWeight: FontWeight.bold)),
Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.only(top: 80),
height: 200,
width: 200,
decoration: BoxDecoration(
//color: Colors.red,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.red,
width: 2,
),
),
),
),
],
),

Flutter - Align widget all the way to the end of a card view. (View image included)

how can I get the flat button to fill the area under the divider all the way to the end of the card, it appears to not be able to go any further down.
See the white space under the FlatButton? I want it to look like the FlatButton is the end.
Doesn't have to be a flat button, any widget with onTap/press/(or a something hack-ish with gesture detector) listener would be fine.
Dart code is ->
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))
),
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 24, bottom: 16),
child: Text(_label, style: TextStyle(fontSize: 24, color: Color.fromARGB(190, 0, 0, 0), fontWeight: FontWeight.bold)),
),
Divider(color: Colors.black26, height: 2,),
Padding(
padding: const EdgeInsets.all(24.0),
child: Text(_information, style: TextStyle(fontSize: 20, color: Colors.black87)),
),
Divider(color: Colors.black26, height: 2,),
SizedBox(width: double.infinity, child: FlatButton(onPressed: () => _onTap(), color: Color.fromARGB(50, 100, 100, 100), child: Text('Done', style: TextStyle()), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))))
],
),
),
),
);
}
Please see the code below, I'm using InkWell & Container :
import 'package:flutter/material.dart';
final Color darkBlue = const Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
//theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
String _label = "";
String _information = "";
return Padding(
padding: const EdgeInsets.all(4.0),
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 24, bottom: 16),
child: Text(_label,
style: TextStyle(
fontSize: 24,
color: Color.fromARGB(190, 0, 0, 0),
fontWeight: FontWeight.bold)),
),
Divider(
color: Colors.black26,
height: 2,
),
Padding(
padding: const EdgeInsets.all(24.0),
child: Text(_information,
style: TextStyle(fontSize: 20, color: Colors.black87)),
),
Divider(
color: Colors.black26,
height: 2,
),
Spacer(),
InkWell(
onTap: () {}, //_onTap(),
child: Container(
width: double.infinity,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color.fromARGB(50, 100, 100, 100)),
child: const Center(child: Text('Done', style: TextStyle())),
),
)
],
),
),
),
);
}
}
I solved my code like this, setting a height factor it did what i wanted automatically.
SizedBox(width: double.infinity, height: 60, child:
FlatButton(onPressed: () => _onTap(), color: Colors.transparent, child:
Text('Done', style: TextStyle()), shape: RoundedRectangleBorder(borderRadius:
BorderRadius.only(bottomLeft: Radius.circular(15), bottomRight: Radius.circular(15)))))
Only downside is that you have to specify a height rather than letting the widget adjust that based on content. Although there is probably a workaround for that.