How to set a fix space between Row items - flutter

I have a Row containing a small image followed by a Text. I'm trying to set a fix space between those 2 widgets (for the moment they are stuck one after the other). That should be something simple but I don't know a nice way to do it...
Here is my code:
Widget displayRow(String imageName, String text, TextStyle textStyle) {
Widget widget = Container(
margin: const EdgeInsets.symmetric(vertical: 8.0),
color: Colors.green,
child: Row (
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image.asset(
"images/${imageName}",
width: 32.0,
height: 32.0,
alignment: Alignment.center,
fit: BoxFit.scaleDown
),
Text(text, style: textStyle),
],
),
height: 120.0,
);
return widget;
}
I have put this code in a function because I intend to use it several times to display different rows all on the same pattern (an image + a text).
Thanks for the help

You can use a Container with a relatively small width:
Widget displayRow(String imageName, String text, TextStyle textStyle) {
Widget widget = Container(
margin: const EdgeInsets.symmetric(vertical: 8.0),
color: Colors.green,
child: Row (
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image.asset(
"images/${imageName}",
width: 32.0,
height: 32.0,
alignment: Alignment.center,
fit: BoxFit.scaleDown
),
Container(width: 10.0), // You can adjust it to suit your design
Text(text, style: textStyle),
],
),
height: 120.0,
);
return widget;
}
You can also opt for wrapping the Image widget inside a Container and giving it a certain padding :
Container(
padding: EdgeInsets.all(15.0),
child: Image.asset(
"images/${imageName}",
width: 32.0,
height: 32.0,
alignment: Alignment.center,
fit: BoxFit.scaleDown
),
),

Related

How to center one element and place the second element next to it

In my layout I have two Widgets in a row, a text and a button.
How can I achieve something like below, where only the Text is centered, and the icon is simply next to it?
---------------------------
Text *
---------------------------
Using Row would center all the contents and would output something like
---------------------------
Text *
---------------------------
Tried: Row(children:[widget1, widget2], mainAxisAlignment: MainAxisAlignment.center);
But this centers both items, causing the text to look off-centered.
You can use CompositedTransformTarget and CompositedTransformFollower as mentioned on comment section by pskink.
class AppPT extends StatelessWidget {
const AppPT({super.key});
#override
Widget build(BuildContext context) {
final LayerLink _layerLink = LayerLink();
return Scaffold(
body: Column(
children: [
Stack(
children: [
Align(
child: CompositedTransformTarget(
link: _layerLink,
child: Container(
color: Colors.red,
width: 100,
height: 60,
alignment: Alignment.center,
child: Text("btn"),
),
),
),
CompositedTransformFollower(
link: _layerLink,
targetAnchor: Alignment.centerRight,
followerAnchor: Alignment.centerLeft,
child: Container(
color: Colors.cyanAccent,
width: 12,
height: 12,
alignment: Alignment.center,
child: Text("*"),
),
),
],
)
],
),
);
}
}
There are few tricks I can think of,
You can use Stack widget with Position.
including another widget on right by applying opacity(invisible) on current snippet.
using transform will be handle if you know the width of the widget.
Transform.translate(
offset: Offset(20 / 2, 0), //20 is the * box size
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
color: Colors.red,
width: 100,
height: 60,
alignment: Alignment.center,
child: Text("btn"),
),
Container(
color: Colors.green,
width: 20,
height: 20,
child: Center(child: Text("*")),
),
],
),
),
Place text and second widget inside row then put the row inside container with alignment center and use SizedBox for spacing between widget instead of Padding Widget.
Container(
color: Colors.green,
alignment: Alignment.center,
height: 100,
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text("Text"),
SizedBox(width: 10),
Text("*"),
],
),
);

Unable to wrap Text inside Container in Flutter

I have the following tree: Scaffold > Column > Row > Container > Text.
I want the Text to wrap, and The Great Google in most cases told me that Expanded is what i need, but none of the below cases worked for me:
Row wrapped inside Expanded
Container wrapped inside Expanded
Text wrapped inside Expanded
All of the above have the same result.
Here's my code for the page's body:
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF282B32),
body: Column(
children: <Widget>[
createRow(
context,
"https://i.stack.imgur.com/6Utrc.jpg?s=256&g=1",
"GuildProtect is a powerful, baterries-included moderation bot for your *safe* server!"
),
createDivider(),
createRow(
context,
"https://cdn.discordapp.com/avatars/967406876029501462/bd3c60dcf55c83fba41b15fba89f798a.webp?size=256",
"This is a very beatiful (because it's pink) avatar of this shitty website creator, enjoy!"
)
]
)
);
}
Row createRow(BuildContext context, String imageUrl, String text) {
const containerHeight = 256.0;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: containerHeight,
padding: const EdgeInsets.only(left: 50, top: 25, bottom: 25),
child: Image.network(imageUrl),
),
Container(
alignment: Alignment.centerRight,
height: containerHeight,
padding: const EdgeInsets.only(right: 50, top: 25),
child: Text(
text,
style: TextStyle(
color: const Color(0xFFFFFCF9),
fontWeight: FontWeight.bold,
fontSize: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.3).fontSize,
),
),
),
]
);
}
Divider createDivider() {
return const Divider(
color: Color(0xFF131518),
indent: 30,
endIndent: 30,
thickness: 1,
height: 20,
);
}
}
I also saw some answers on SO recommending to cut the text or show ellipsis, but i dont need this behaviour, i need the text to actually wrap. This video's second solution shows exactly what i want to achieve (and no, the solution from there didn't help).
Any help is appreciated!
In createRow(), wrap the second Container() with Flexible().
Flexible(
child: Container(
alignment: Alignment.centerRight,
height: containerHeight,
padding: const EdgeInsets.only(right: 50, top: 25),
child: Text(
text,
style: TextStyle(
color: const Color(0xFFFFFCF9),
fontWeight: FontWeight.bold,
fontSize: DefaultTextStyle.of(context)
.style
.apply(fontSizeFactor: 1.3)
.fontSize,
),
),
),
)
Lemme know if it worked for your use case.
Why are you seeing this?.
Well, this is because the width of the widgets which you are trying to put, is greater then the screen size.
Possible solutions:
Try to add width property to the second Container in the Row
try to use .fit property, which will fit the image in it's father widget size.
I don't think that wrapping the container in Expanded wouldn't fix the situation as I see the text is too long (the screen has overflowed by 260 pixels).
Try to use TextOverflow as mentioned in link.
Please, let me know if any of my solutions works.
Anywhere you want to use a text and its length is not specified, you may encounter a folding error.
My suggestion is to use Expanded.
This is the output of your code snippet in my simulator
your code Output in mobile
It is enough to wrap the second Container with an Expanded widget (createRow) :
Row createRow(BuildContext context, String imageUrl, String text) {
const containerHeight = 256.0;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: containerHeight,
padding: const EdgeInsets.only(left: 50, top: 25, bottom: 25),
child: Image.network(imageUrl),
),
--> Expanded(
child: Container(
alignment: Alignment.centerRight,
height: containerHeight,
padding: const EdgeInsets.only(right: 50, top: 25),
child: Text(
text,
style: TextStyle(
color: const Color(0xFFFFFCF9),
fontWeight: FontWeight.bold,
fontSize: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 1.3).fontSize,
),
),
),
),
]
);
}
and output:
--> after Wrap Container with Expanded Widget
It is noteworthy that this part of your work is not responsive.
Probably, the texts are too big in my emulator because of the difference made by the DefaultTextStyle.of(context) class.
Anyway, I hope it solved your problem.
full code:
I used MediaQuery for setting fontSize Because no details are provided from the content of the defaultTextStyle class.
import 'package:flutter/material.dart';
class TstPage extends StatelessWidget {
const TstPage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF282B32),
body: Column(
children: <Widget>[
createRow(
context,
"https://i.stack.imgur.com/6Utrc.jpg?s=256&g=1",
"GuildProtect is a powerful, baterries-included moderation bot for
your *safe* server!"
),
createDivider(),
createRow(
context,
"https://cdn.discordapp.com/avatars/967406876029501462/bd3c60dcf55c83fba41b15fba89f798a.webp?size=256",
"This is a very beatiful (because it's pink) avatar of this shitty
website creator, enjoy!"
)
]
)
);
}
Row createRow(BuildContext context, String imageUrl, String text) {
const containerHeight = 256.0;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: containerHeight,
padding: const EdgeInsets.only(left: 50, top: 25, bottom: 25),
child: Image.network(imageUrl),
),
Expanded(
child: Container(
alignment: Alignment.centerRight,
height: containerHeight,
padding: const EdgeInsets.only(right: 50, top: 25),
child: Text(
text,
style: TextStyle(
color: const Color(0xFFFFFCF9),
fontWeight: FontWeight.bold,
fontSize: MediaQuery.of(context).size.width*0.04,
),
),
),
),
]
);
}
Divider createDivider() {
return const Divider(
color: Color(0xFF131518),
indent: 30,
endIndent: 30,
thickness: 1,
height: 20,
);
}
}

Child Container's Height is depending on parent Container's Widget

I Creating a Container giving it a height and width responsively, but the issue is that in the child of Container I use a ListView to show some Cards which are basically container and I give them a constant height but the height of the card are totally depending on Container's height, even if I give the of cards to 0, nothing will happen, and when I increase the container height, the card height increases, same happens while decreasing. this never happens to me before in flutter, may be this is a new version, I need help, please give answers with an explanation. You can see the Code of the container and Card.
Container Code
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 0),
child: Container(
child: ListView(
scrollDirection: Axis.horizontal,
children: sample
.map((obj) => card.PredictionCard(
temprature: obj.temprature, status: obj.status))
.toList(),
),
height: _device.height * 0.22,
decoration: cardDecoration,
),
),
Card Code
class PredictionCard extends StatelessWidget {
final temprature;
final status;
const PredictionCard({this.temprature, this.status});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Container(
margin: EdgeInsets.symmetric(
vertical: 10,
),
height: 120,
decoration: predictionCardDecoration,
width: 100,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'$temprature',
style: TextStyle(
color: Colors.white,
fontSize: 40,
),
),
Text(
'$status',
style: TextStyle(
color: Colors.white, fontSize: 15, letterSpacing: 1),
),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
children: [
Image(
image: AssetImage('assets/rainIcon.png'),
),
Text(
'23%',
style: TextStyle(
color: Colors.white, fontSize: 15, letterSpacing: 1),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset('assets/rainDropIcon.png'),
Text(
'0%',
style: TextStyle(
color: Colors.white, fontSize: 15, letterSpacing: 1),
),
],
),
],
)
],
),
),
);
}
}
Code of Class from where Responsive height is integrated
// widget binging method
class DeviceConfig {
final height = WidgetsBinding.instance.window.physicalSize.height /
WidgetsBinding.instance.window.devicePixelRatio;
final width = WidgetsBinding.instance.window.physicalSize.width /
WidgetsBinding.instance.window.devicePixelRatio;
}
// using media query {uses context to set value of device configuration}
class DeviceConfigQuery {
var height;
var width;
DeviceConfigInit(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
}
}
Ok I will allow myself to copy the answer from another post as its worth to remember that and I woudnt put it better.
Constraints in Flutter works a bit different than usual. Widgets
themselves do not have constraints.
When you specify a width/height on a Container, you're not
constraining Container. You're constraining the child of Container.
Container will then size itself based on the size of its child.
As such, parent widgets always have the last word on how their
descendants should be sized.
If you want to go around this, you have to use Align widget:
Container(
width: 200.0,
height: 200.0,
child: Align(
alignment: Alignment.topLeft,
child: Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.red),
),
),
);
This may seem weird and limiting. But this single weirdness is the
reason why Flutter's layout is so powerful and composable.
answered by:
RĂ©mi Rousselet in this post https://stackoverflow.com/a/54717843/2945977
In your example instead of using Padding, use Align with alignment: Alignment.center

How to design a flutter timeline widget with fixed times and variable events

I'm making a vertical timeline in flutter but I've hit a roadblock on how to design the timeline and event system. The image below is what I have and how I want it to show. The yellow container is the event, events can be on either side and overlap other events. Currently it's three rows inside a column, with the sides expanded and middle fixed width. Each dot is its own widget with a datetime associated with it.
Now my issue is, how can I make it so that the events line up with the center numbers based on datetime?
I'm currently using positioned on the event with top, but I have no way of getting the distance from the top of the center widgets.
main build
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildLeftCol(),
_buildCenterCol(CustomTime().times),
_buildRightCol(12)
],
),
)
],
),
_buildLeftCol
Widget _buildLeftCol() {
return Expanded(
child: Container(
child: Stack(
children: <Widget>[
_buildEventItem(DateTime.now()),
],
)
),
);
}
_buildEventItem
Widget _buildEventItem(DateTime time) {
var index = CustomTime().getIndexOf(time);
var position = 41.0 * index;
return Positioned(
left: 160,
top: position,
child: Container(
width: 200,
height: 200,
color: Colors.yellow,
child: Text("data")
),
);
}
Widget _buildCenterCol(List<DateTime> list) {
return Column(children: list.map((time) => timeItem(time)).toList());
}
Widget timeItem(DateTime time) {
if(time.minute != 00) {
return Padding(
padding: const EdgeInsets.only(top:8.0, bottom: 8.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(9.0),
child: Container(
height: 18,
width: 18,
color: Color(0xFF0288D1),
),
),
);
} else {
return ClipRRect(
borderRadius: BorderRadius.circular(32.0),
child: Container(
height: 64,
width: 64,
color: Color(0xFF00305A),
child: Center(child: Text(DateFormat('HH').format(time), style: TextStyle(color: Colors.white, fontSize: 32.0),))
)
);
}
}
You can try the timeline_tile package released recently. Currently it does not provide dotted lines, but you can easily achieve what you desire with its tiles, for example:
TimelineTile(
alignment: TimelineAlign.center,
rightChild: Container(
constraints: const BoxConstraints(
minHeight: 120,
),
color: Colors.lightGreenAccent,
),
leftChild: Container(
color: Colors.amberAccent,
),
);
If aligned center os manual you can have children on both sides.
Also, the beautiful_timelines repository contains some examples built with this package.

Flutter Align widget does not align

I'm building a ListItem and I want the text to be in a cardview that takes up the entire width and just enough height as the text size is. This is my code
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Align(
child: Container(
width: double.infinity,
height: 200.0,
color: Colors.pinkAccent,
),
),
Container(
width: double.infinity,
color: Colors.deepPurpleAccent,
child: Align(
alignment: Alignment.bottomCenter,
child: Card(
child: Text(
'some text',
textAlign: TextAlign.center,
),
)),
)
],
);
}
There are two widgets inside the stack, I want the second widget to lap above the first widget but just for a small part. Yet as you can see, the align of the second widget isn't at the bottom but at the top. I also tried switching Container and Align as child of each other but to no avail. Here's a screenshot of the resulting code
There is nothing like "BottomCenter" (with capital B). You should use Alignment.bottomCenter. But you probably need to set alignment for Stack.
Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
Container(
width: double.infinity,
height: 200.0,
color: Colors.pinkAccent,
),
Container(
width: double.infinity,
color: Colors.deepPurpleAccent,
child: Card(
child: Text(
'some text',
textAlign: TextAlign.center,
),
),
)
],
)