When displaying text in your Flutter app, you may notice that Flutter's text rendering capabilities are lacking some features commonly used in web pages, such as CSS
float, which is used to place an image or other element on the left or right side of the text, allowing the text to wrap around it.
For example, let's say we're starting with some rich text, and we want to add a drop-cap for the first letter, and float a couple images in the text.
To accomplish this, we could resort to using a package such as
webview_flutter to display the text in a platform native web view using HTML and CSS, but that comes with its own complications and limitations — and after all, we are writing a Flutter app, not a web app — it would be better if the text and floated items could be rendered with widgets!
FloatColumn to the rescue
We can accomplish our goal with the help of the
float_column package, whose only dependency is Flutter, so it works seamlessly on all Flutter platforms: Android, iOS, Linux, macOS, Web, and Windows.
This is the code we're starting with — basically, just some rich text:
Text.rich( TextSpan( children: [ TextSpan(text: '“This is what you shall do...'), ... ], ), ),
First, let's add the drop cap
Floatablefor the drop cap widget.
float: FCFloat.startcauses the child
DropCapwidget to float at the start of the text so the text can wrap around it.
Remove the '“T' from the TextSpan.
// 1. Import the `float_column` package. import 'package:float_column/float_column.dart'; // 2. Wrap the `Text.rich` in a `FloatColumn` widget. FloatColumn( children: [ Text.rich( TextSpan( children: [ // 3. Add a `WidgetSpan` and `Floatable` for the drop cap widget. WidgetSpan( child: Floatable( float: FCFloat.start, child: DropCap('“T', height: 3), ), // 4. Remove the '“T' from the TextSpan. TextSpan(text: 'his is what you shall do...'), ], ), ), ], )
Which gives us this:
Next, let's add the floating images
This involves adding a
Floatable for each image widget.
For the first image, we're setting
float: FCFloat.end. Because the current text direction is left-to-right (LTR), the image is floated to the right side of the text. If the current text direction was RTL it would float to the left side. The possible
FCFloat values are
We're also setting
clear: FCClear.both for both images. Like the CSS
clear property, this makes sure the floating widget is placed below floating widgets on both sides. The possible
FCClear values are
clearMinSpacing property provides a way to add or subtract additional spacing in relation to the cleared position. A positive value moves the widget down, and a negative value moves it up.
import 'package:float_column/float_column.dart'; FloatColumn( children: [ Text.rich( TextSpan( children: [ WidgetSpan( child: Floatable( float: FCFloat.start, child: DropCap('“T', height: 3), ), // Add a `WidgetSpan` and `Floatable` for each floating image: WidgetSpan( child: Floatable( float: FCFloat.end, clear: FCClear.both, clearMinSpacing: 16, maxWidthPercentage: 0.33, padding: EdgeInsetsDirectional.only(start: 8), child: Img(name: 'walt.jpg', title: 'Walt Whitman'), ), ), WidgetSpan( child: Floatable( float: FCFloat.start, clear: FCClear.both, clearMinSpacing: 60, maxWidthPercentage: 0.33, padding: EdgeInsetsDirectional.only(end: 12), child: Img(name: 'jeremy.jpg', title: 'Photo by...'), ), ), TextSpan(text: 'his is what you shall do...'), ], ), ), ], )
Which accomplishes our goal:
Try it out with Flutter Web:
For the complete source code for this example (with some tweaks so it looks good on screens of any size), see:
And for info about the
float_column package see: