How do I clip a variable sized widget in flutter?

Tony

I'm building a chat app where audio messages can accompany the text. The widget that displays this is a very standard looking chat bubble (think iMessage) with one twist - the bubble becomes a progress bar when the audio is playing. The progress bar is essentially just a gradual change in the background color. You can see the layout in this dartpad (hit run). A screenshot of the mock is here:

enter image description here

Because the chat bubble is rounded, I need the progress bar to round only at the end. In other words, it should always be rounded on the left as it is flush with the left side of the message but it should be flat on the right until it hits the end of the message. I think ClipRRect is the right widget to do this.

However, because the message bubble width is variable, I use a FractionallySizedBox as the progress bar. 1/10th the way through the audio, it should be 1/10th the width of the chat bubble. Then I use Positioned.fill to wrap the progress bar so that the fraction is taken out of the full message bubble width. ClipRRect does not seem to play nicely wrapping Positioned.fill I believe it expects the child to have a set size:

RenderBox was not laid out: RenderClipRRect#3b019 relayoutBoundary=up13
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'

This is a dartpad to the version with the not-working ClipRRect. Is there some other widget I can wrap Position.fill in to make it clippable? Or maybe a better way to lay this out?

Sanjay Sharma

Please try the following code.

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: ChatAudioTextBubble("Test message"),
        ),
      ),
    );
  }
}

class ChatAudioTextBubble extends StatefulWidget {
  final String text;

  ChatAudioTextBubble(this.text);

  @override
  _ChatAudioTextBubbleState createState() => _ChatAudioTextBubbleState();
}

class _ChatAudioTextBubbleState extends State<ChatAudioTextBubble>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
      lowerBound: 0.0,
      upperBound: 1.0,
      value: 0.0,
      duration: const Duration(milliseconds: 1000),
      vsync: this,
    )..addListener(() {
        this.setState(() {});
      });
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _onTapHandler() {
    _controller.reset();
    _controller.forward(from: 0.0);
  }

  Widget build(BuildContext context) {
    return GestureDetector(
        behavior: HitTestBehavior.translucent,
        onTap: () {
          _onTapHandler();
          print(
              "Plays the audio and starts the animation which takes _controller.value from 0-1");
        },
        child: Stack(children: [
          Positioned.fill(
              child: Container(
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                color: Color(0xFFE6E6E6)),
          )),
          Container(
              constraints: BoxConstraints(
                  minWidth: 40,
                  maxWidth: MediaQuery.of(context).size.width * 0.70),
              child: _buildTextChild()),
          Positioned.fill(
            child: ClipRRect(
              borderRadius: BorderRadius.only(
                topRight: Radius.circular(10.0),
                bottomRight: Radius.circular(10.0),
              ),
              child: FractionallySizedBox(
                alignment: Alignment.centerLeft,
                heightFactor: 1,
                widthFactor: _controller == null ? 0 : _controller.value,
                child: Container(
                  decoration: BoxDecoration(
                    shape: BoxShape.rectangle,
                    color: Colors.blue.withOpacity(0.3),
                    borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(10.0),
                      topRight: Radius.zero,
                      bottomLeft: Radius.circular(10.0),
                      bottomRight: Radius.zero,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ]));
  }

  Widget _buildTextChild() {
    final color = Colors.black;
    return Padding(
        padding: EdgeInsets.fromLTRB(16, 8, 16, 8),
        child: Text(widget.text, style: TextStyle(color: color, fontSize: 18)));
  }
}


Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How do I change the decibels of a clip

In Flutter, how do I find a widget in some (x,y) position?

How do I clip a circular shape?

In Flutter, how do I pass data into a Stateless Widget?

How do I clip the edges of my tab bar container in flutter?

How do I add a Dismissible Widget on my ListView in Flutter?

How do I run Flutter widget tests with shadows enabled?

Accidentally deleted flutter default widget code, how do I fix it?

How do I declare a variable sized array in C?

How do I clip an ExcelReference against the UsedRange?

Flutter how do I remove unwanted padding from Text widget?

Flutter - How do I check if a variable exists?

How do I make this Picker clip properly

How do I limit the number of words in a Text Widget in Flutter?

How do I animate Color using an AnimatedBuilder widget? Flutter

How do I render a widget based on a condition in flutter?

How do I save data from a stateful widget in Flutter?

How to clip the corners of Positioned widget in flutter

How do i make background images in container widget change in flutter

How do I align a TextFormField and Text widget inside a row in Flutter?

How do I clip the overflow of my Polyline

How do I make a clip outside of method?

How to clip a widget in flutter

How do I convert a DropdownButton widget into a listview widget in flutter

How do I make my widget clickable in flutter?

How do i correctly initialise a variable from a stateful widget to another widget in flutter and maintain state?

How do I change the alignments of a widget and all of its descendants in Flutter?

Flutter: How do I create a widget that contains distinct instances of a list

How can I make such clip circles in flutter?