How to insert image in Dart Text() being wrapped? - flutter

I'm trying to put an image inside a long text being wrapped in a Dart AlertDialog() widget. Let me illustrate the problem with some images.
What I want:
What I want
What I have:
What I have
(The coin Image() is flushed to the line after my text while I want it being part of it).
I'm currently trying to use the Wrap() widget, see the minimal code below
Wrap(children: [
Flexible(
child: Text('Are you sure you want to buy this item for ' +
item.price.toString())),
Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 0, 5),
child: Image.asset(
"path/to/my/image",
width: 30,
)),
Text('?'),
]),
It is supposed to place its children's widgets below each other when reaching the width of the Wrap() context. However, it's not working as I would like, since it put the Image widget below the Text() one being wrapped by Flexible() instead of putting it next to this last.
My opinion about this problem is that the wrapping of a text line still creates a "text box" that will go until the end of the context width (i.e. the end of the line) even if the last line of text stops earlier. This is due to the fact that the previous line had obviously reached the width of the Wrap() context. This is probably why the Image.assets() inserted as the next widget in the Wrap() children list is flushed to the next line anyway.
Of course I've tried several other approaches, namely to use the Row() widget with the Text() widget wrapped inside a Flexible() widget as follow:
Row(children: [
const Flexible(
child: Text(
'Are you sure you want to buy this item for ' + item.price.toString(),
)),
Row(children: [
Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 0, 5),
child: Image.asset(
"path/to/my/image",
width: 30,
)),
Text('?'),
]),
Which of course does not work since it places the Image() widget not next to the last word of the wrapped text but next to the whole generated Flexible() text zone.
Of course, the problem comes with the fact that the text is long and is, therefore, broken into several lines. The first approach would have worked perfectly if the text was not broken into several lines.
Is there any way to either
Limit the size of a wrapped line in order to avoid it being considered as a full line when wrapped;
Insert an image as a text character so that only the use of Flexible() do the trick to solve this problem;
Break a row widget into several lines automatically.
Thanks in advance for your time

Try Text.rich:
Text.rich(TextSpan(
children: <InlineSpan>[
TextSpan(text: 'Flutter is'),
WidgetSpan(
child: Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 0, 5),
child: Image.asset(
"path/to/my/image",
width: 30,
),),),
TextSpan(text: '?'),
],
)

I think the text widget extends to the end of the line which prevents the image from getting behind. To solve this problem I propose to split the first sentence into two blocks of text like this:
Wrap(children: [
Flexible(
child: Text('Are you sure you want to')),
Flexible(child: Text('buy this item for ' )),
Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 0, 5),
child: Image.asset(
"path/to/my/image",
width: 30,
Text('?'),
]),
Other way is to look on the way of Stack widget which seem to be a good solution

Related

Flutter - Align only one widget inside of a Row

I have a text that can vary in height, followed by a PopupMenuButton. I want the text to be center-aligned on the vertical axis (so that there isn't a weird white space when there's only 1 ligne of text) but the PopupMenuButton to stay in the top right corner, no matter the height of the text. Thus using crossAxisAlignement doesn't work here since all widgets are affected. Using an Align widget on the text or PopupMenuButton doesn't work and textAlign doesn't either It seems any solution must be implemented on the Row level and not in its children, which makes sense.
For now I'm using a Row to contain these 2 widgets, but I'm not so sure it is what I need if I want the behaviour mentionned before. Is there a solution for the Row, or another widget I can use for this ?
Here is the code as it stands. Thanks.
Row(
children: [
Expanded(
child: RichText(
text: TextSpan(), // bunch of text in there
)
)
),
SizedBox( // To box in the 3 dots icon (material design forces 48px otherwise)
height: 24,
width: 24,
child: PopupMenuButton(
padding: EdgeInsets.all(0),
onSelected: menuSelect,
itemBuilder: (BuildContext context) {
return [
PopupMenuItem(value: 0, child: Text('Read', textAlign: TextAlign.center,),),
PopupMenuItem(value: 1, child: Text('Delete', textAlign: TextAlign.center,),)
];
},
),
)
],
)
Here's a way to do it :
Wrap your SizedBox with an Align(alignment: Alignment.topRight)
Wrap your Row with an IntrinsicHeight so that the cross-axis
doesn't stretch
Alternatively, you might want to look into the Stack widget if you're not familiar with it.

How can I keep a TextField in a single run in a Wrap until it reaches a minimum width?

Display:
Code
Card(
child: Wrap(children: [
Text('Hi. What\'s your name?'),
Container(
constraints: BoxConstraints(minWidth: 300), child: TextField())
]))
Demo
https://dartpad.dev/65527c29343bd9afca842dff66907e6f?null_safety=true
What's needed
I would like for the TextField to run adjacent to right of the Text. It should have a minimum constraint width of 300. Then if the available space to the right of the Text is less than 300, it should wrap and place itself below the text.
Basically, I need to implement similar method to Expadable for the TextField that only covers the first run of the Wrap.
Problem
The TextField automatically extends to the largest possible width.
Because this is a Wrap, it automatically sends it below the initial Text where it has the most available width.
Use Row Widget instead of Wrap and expand the text
Card(
child: Row(children: [
Expanded(child: Text('Hi. What\'s your name?')),
Container(width: 300, child: TextField())
]),
),

Flutter - Text overflow in Row when another widget in the same Row is flexible

I want to implement a Row having two Text widgets and a middle line like this:
The following code is my current implementation.
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Text',
overflow: TextOverflow.ellipsis
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: 16, right: 16),
height: 1,
child: Container(
color: Colors.black
)
),
),
Text(
'Right Text'
)
]
)
The problem of this code is that the left text overflows if it is long like this:
The expected output is:
Wrapping the first Text widget with a Flexible can solve the overflow issue, but the output is not the same as the expected output because of the Expanded widget that fills the space between two Text widgets with a line.
How can I achieve this? Any help is highly appreciated!

Column widget draws a line between children when they are wrapped in specific widget with decoration. How can i cure this?

The problem is visible on the attached screenshot.
Code of a main widget:
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Flexible(
child: Decor(
child: Container(),
),
flex: 1,
),
Flexible(
child: Decor(
child: Container(),
),
flex: 6,
)
],
);
Code of a Decor widget:
Container(
decoration: BoxDecoration(
color: COLOR,
),
margin: const EdgeInsets.symmetric(
horizontal: MEDIUM_PADDING,
),
padding: const EdgeInsets.all(MEDIUM_PADDING),
width: 300.0,
child: child,
);
Answering in advance "Why would you even need to do such a Decor Widget"? Both flexibles will be populated with data of some sort. Second flexible will be with a ListView inside and the first one will be a "Header" for what is inside a ListView. Data is retrieved from server every 10s, so the main widget is wrapped with a StreamBuilder.
Problem is that StreamBuilder cannot be shrinked to the size of its child, whereas ListView can, so I wrap both "Header" and a ListView in Decor so that grey background color doesn't take all available space on a screen which than produces black line seen on a screenshot?
So the question is: is there a way either to remove the black line between two widgets in a column?
Also, if you know magic of how to shrink StreamBuilder to the size of its child please answer here too.
Ok I know that this is not a very nice solution and more like workaround but I think the only way to get rid of the line is to set border color of the container in your Decor widget
Container(
decoration: BoxDecoration(
color: COLOR,
border: Border.all(width: 0, color: COLOR) //added line
),
margin: const EdgeInsets.symmetric(
horizontal: MEDIUM_PADDING,
),
padding: const EdgeInsets.all(MEDIUM_PADDING),
width: 300.0,
child: child,
);
First I thought setting border width to 0 will help it but that didn't work.. Color did

How to wrap a row of texts?

I have two Text widgets inside a Row. I want to show the text widgets one after another, and wrap the second one to the next line if it doesn't fit in the first line.
I've tried Flexible, Wrap, and what not. I can't seem to get it working.
Row(
children: <Widget>[
Text('This is some text.'),
Text('Another piece of text.')
]
);
I want the output to look something like this (the screen edges are indicated by |):
|This is some text. Another |
|piece of text. |
The best I could get was the following:
|This is some Another piece|
|text. of text. |
Edit: Thanks for replies, everyone. I've tried RichText too, and it works, but I want to bind more than one gesture to each TextSpan element, which cannot be done easily with RichText. I'm about to create a question on that, but stackoverflow doesn't allow me to create more than one question in 90 minutes.
UPDATED ANSWER
The first thing you are doing wrong is using Row to put one text widget under another text.
|This is some text. Another |
|piece of text. |
This is the desired UI are you are trying to achieve right? So From your question, it is clear that you want two text widget one under another.
so this code will work for you. replace Row with Column widget like this. If you want to continue with Row each of your text will wrap but not one text after another. here is the working code. I have putted two text to show you that how they wrap one after another. Checkout the image below to see the result
body: Center(
child: Container(
color: Colors.amberAccent,
width: 200,
height: 200,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Flexible(
fit: FlexFit.tight,
child: Text(
'This is some text.long text more long Text, even more long text',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
Flexible(
fit: FlexFit.tight,
child: Text(
'Another piece of text.not so long text yet needs to be a liitle long text',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
)
],
),
),
),
),
here is the screenshot
The Wrap Widget will either keep the two Texts on the same line or put the second Text on the next line if there's overflow.
Wrap(
children: [
Text(
'This is some text.',
),
Text(
'Another piece of text.',
),
],
),
You can achieve that using the RichText widget:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(),
body: RichText(
text: TextSpan(
children: [
TextSpan(text: "This is some text."),
TextSpan(text: "Another piece of text. Another piece of text. Another piece of text. Another piece of text."),
],
),
),
);
}
The RichText widget displays text that uses multiple different styles.
The text to display is described using a tree of TextSpan objects,
each of which has an associated style that is used for that subtree.
The text might break across multiple lines or might all be displayed
on the same line depending on the layout constraints.
RichText