206

How can I have a line of text with different formatting?

e.g.:

Hello World

RBT
  • 24,161
  • 21
  • 159
  • 240
Dvdwasibi
  • 10,537
  • 7
  • 22
  • 22

8 Answers8

416

You should use the RichText widget.

A RichText widget will take in a TextSpan widget that can also have a list of children TextSpans.

Each TextSpan widget can have a different TextStyle.

Here is the example code to render: Hello World

var text = RichText(
  text: TextSpan(
    // Note: Styles for TextSpans must be explicitly defined.
    // Child text spans will inherit styles from parent
    style: const TextStyle(
      fontSize: 14.0,
      color: Colors.black,
    ),
    children: <TextSpan>[
      TextSpan(text: 'Hello'),
      TextSpan(text: 'World', style: const TextStyle(fontWeight: FontWeight.bold)),
    ],
  ),
);
Stijn de Witt
  • 40,192
  • 13
  • 79
  • 80
Dvdwasibi
  • 10,537
  • 7
  • 22
  • 22
  • This approach will ignore the font scaling specified by the phone, potentially impacting accessibility. For more details see https://github.com/flutter/flutter/issues/61802#issuecomment-660546228 – Castrohenge Aug 25 '21 at 16:55
  • 5
    `Text.rich` should be used to avoid the scaling issue. – Castrohenge Aug 25 '21 at 17:03
  • 1
    Text.rich actually uses the app's default TextStyle - which could be very helpful. Check here: https://stackoverflow.com/a/64060239/3041394 – schlenger Mar 16 '22 at 12:38
49

[UPDATE]

The below answer fits best for couple of words and not for a paragraph,If you have a long sentence or a paragraph where you need to format a particular text prefer using RichText as suggested by @DvdWasibi in the above answer

[OLD ANSWER]

I like keeping my code short and clean this is How I Would do it add two text fields in a row one with Normal font and another bold,

Note: This may not look good for a long paragraph looks good for Headlines etc.

Row(children: [
  Text("Hello"),
  Text("World", style: const TextStyle(fontWeight: FontWeight.bold))
]);

and you should get a desired output as "Hello World"

kalucki23
  • 172
  • 4
  • 15
Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131
  • 15
    This is not a great idea, if you are going to have a paragraph of text. Each Text() inside the row create its own vertical/horizontal space. – Muhammad Adil May 09 '19 at 18:54
  • so whats the alternative to using Row? and if I want text side by side with different formatting – Mahesh Jamdade May 10 '19 at 10:47
  • 3
    look at above answer from @Dvdwasibi , just try your implementation with large paragraph and you will find kind of a two different paragraphs side by side. your answer is Correct for 2/3 words but not for a paragraph. – Muhammad Adil May 13 '19 at 10:09
  • 1
    Agreed, thanks by the way I have updated my answer. :) – Mahesh Jamdade Dec 30 '20 at 04:13
18
return RichText(
  text: TextSpan(
    text: 'Can you ',
    style: TextStyle(color: Colors.black),
    children: <TextSpan>[
      TextSpan(
        text: 'find the',
        style: TextStyle(
          color: Colors.green,
          decoration: TextDecoration.underline,
          decorationStyle: TextDecorationStyle.wavy,
        ),
        recognizer: _longPressRecognizer,
      ),
      TextSpan(text: 'secret?'),
    ],
  ),
);
Axel A. García
  • 683
  • 9
  • 21
Parvesh Khan
  • 1,356
  • 1
  • 10
  • 9
10

You should use the Text.rich constructor from Text class here.

By using the rich constructor you can display a paragraph with differently styled TextSpans.

Why I recommended it instead of RichText is because of by using RichText you will required to define the parent TextStyle in RichText but using the rich constructor of Text you don't need explicitly defined the parent TextStyle in Text.rich

Here is the example how to use it with same result Using RichText

const text = RichText(
  text: TextSpan( 
    // Here is the explicit parent TextStyle
    style: new TextStyle(
      fontSize: 16.0,
      color: Colors.black,
      fontFamily: 'Montserrat', 
    ),
    children: <TextSpan>[
      new TextSpan(text: 'Hello'),
      new TextSpan(text: 'World', style: new TextStyle(fontWeight: FontWeight.bold)),
    ],
  ),
 );

Using rich constructor of Text

const text = Text.rich(
  TextSpan(
    // with no TextStyle it will have default text style
    text: 'Hello',
    children: <TextSpan>[
      TextSpan(text: 'World', style: TextStyle(fontWeight: FontWeight.bold)),
    ],
  ),
)
Fran Na Jaya
  • 280
  • 3
  • 8
6

I've solved a similar problem by using flutter_html widget with custom styles for different tags. Actually, I've got the strings in different languages and some parts of them should be bold, so it wasn't easy to determine which part of the string I should make bold since strings was in l10n locale files. Here is example:

Container(
   child: Html(
              data: "<p>My normal text <b>with bold part</b> in any place</p>",
              style: {
                "p": Style(
                    fontSize: FontSize.large,
                    fontWeight: FontWeight.normal),
                "b": Style(
                  fontWeight: FontWeight.bold,
                ),
    )
 );

I think this approach is useful in case you have a lot of differently styled text inside your regular text.

kazakovs
  • 379
  • 1
  • 3
  • 9
4

Not fully tested but you can try this helper function that uses Text.rich and takes in the fullText and the textToBold then returns a Text:

static Text boldTextPortion(
    String fullText,
    String textToBold,
) {
    final texts = fullText.split(textToBold);
    final textSpans = List.empty(growable: true);
    texts.asMap().forEach((index, value) {
      textSpans.add(TextSpan(text: value));
      if (index < (texts.length - 1)) {
        textSpans.add(TextSpan(
          text: textToBold,
          style: const TextStyle(fontWeight: FontWeight.bold),
        ));
      }
    });
    return Text.rich(
      TextSpan(
        children: <TextSpan>[...textSpans],
      ),
    );
}
mgcaguioa
  • 1,443
  • 16
  • 19
3

Regex

You can use this widget. The example below always make numbers bold.

import 'package:flutter/material.dart';

class TextBold extends StatelessWidget{
  final String text;
  final String regex;
  static const _separator = " ";

  const TextBold({Key key, this.text, this.regex = r'\d+'}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    final parts = splitJoin();

    return Text.rich(TextSpan(
        children: parts.map((e) => TextSpan(
            text: e.text,
            style: (e.isBold)
                ? const TextStyle(fontFamily: 'bold')
                : const TextStyle(fontFamily: 'light')))
            .toList()));
  }

  // Splits text using separator, tag ones to be bold using regex
  // and rejoin equal parts back when possible
  List<TextPart> splitJoin(){
    assert(text!=null);

    final tmp = <TextPart>[];

    final parts = text.split(_separator);

    // Bold it
    for (final p in parts){
      tmp.add(TextPart(p + _separator,p.contains(RegExp(regex))));
    }

    final result = <TextPart>[tmp[0]];
    // Fold it
    if (tmp.length>1) {
      int resultIdx = 0;
      for (int i = 1; i < tmp.length; i++)
        if (tmp[i - 1].isBold != tmp[i].isBold) {
          result.add(tmp[i]);
          resultIdx++;
        }
        else
          result[resultIdx].text = result[resultIdx].text
              + tmp[i].text;
    }

    return result;
  }
}

class TextPart{
  String text;
  bool isBold;

  TextPart(this.text, this.isBold);
}

Roddy R
  • 1,222
  • 10
  • 10
0
RichText()

Or if you receiving text from for example 'someText'.tr, so use styled_text pub package.

TuGordoBello
  • 4,350
  • 9
  • 52
  • 78