I have a text widget and I want to place a container which covers the whole word in that text. To achieve that I found a code that gives the dimensions of a string for the specified text style. Using that I created a simple flutter app in which you can press the button to place that container on the next word.
Here is the whole program
import 'package:flutter/material.dart';
const loremIpsum =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
debugShowCheckedModeBanner: false,
home: SelectText(),
);
}
}
class SelectText extends StatefulWidget {
SelectText({super.key});
late List<String> splitted;
int current = 0;
double left = 0;
Size size = const Size(0, 0);
@override
State<SelectText> createState() => _SelectTextState();
}
class _SelectTextState extends State<SelectText> {
@override
void initState() {
super.initState();
widget.splitted = loremIpsum.split(' ').toList();
}
@override
Widget build(BuildContext context) {
double textScaleFactor = MediaQuery.of(context).textScaleFactor;
return SafeArea(
child: Scaffold(
body: Column(
children: [
Stack(
children: [
Positioned(
left: widget.left,
top: 0,
child: Container(
width: widget.size.width,
height: widget.size.height,
color: Colors.red,
),
),
const Text(loremIpsum),
],
),
const SizedBox(height: 20),
FilledButton(
onPressed: () {
var (pos, size) =
getNextPositionAndSize(textScaleFactor: textScaleFactor);
setState(() {
widget.left = pos;
widget.size = size;
});
},
child: const Text("FF GO NEXT"),
),
],
),
),
);
}
(double, Size) getNextPositionAndSize({required double textScaleFactor}) {
String text = "";
for (int i = 0; i <= widget.current; i++) {
text += " ";
text += widget.splitted[i];
}
double nextPos = getTextSize(
text: text,
textStyle: const TextStyle(),
textScaleFactor: textScaleFactor,
).width;
Size size = getTextSize(
text: widget.splitted[widget.current + 1],
textStyle: const TextStyle(),
textScaleFactor: textScaleFactor,
);
setState(() {
widget.current += 1;
});
return (nextPos, size);
}
}
Size getTextSize({
required String text,
required TextStyle textStyle,
required double textScaleFactor,
}) {
final size = (TextPainter(
text: TextSpan(text: text, style: textStyle),
maxLines: 1,
textScaleFactor: textScaleFactor,
textDirection: TextDirection.ltr)
..layout())
.size;
return size;
}
This code works fine for the iPhone 14 - iOS 17 simulator and macOS Desktop App but when I hand it over to my friend and he runs it on an android device I don't get the desired outcome which means the code doesn't calculate the dimensions right. Could you help me with that?
You don't need to calculate the string dimensions of every word for your purpose. Instead, you can use RichText Widget that you can style/manipulate every word separately.
I rewrote the code that is suitable for your purpose below. Regardless of the font type or font size, the following code will always work.
Hope this helps. Good luck :)