Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Detect content overflow and clip it

Tags:

I'm trying to use ClipRect with a Column inside it, but it doesn't seem to work well.

What I'd like to achieve is to clip the column's content and to show a text message if there is an overflow (if the column's content cannot be displayed within the available space).

Do you have any suggestions how I can make it happen?

import 'package:flutter/material.dart';

void main() => runApp(ContentOverflowDetectionApp());

class ContentOverflowDetectionApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Overflow detection"),
        ),
        body: Stack(
          fit: StackFit.expand,
          children: [
            ClipRect(
              child: Column(
                children: [
                  Container(
                    width: 300,
                    height: 400,
                    color: Colors.green[200],
                    child: Text('first widget'),
                  ),
                  Container(
                    width: 350,
                    height: 350,
                    color: Colors.yellow[200],
                    child: Text('overflowed widget'),
                  ),
                ],
              ),
            ),
            Positioned(
              child: Align(
                alignment: FractionalOffset.bottomCenter,
                child: Text("SHOW THIS TEXT ONLY IF CONTENT HAS OVERFLOWED."),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

like image 558
pasul Avatar asked Mar 10 '19 20:03

pasul


People also ask

How do you check the text overflow in Flutter?

Ellipsis: Use an Ellipsis (. . .) to indicate that text is overflow.

How do you resolve overflow issues in Flutter?

Solution : The solution to resolve this overflow error is to make your entire widget or in our case the Column scrollable. We can do that by wrapping our Column inside a SingleChildScrollView. Also, wrap the SingleChildScrollView with Center so that the entire UI is centered.

What is clipBehavior in Flutter?

Clip clipBehavior. Controls how the contents of the dialog are clipped (or not) to the given shape. See the enum Clip for details of all possible options and their common use cases. Defaults to Clip. none, and must not be null.


2 Answers

You shouldn't use ClipRect for your goals. Please try to add clipBehavior parameter with the value Clip.antiAlias to your Stack widget.

import 'package:flutter/material.dart';

void main() => runApp(ContentOverflowDetectionApp());

class ContentOverflowDetectionApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Overflow detection"),
        ),
        body: Stack(
          fit: StackFit.expand,
          clipBehavior: Clip.antiAlias,
          children: [
            Positioned(
              top: 0,
              child: Column(
                children: [
                  Container(
                    width: 300,
                    height: 400,
                    color: Colors.green[200],
                    child: Text('first widget'),
                  ),
                  Container(
                    width: 350,
                    height: 350,
                    color: Colors.yellow[200],
                    child: Text('overflowed widget'),
                  ),
                ],
              ),
            ),
            Positioned(
              child: Align(
                alignment: FractionalOffset.bottomCenter,
                child: Text("SHOW THIS TEXT ONLY IF CONTENT HAS OVERFLOWED."),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

This solution just fixes a clipping.

How to get height of a Widget? gives answer how to check widget height and add Text with a message about overflow

like image 111
Aleksandr Denisov Avatar answered Sep 22 '22 09:09

Aleksandr Denisov


For those who want a "height limiter" (a widget which limits the height of its children, and if the child wants to be too high, show some hint), here is my code snippet that you can copy-and-paste:

class HeightLimiter extends StatefulWidget {
  final Widget child;
  final double maxHeight;
  final double fadeEffectHeight;

  const HeightLimiter({Key key, this.maxHeight, this.child, this.fadeEffectHeight = 72}) : super(key: key);

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

class _HeightLimiterState extends State<HeightLimiter> {
  var _size = Size.zero;

  @override
  Widget build(BuildContext context) {
    return ConstrainedBox(
      constraints: BoxConstraints(
        maxHeight: widget.maxHeight,
      ),
      child: Stack(
        clipBehavior: Clip.hardEdge,
        children: [
          Positioned(
            top: 0,
            left: 0,
            right: 0,
            child: MeasureSize(
              onChange: (size) => setState(() => _size = size),
              child: widget.child,
            ),
          ),
          if (_size.height >= widget.maxHeight)
            Positioned(
              bottom: 0,
              left: 0,
              width: _size.width,
              child: _buildOverflowIndicator(),
            ),
        ],
      ),
    );
  }

  Widget _buildOverflowIndicator() {
    return Container(
      height: widget.fadeEffectHeight,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.bottomCenter,
          end: Alignment.topCenter,
          colors: [
            Colors.white.withAlpha(200),
            Colors.white.withAlpha(0),
          ],
          tileMode: TileMode.clamp,
        ),
      ),
    );
  }
}

And the MeasureSize just comes from https://stackoverflow.com/a/60868972/4619958.

Result looks like the following (the green children overflow the blue parent) when child too high; When child is short enough, nothing special is shown.

enter image description here

Thanks @Aleksandr and @Dpedrinha for their answer!

like image 23
ch271828n Avatar answered Sep 22 '22 09:09

ch271828n