In the image below, I need to make the green child to take up all of the grey container on the left side, so I don't want any padding in the container it is in.
code:
return Column(children: [
Container(
padding: EdgeInsets.all(0),
margin: EdgeInsets.all(0),
alignment: Alignment.topLeft,
color: Colors.grey,
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: AspectRatio(
aspectRatio: 1 / 1,
child: VpBaseCard(
elevation: 0,
width: double.infinity,
children: [
FaIcon(FontAwesomeIcons.cameraRetro,
size: 100,
color: Colors.white.withOpacity(0.7))
],
active: true,
padding: const EdgeInsets.all(PAD_0),
onPressed: () {},
))),
Expanded(
flex: 1,
child: AspectRatio(
aspectRatio: 1 / 1,
child: VpBaseCard(
inactiveColor: Colors.grey,
width: double.infinity,
children: [
FaIcon(FontAwesomeIcons.imagePolaroid,
size: 100,
color: Colors.white.withOpacity(0.7))
],
active: false,
padding: const EdgeInsets.all(PAD_0),
onPressed: () {},
)))
])),
]);
VpBaseCard:
class VpBaseCard extends StatelessWidget {
VpBaseCard(
{#required this.active,
this.icon,
this.text,
this.width,
this.children,
this.inactiveColor = Colors.white,
this.activeColor,
this.height,
this.expanded = false,
this.iconSize,
this.overflow,
this.elevation = ELEVATION_2,
#required this.onPressed,
#required this.padding});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
HapticFeedback.lightImpact();
onPressed();
},
child: Container(
padding: padding,
height: height,
child: Card(
clipBehavior: Clip.antiAlias,
color: active
? activeColor ??
Theme.of(context).primaryColor.withOpacity(0.7)
: inactiveColor ?? Colors.white,
elevation: active ? elevation : 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Container(
width: width,
height: height,
padding: const EdgeInsets.all(0),
child: Flex(
direction: Axis.vertical,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: children ?? [])))));
}
bool active;
List<Widget> children;
bool expanded;
double width;
double height;
double iconSize;
double elevation;
TextOverflow overflow;
IconData icon;
String text;
VoidCallback onPressed;
EdgeInsetsGeometry padding;
Color inactiveColor;
Color activeColor;
}
Why does the Container seem to have slight padding?
The Card widget within your VpBaseCard has a default margin of EdgeInsets.all(4.0). Try setting that to zero.
https://api.flutter.dev/flutter/material/Card/margin.html
Related
I'm trying to make a discrete progress indicator similar to percent indicator but in a discrete manner.
And I wanna add some guide widget or arrow at the position of the current progress position something like images. (It is not actually implemented, it is a view of widget inspector, but I wanna get the result of that image, top or bottom of the row.)
But, the problem is, how can I get the position of the child widget of the row and add some stacked widget to that?
class LinearDiscreteIndicator extends StatelessWidget {
final int numTotal;
final int numCurrent;
final double? width;
final double lineHeight;
final double margin;
final Color fillColor;
final Color emptyColor;
final Radius barRadious;
final MainAxisAlignment alignment;
final Widget? progressWidget;
const LinearDiscreteIndicator({
Key? key,
required this.numTotal,
required this.numCurrent,
this.width,
required this.lineHeight,
this.margin = 2,
this.fillColor = Colors.blue,
this.emptyColor = Colors.grey,
this.barRadious = const Radius.circular(2),
this.alignment = MainAxisAlignment.start,
this.progressWidget,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
children: [
SizedBox(
height: lineHeight,
width: width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: alignment,
children: List.generate(numTotal, (index) => index)
.map(
(e) => Expanded(
child: Padding(
padding: EdgeInsets.only(
right: e == (numTotal - 1) ? 0 : margin,
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(barRadious),
color: e > numCurrent ? emptyColor : fillColor,
),
),
),
),
)
.toList(),
),
),
],
);
}
}
This is my current widget class code, but I'm not sure how can I enable a tooltip-like widget at the position of the current progress.
var numCurrent = 10;
var numTotal = 30;
var itemWidth = (MediaQuery.of(context).size.width / numTotal);
double containerWidth = 80;
var positionLeft = ((itemWidth) * (numCurrent + 1)) - (containerWidth / 2);
return Scaffold(
appBar: AppBar(),
backgroundColor: theme.colorScheme.background,
body: SingleChildScrollView(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 50,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Positioned(
left: positionLeft,
top: 10,
child: Container(
child: Stack(
children: const [
Align(alignment: Alignment.topCenter, child: Text("Container")),
Align(
alignment: Alignment.bottomCenter,
child: Icon(
Icons.arrow_drop_down_sharp,
size: 24,
)),
],
),
width: containerWidth,
height: 30,
color: Colors.red,
),
),
Positioned(
bottom: 0,
child: LinearDiscreteIndicator(
numCurrent: numCurrent,
numTotal: numTotal,
lineHeight: 4,
width: MediaQuery.of(context).size.width,
),
),
],
),
),
],
),
),
);
I am trying to create a horizontal stepper that changes based on a status. It would need a title above, different image (preferably svg) inside the circle and changing color of the divider with the same thickness.
Im trying to achieve this
I tried different approach and other packages, and I cant seem to get to make this, maybe I'm doing something wrong.
Stepper has its title on the side and the circles are checks and numbers only.
IconStepper from im_stepper package only has icons for steps, and no titles, and only dots for the divider.
EnhanceStep from enhance_stepper package has the title below the the icon, and it doesn't have a circle. I tried editing the package and the icon is not aligned with the line anymore.
Custom Widget but it is all UI and no functionality on changing the selected, and changing the index changes the color of the step itself but not the ones before it. Also the text is not aligned along the center of the step, is just aligned using Row's MainAxisAlignment.spaceBetween,
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class Testing4 extends StatefulWidget {
const Testing4({Key? key}) : super(key: key);
#override
State<Testing4> createState() => _Testing4State();
}
class _Testing4State extends State<Testing4> {
final List<int> steps = [1, 2, 3];
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
for (var step in steps) Center(child: Text('STEPPER # $step'))
],
),
SizedBox(
width: MediaQuery.of(context).size.width,
height: kToolbarHeight,
child: Stack(
alignment: Alignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: MediaQuery.of(context).size.width / 3,
child: const Divider(
color: Colors.black,
thickness: 5,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3,
child: const Divider(
color: Colors.grey,
thickness: 5,
),
),
],
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (var step in steps)
Column(
children: [
Stack(
children: [
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
step == 2 ? Colors.black : Colors.grey,
),
padding: const EdgeInsets.all(10),
child: Center(
child: SvgPicture.asset("assets/check.svg"),
),
)
],
),
],
)
],
),
)
],
),
),
],
)),
);
}
}
In the end, this one worked for me
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CustomStepper extends StatelessWidget {
CustomStepper({
Key? key,
required int currentStep,
required this.steps,
}) : _curStep = currentStep,
assert(currentStep >= 0 == true && currentStep <= steps.length),
super(key: key);
final int _curStep;
final Color _activeColor = Colors.black;
final Color _inactiveColor = Colors.grey.shade300;
final double lineWidth = 5.0;
final List<Map<String, dynamic>> steps;
List<Widget> _iconViews() {
var list = <Widget>[];
steps.asMap().forEach((i, icon) {
Color circleColor =
(i == 0 || _curStep >= i) ? _activeColor : _inactiveColor;
Color lineColor = _curStep > i ? _activeColor : _inactiveColor;
list.add(
Container(
width: 55.0,
height: 55.0,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: circleColor,
),
child: SvgPicture.asset(
icon['image'],
),
),
);
if (i != steps.length - 1) {
list.add(Expanded(
child: Container(
height: lineWidth,
color: lineColor,
)));
}
});
return list;
}
List<Widget> _titleViews() {
var list = <Widget>[];
steps.asMap().forEach((i, text) {
list.add(Text(text["title"], style: TextStyle(color: _activeColor)));
});
return list;
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _titleViews(),
),
const SizedBox(
height: 10,
),
Row(
children: _iconViews(),
),
],
);
}
}
I want to remove the following blue padding from MaterialBanner widget, but it doesn't seem to be customizable. I want to insert an image in the red region.
I looked into MaterialBanner for using across Scaffold widgets because ScaffoldMessenger doesn't allow me to insert widgets other than MaterialBanner.
Is there any suggestion?
dartpad.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Scaffold(body: JustBanner())));
}
class JustBanner extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _JustBannerState();
}
}
class _JustBannerState extends State<JustBanner> {
#override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
final messenger = ScaffoldMessenger.of(context);
messenger.clearMaterialBanners();
messenger.showMaterialBanner(MaterialBanner(
padding: EdgeInsets.zero,
leadingPadding: EdgeInsets.zero,
leading: const SizedBox.shrink(),
backgroundColor: Colors.blue,
content: Container(
color: Colors.red,
width: 200,
height: 50,
),
actions: const [SizedBox.shrink()]));
},
child: const Text('Banner')),
],
);
}
}
Container(
width: MediaQuery.of(context).size.width,
child: MaterialBanner(
content: Text('Hello'),
actions: [
Icon(Icons.add),
],
),
),
Its no possible without copy and re-create the class, buttonBar always appear:
final Widget buttonBar = Container( // <-- problematic widget
alignment: AlignmentDirectional.centerEnd,
constraints: const BoxConstraints(minHeight: 52.0),
padding: const EdgeInsets.symmetric(horizontal: 8),
child: OverflowBar(
overflowAlignment: widget.overflowAlignment,
spacing: 8,
children: widget.actions,
),
);
final double elevation = widget.elevation ?? bannerTheme.elevation ?? 0.0;
final Color backgroundColor = widget.backgroundColor
?? bannerTheme.backgroundColor
?? theme.colorScheme.surface;
final TextStyle? textStyle = widget.contentTextStyle
?? bannerTheme.contentTextStyle
?? theme.textTheme.bodyText2;
Widget materialBanner = Container(
margin: EdgeInsets.only(bottom: elevation > 0 ? 10.0 : 0.0),
child: Material(
elevation: elevation,
color: backgroundColor,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: padding,
child: Row(
children: <Widget>[
if (widget.leading != null)
Padding(
padding: leadingPadding,
child: widget.leading,
),
Expanded(
child: DefaultTextStyle(
style: textStyle!,
child: widget.content,
),
),
if (isSingleRow)
buttonBar, // <----- here
],
),
),
if (!isSingleRow)
buttonBar, // <----- here
if (elevation == 0)
const Divider(height: 0),
],
),
),
);
I created a material for my app which should enclose some text. It looks like this:
Sometimes, there is overflowing text. With a flexible it looks like this:
And I also want it to align like in a Table. Without alignment to the others it looks like this:
The Border between the colors should be at the same position for all of those elements so it looks clean.
How can I achieve all of this? The Flexible Widget throws a WrongParent Exception when Put into a Table.
My Code:
import 'dart:math';
import 'package:flutter/material.dart';
import 'nook_constants.dart';
class NookTable extends StatelessWidget {
final double width;
final double height;
final EdgeInsets margin;
final Widget child;
final String title;
final String text;
final String font;
NookTable({
this.width,
this.height,
this.margin: nookDefaultMargin,
this.child,
this.title,
this.text,
this.font
});
final cell = (Widget widget) => Padding(
padding: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
child: widget,
);
#override
Widget build(BuildContext context) {
var margin = EdgeInsets.only(
left: this.margin?.left ?? 0.0,
right: this.margin?.right ?? 0.0,
top: this.margin?.top ?? 0.0,
bottom: max(2, this.margin?.bottom ?? 0.0),
);
return Container(
width: width,
height: height,
clipBehavior: Clip.antiAlias,
margin: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
decoration: BoxDecoration(
color: Colors.transparent,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
NookTitleDetails(text: title, width: width,),
NookTextDetails(text: text,),
],
),
);
}
}
class NookTextDetails extends StatelessWidget {
final String text;
final String font;
NookTextDetails({
this.text,
this.font
});
final cell = (Widget widget) => Padding(
padding: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
child: widget,
);
#override
Widget build(BuildContext context) {
return Flexible(
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.only(bottomRight: Radius.circular(25), topRight: Radius.circular(25)),
color: nookBeige,
child: cell(Text(text))
),
);
}
}
class NookTitleDetails extends StatelessWidget {
final String text;
final String font;
final double width;
NookTitleDetails({
this.text,
this.font,
this.width
});
final cell = (Widget widget) => Padding(
padding: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
child: widget,
);
#override
Widget build(BuildContext context) {
return Container(
width: width,
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(25), topLeft: Radius.circular(25)),
color: nooklightGreen,
child: cell(Text(text, style: TextStyle(color: nookWhite)))
),
);
}
}
Container(
decoration: BoxDecoration(
color: Colors.lime,
borderRadius: BorderRadius.all(Radius.circular(10))
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Stack(
children: <Widget>[Container(
width: 100,
padding: EdgeInsets.all(5),
child: Text('Fundort',textAlign: TextAlign.center,))],
)),
Expanded(
flex: 4,
child: Container(
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.horizontal(right:Radius.circular(10))
),
padding: EdgeInsets.all(10),
child: Text('Sign in with FacebookSign in with Facebook',
style: TextStyle(fontSize: 18, color: Colors.white)),
),
)
]),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 0,
child: Container(
width:100,
child:Text('Text to the left')
)
),
Expanded(
flex: 4,
child:Text('Text to the right')
),
],
),
I'm trying to set up a background color for a Row() widget, but Row itself has no background color or color attribute. I've been able to set the background color of a container to grey, right before the purple-backgrounded text, but the text itself does not fill the background completely and the following spacer does not take any color at all.
So how can I have the Row background set to the "HexColor(COLOR_LIGHT_GREY)" value so it spans over the whole row?
Any idea? Thanks a lot!
Here's the code that I have so far:
import 'package:flutter/material.dart';
import '../manager/ShoppingListManager.dart';
import '../model/ShoppingListModel.dart';
import '../hexColor.dart';
import '../Constants.dart';
class ShoppingListWidget extends StatelessWidget {
final Color color = Colors.amberAccent;
final int shoppingListIndex;
ShoppingListWidget({this.shoppingListIndex});
#override
Widget build(BuildContext context) {
ShoppingListManager slm = new ShoppingListManager();
String shoppingListName =
slm.myShoppingLists.shoppingLists[shoppingListIndex].name;
int categoryCount =
slm.myShoppingLists.shoppingLists[shoppingListIndex].categories.length;
return Scaffold(
appBar: AppBar(
title: Text(shoppingListName),
automaticallyImplyLeading: true,
),
body: ListView.builder(
itemBuilder: (context, index) {
Category cat = slm.myShoppingLists.shoppingLists[shoppingListIndex]
.categories[index];
return Container(
decoration: new BoxDecoration(
border: new Border.all(color: Colors.grey[500]),
color: Colors.white,
),
child: new Column(
children: <Widget>[
getCategoryWidget(context, cat),
getCategoryItems(context, cat),
],
),
);
},
itemCount: categoryCount,
),
);
}
// Render the category "headline" row where I want to set the background color
// to HexColor(COLOR_LIGHT_GREY)
Widget getCategoryWidget(BuildContext context, Category cat) {
return new Row(
children: <Widget>[
new Container(height: 40.0, width: 10.0, color: HexColor(cat.color)),
new Container(
height: 40.0, width: 15.0, color: HexColor(COLOR_LIGHT_GREY)),
new Container(
child: new Text("Category", textAlign: TextAlign.start,
style: TextStyle(
fontFamily: 'Bold',
fontSize: 18.0,
color: Colors.black),
),
decoration: new BoxDecoration(
color: Colors.purple,
),
height: 40.0,
),
Spacer(),
CircleAvatar(
backgroundImage:
new AssetImage('assets/icons/food/food_settings.png'),
backgroundColor: HexColor(COLOR_LIGHT_GREY),
radius: 15.0,
),
new Container(height: 15.0, width: 10.0, color: Colors.transparent),
],
);
}
// render the category items
Widget getCategoryItems(BuildContext context, Category cat) {
return ListView.builder(
itemBuilder: (context, index) {
String itemName = "Subcategory";
return new Row(children: <Widget>[
new Container(height: 40.0, width: 5.0, color: HexColor(cat.color)),
new Container(height: 40.0, width: 20.0, color: Colors.white),
new Container(
child: new Text(itemName),
color: Colors.white,
),
Spacer()
]);
},
itemCount: cat.items.length,
shrinkWrap: true,
physics:
ClampingScrollPhysics(),
);
}
}
Just wrap your Row with a Container with colour property like below:
Container(
color: Colors.black,
child: Row(
children: <Widget>[
Expanded(
child: Text('Demo', style: TextStyle(color: Colors.white),),
)
],
),
)
Wrap Row in a Container or a ColoredBox and provide it a color.
Container(
color: Colors.red, // <-- Red color provided to below Row
child: Row(...), /
)
or
ColoredBox(
color: Colors.red, // <-- Red color provided to below Row
child: Row(...), /
)
You can try this, it will work.
return DataRow.byIndex(
index: row.key,
color: MaterialStateColor.resolveWith(
(states) {
if (row.key % 2 == 0) {
return Colors.blue[50];
} else {
return Colors.white;
}
},
),
I use my own custom row and column with so may customizable options:
Widget column({
final EdgeInsets padding = EdgeInsets.zero,
final EdgeInsets margin = EdgeInsets.zero,
final List<Widget> children = const <Widget>[],
final MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
final MainAxisSize mainAxisSize = MainAxisSize.max,
final CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
final VerticalDirection verticalDirection = VerticalDirection.down,
final BoxDecoration? decoration,
final double? width,
final double? height,
final bool isScrollable = false,
final VoidCallback? onTap,
}) =>
Container(
width: width,
height: height,
decoration: decoration,
padding: padding,
margin: margin,
child: isScrollable
? SingleChildScrollView(
child: Column(
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
verticalDirection: verticalDirection,
children: children,
),
)
: GestureDetector(
onTap: onTap,
child: Column(
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
verticalDirection: verticalDirection,
children: children,
),
),
);
Widget row({
final EdgeInsets padding = EdgeInsets.zero,
final EdgeInsets margin = EdgeInsets.zero,
final List<Widget> children = const <Widget>[],
final MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
final MainAxisSize mainAxisSize = MainAxisSize.max,
final CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
final VerticalDirection verticalDirection = VerticalDirection.down,
final BoxDecoration? decoration,
final double? width,
final double? height,
final bool isScrollable = false,
final VoidCallback? onTap,
}) =>
Container(
width: width,
height: height,
decoration: decoration,
padding: padding,
margin: margin,
child: isScrollable
? SingleChildScrollView(
child: Row(
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
verticalDirection: verticalDirection,
children: children,
),
)
: GestureDetector(
onTap: onTap,
child: Row(
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
verticalDirection: verticalDirection,
children: children,
),
),
);
You can simply use ListTile and set the tile color like:
return const ListTile(
title: Text('This is a text'),
tileColor: Colors.lightBlue,
);
It will change the color of whole row in a ListView
Or you can also add a BoxDecoration to the TableRow.
Then add the background color as the color property to the BoxDecoration on the TableRow.
Table(
border: TableBorder.all(),
children: pairs
.asMap()
.map((index, pair) => MapEntry(
index,
TableRow(
decoration: BoxDecoration(
color: Theme.of(context)
.accentColor // Background color for the row
.withOpacity(index % 2 == 0 ? 1.0 : 0.5), // To alternate between dark and light shades of the row's background color.
),
children: [
Padding(
padding: const EdgeInsets.all(kDefaultMargin / 2),
child: Text(
pair.first,
),
),
Padding(
padding: const EdgeInsets.all(kDefaultMargin / 2),
child: Text(pair.second),
)
])))
.values
.toList()
);