My issue is that flutter breaks Text at non whitespace characters:
How can I tell flutter not to beak text at the "/" but only when it encounters a whitespace?
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Center(
child: Container(
width: 220.0,
child: Text(
'This should not break here x/y/z',
style: TextStyle(fontSize: 30.0),
),
),
),
),
);
}
}
I have been looking into packages like auto_size_text, but found nothing addressing this problem.
Edit:
Working with '\n' is not an option since the length of the text varies,but it always includes the three x/y/z characters divided by slashes at the end.
I would rather not calculate the size of the rendered text in advance to determine whether a newline should be included before x/y/z. That would seem a little heavy, since these are card titles contained in a ListView.
On the web there is no issue, there the text is only broken at whitespaces:
<!DOCTYPE html>
<html>
<body>
<div style="background-color: grey; height: 200px; width: 400px;">
<p style="font-size: 24.0pt;">
This should not break here x/y/z
</p>
</div>
</body>
</html>
I usually use TextAlign.justify to fit the text, and to my liking, you can try:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: Center(
child: Container(
width: 220.0,
child: Text(
'This should not break here x/y/z',
textAlign: TextAlign.justify,
style: TextStyle(fontSize: 30.0),
),
),
),
),
);
}
}
Also TextAlign.center not bad.
https://github.com/flutter/flutter/issues/61081#issuecomment-1103330522
Replace space with NO-BREAK SPACE '\u00a0' where you don't want to break. This forces two characters around it to stay put together in
the same line.
Insert ZERO WIDTH NO-BREAK SPACE '\ufeff' between the characters you don't want to break. Same as the above but takes no space.
Optionally insert ZERO WIDTH SPACE '\u200b' where you want to break. This allows two characters around it to break freely.
To break only around spaces, replace
Text(string)
with
Text(string.split('').join('\ufeff').replaceAll('\ufeff \ufeff', ' '))
Related
This is the model of what i want to do !
I'm contacting you because I'm trying to copy the Libération newspaper application but I'm stuck (already!) on the question of the title.
I have attached a visual and I will try to be clear. I would like the first part of the title to be in red and then the title to continue in black and line up again, aligned to the left, under the red title. I have tried many methods to no avail. Expanded, Wrap... either the text sticks out or, when I manage to make the line break of the black text, it is positioned under the black text, not under the red text, considering that the block starts on the right of the red block.
I tried Wrap, Row, Expanded.
Thank you :-)
this is just an example ,
If it's dynamic you might want to use: a separator; to split the title or the text or another symbol
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
final String title =
"Chez Pol; Et si on mesurait le bruit à l'Assemblée pour la santé des députés?";
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: SafeArea(
child: Scaffold(
body: RichText(
text: TextSpan(
text: title.split(';')[0].toString(),
style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
children: <TextSpan>[
TextSpan(
text: title.split(';')[1].toString(),
style: const TextStyle(color: Colors.black),
),
],
),
),
),
),
);
}
}
If I use Row() instead of Center(), it will not be displayed,just blank.
I expect a music player like layout.
Make 2 Row, the 1st Row contain "LeftMenu" and "Expanded Container" for content .
Putting this in scaffold gives you the left menu:
drawer: const Drawer(
child: Text("Left Menu")
),
Putting this inside scaffold body works. Expanded and a row:
Column(
children: [
Expanded(
child: Container(
color: Colors.green,
child: const Center(child: Text("1")),
)
),
Row(
children: const [
Text("1"),
SizedBox(width: 10),
Text("2"),
],
),
],
)
If you replace center with row, it probably displays but in the top left corner and not middle. Try to wrap your Row with Center and it should display in the middle. For the row you need to add a mainAxisAlignment.
import 'package:flutter/material.dart';
const Color darkBlue = 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: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:[ Text('Left menu'),Text('Place container here')]
),),
),
);
}
}
This is actually the wrong question.
The real problem is: if the ListView is nested by Column, Row, it will not be displayed.
You need to use Expanded or Container on the outside and then nest it with Colmn or Row.
I need to word-wrap some text and have been reading how Flexible and Expanded help make that happen. My problem is the rendering breaks when I put the resulting widgets in a Column. I read that you need to wrap parent columns in Expanded widgets, too, but that gave the same broken result?
Here's a text version of what I'm after
The DartPad code below produces that, but when the commented Column is uncommented, no text is rendered?
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeDat.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return
// Column( children: [ // <- Uncommenting Column breaks rendering
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('[Avatar]'),
SizedBox(width: 10),
Expanded(
child: Column(mainAxisAlignment: MainAxisAlignment.start, children: [
Flexible(
child: Text(
'Really Really Really Really Really Really Really Really '
'Really Really Really Really Really Really Long Heading'),
),
Flexible(
child: Text(
'Really Really Really Really Really Really Really Really '
'Really Really Really Really Really Really Long Text'),
),
]),
),
SizedBox(width: 10),
Text('[Button]'),
// ]),
],
);
}
}
You can solve the issue just by wrapping the Row with an Expanded.
try this
Flexible(fit: FlexFit.loose,child:.....)
I tried my best to summarize what I want in the title, but here is a more detailed explanation:
Widgets' centers should be placed evenly throughout the row.
A larger widget should be able to extend into the "personal space" of a smaller one.
When it would overflow, overflow should start on the bigger items, cutting into the smaller ones later.
Here's an illustration:
Behavior with Expandeds:
Everything fits
Longest item is overflowing - The problem with this is that the longest text would easily fit if it could extend into the boundary of the shorter texts next to it.
How it should work:
Please notice: The boxes are not Expanded, but the centers of them are evenly placed (not by themselves, but as if they were the centers of Expandeds). As opposed to just laying them out with usual MainAxisAlignment options; neither of those ensures that the centers are evenly placed, a longer text can push the shorter ones to one side. (Illustraion of what I don't want)
Everything fits
Longest text extends into the area of the shorter ones
When two boxes would touch, overflow the longer one
Extreme case - default to even sizes
This may be asking a lot, but I think there should be a way of achieving these, what's more, I think this should be the default way rows with texts work.
Any help on any sub-request is much appreciated.
Edit: I understand that everything I described is pretty complicated when put together. I would be happy to know a way to just simply place center lines evenly, with different width boxes (and no, spaceEvenly doesn't do this). Overflowing behavior can be a different question.
Have you tried mainAxisAlignment: MainAxisAlignment.spaceEvenly? Then you can play with the padding. It seems that you would also like to make your UI responsive, try the LayoutBuilder class. The documentation can be found here https://flutter.dev/docs/development/ui/layout/responsive .
First of all use 3 Expanded() for taking spaces for 3 Text() Widgets after that you can align your text at center using a container. Hope this solution will meet your requirement.
import 'package:flutter/material.dart';
final Color darkBlue = 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) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Container(
alignment: Alignment.center,
child: Text('Lorem', style: TextStyle(fontSize: 24),),
),
),
Expanded(
child: Container(
alignment: Alignment.center,
child: Text('Lorem ispum', style: TextStyle(fontSize: 24),),
),
),
Expanded(
child: Container(
alignment: Alignment.center,
child: Text('Lorem', style: TextStyle(fontSize: 24),),
),
),
]
);
}
}
I have a Container where I need to show a barcode and I'd love to have the barcode to be as wide as possible on the screen.
For now I set the font size at a reasonable size that suits all devices, but it's only temporary of course.
How can I solve this? This is the code I am using for building the Widget.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Container(
padding: const EdgeInsets.all(12.0),
child: Column(
children: <Widget>[
SizedBox(
width: double.infinity,
child: Text(_barcode, style: TextStyle(fontFamily: 'Code128', fontSize: 90.0))
),
Text(_barcode, style: TextStyle(fontSize: 40.0))
]
),
)
);
}
I believe what you're looking for is FittedBox.
BoxFit applies whichever 'fit' you want to stretch/scale the child to fit in the box. It doesn't perform a pure 'stretch' on the text but rather the space it should take up. You shouldn't specify the text's size at the same time.
That looks like this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
MyAppState createState() {
return new MyAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: Container(
color: Colors.blue,
width: 300.0,
height: 200.0,
child: FittedBox(
fit: BoxFit.contain,
child: Text("Whee"),
),
),
),
),
),
);
}
}
If you're wanting to actually 'stretch' the text (i.e. make the actual characters wider or taller) you'll have to do something a bit more custom.
If that's the case, look at CustomPaint, CustomPainter, TextPainter, and the Canvas translate & scale options. Basically, you would need to create a class extending CustomPainter in which you created a TextPainter, laid it out at a particular size, painted it onto the canvas, and then scaled it to fit the actual size of the CustomPainter (or do you scale the canvas first - I forget...). Then you'd pass an instance of that class to CustomPaint.
FittedBox is what worked for me but there is a twist. I also had to style my fontSize to a big number for it to work. Hope this helps.
child: FittedBox(
fit: BoxFit.fitHeight,
child: Text(
"Your Expanded Text :)",
style: TextStyle(fontSize: 400.0),
),
),
The code sample in the question has a Text widget as one of the children: of a Column widget. The width of the Text parent is unknown.
So to maximise the width and size of the Text widget in this case, wrap the Text widget in a FittedBox, then an Expanded.
child: Column(children: <Widget>[
Expanded(
child: FittedBox(
fit: BoxFit.contain,
child: Text(
'123',
)),
),
]),
The Text size should also automatically resize correctly even when the device is rotatated, or the screen resized, without overflow issues.
Expanded:
/// A widget that expands a child of a [Row], [Column], or [Flex]
/// so that the child fills the available space.
///
/// Using an [Expanded] widget makes a child of a [Row], [Column], or [Flex]
/// expand to fill the available space along the main axis (e.g., horizontally for
/// a [Row] or vertically for a [Column]). If multiple children are expanded,
/// the available space is divided among them according to the [flex] factor.
from /flutter/packages/flutter/lib/src/widgets/basic.dart
FittedBox:
/// Creates a widget that scales and positions its child within itself according to [fit].
you can use fitted box widget.
FittedBox(child:Text('text sample'));
https://api.flutter.dev/flutter/widgets/FittedBox-class.html
FittedBox would only work if it is provided some constraints, so make sure to provide one, like provide height as shown below:
SizedBox(
height: 400, // 1st set height
child: FittedBox(child: Text("*")), // 2nd wrap in FittedBox
)
Use TextPainter.width and a for loop to find the largest fitting font size (adding +1 is not very efficient, you may want to fine-tune that):
import 'package:flutter/material.dart';
main() => runApp(MaterialApp(
home: MyHomePage(),
theme: ThemeData(platform: TargetPlatform.iOS),
));
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text autoscale'),
),
body: Padding(
padding: EdgeInsets.all(32.0),
child: Center(
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final text = 'Hello World';
final style = TextStyle(fontWeight: FontWeight.bold); // apply your barcode font here
final fontSize = calculateAutoscaleFontSize(text, style, 30.0, constraints.maxWidth);
return Text(
text,
style: style.copyWith(fontSize: fontSize),
maxLines: 1,
);
},
),
),
),
);
}
}
double calculateAutoscaleFontSize(String text, TextStyle style, double startFontSize, double maxWidth) {
final textPainter = TextPainter(textDirection: TextDirection.ltr);
var currentFontSize = startFontSize;
for (var i = 0; i < 100; i++) {
// limit max iterations to 100
final nextFontSize = currentFontSize + 1;
final nextTextStyle = style.copyWith(fontSize: nextFontSize);
textPainter.text = TextSpan(text: text, style: nextTextStyle);
textPainter.layout();
if (textPainter.width >= maxWidth) {
break;
} else {
currentFontSize = nextFontSize;
// continue iteration
}
}
return currentFontSize;
}
Wrap the text within a FittedBox widget, to force the text to be enclosed by a box. The FittedBox's size will depend on it's parent's widget. Within the FittedBox, the Text widget, can simply 'cover' the box, so the text doesn't stretch to fill the available space within the FittedBox. The enum BoxFit.fill, is a way to stretch the text to fit the entire space available within the FittedBox. You can change the dimensions of the box by altering the height and width of the FittedBox's parent, the Container.
Container(
height: _height,
width: _width,
FittedBox(
fit: BoxFit.fill,
child: Text("Whee"),
)
)