Search code examples
flutterflutter-layout

How to implement time text wrapping behaviour in chat bubble on Flutter


A lot of native mobile chat messengers, like telegram, whatsapp, etc, implement this wrapping behaviour: wrapping time label to a new line when there is no enough room for text.

Simple chat bubble consist of two parts: Text and time label. In simple case, they are almost positioned on the same baseline. Even when the text is multiline (baseline with last line). But in some cases, when there is no free space and the texts are trying to intersect, an indent is added at the bottom of bubble.

It will be simple to understand, if I show it by pictures and videos: enter image description here

And 2 videos:

multiline https://youtu.be/eigLIHWaub8

singleline https://youtu.be/9GMDFYwMqdU

How to implement it on Flutter?


Solution

  • You can use Stack with fake placeholder for time (or another info) on first layer and real positioned text on the second layer.

        class CustomCard extends StatelessWidget {
    
    
         final String msg;
          final String additionalInfo;
    
          CustomCard({
            @required this.msg,
            this.additionalInfo = ""
          });
    
          @override
          Widget build(BuildContext context) {
            return Card(
              child: Stack(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: RichText(
                      text: TextSpan(
                        children: <TextSpan>[
    
                      //real message
                      TextSpan(
                        text: msg + "    ",
                        style: Theme.of(context).textTheme.subtitle,
                      ),
    
                      //fake additionalInfo as placeholder
                      TextSpan(
                          text: additionalInfo,
                          style: TextStyle(
                              color: Color.fromRGBO(255, 255, 255, 1)
                          )
                      ),
                    ],
                  ),
                ),
              ),
    
              //real additionalInfo
              Positioned(
                child: Text(
                  additionalInfo,
                  style: TextStyle(
                    fontSize: 12.0,
                  ),
                ),
                right: 8.0,
                bottom: 4.0,
              )
            ],
          ),
        );
     }
    

    And result can looks like: result screenshot