flutterdartflutter-clippath

How to fit the text inside a specific area of custom clipPath


I have created this UI enter image description here

the problem is right now that the text is not displayed fully. How can i put the text for example inside the upper part of the ui so that the text is not covered by the clipped area of the ui, so that it can ignore somehow the bottom part of the ui where i have marked as red container in this picture

enter image description here

this is my complete code

class QuoteWidget extends StatelessWidget {
  const QuoteWidget({super.key, required this.child});
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 20),
      alignment: Alignment.center,
      child: AppCustomClipPath(
        shadow: Shadow(
          color: Colors.grey.withOpacity(0.5), //color of shadow
          blurRadius: 15, // blur radius
          offset: const Offset(0, 2),
        ),
        clipper: CustomQuotePainter(),
        child: Container(
          constraints: BoxConstraints(
            maxHeight: MediaQuery.of(context).size.height * 0.6,
            maxWidth: MediaQuery.of(context).size.width,
          ),
          color: Colors.white,
          padding: const EdgeInsets.only(
            bottom: 60,
            top: 15,
            left: 15,
            right: 15,
          ),
          child: Text(
            "Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum  Lorem Impsum Lorem    Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem       Impsum",
            style: Theme.of(context)
                .textTheme
                .displaySmall!
                .copyWith(color: Colors.black),
          ),
        ),
      ),
    );
  }
}

class CustomQuotePainter extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Path path0 = Path();
    path0.moveTo(size.width * 0.0001600, size.height * 0.0004800);
    path0.lineTo(size.width * 1.0015800, size.height * -0.0002800);
    path0.lineTo(size.width * 1.0015800, size.height * 0.6996800);
    path0.lineTo(size.width * 0.4008200, size.height * 0.7007400);
    path0.lineTo(size.width * 0.2009700, size.height * 0.9068600);
    path0.lineTo(size.width * 0.2006800, size.height * 0.6992200);
    path0.lineTo(size.width * -0.0002100, size.height * 0.7003800);
    path0.lineTo(size.width * 0.0001600, size.height * 0.0004800);
    path0.close();

    return path0;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
    return false;
  }
}

@immutable
class AppCustomClipPath extends StatelessWidget {
  final Shadow? shadow;
  final CustomClipper<Path>? clipper;
  final Widget? child;

  const AppCustomClipPath({
    super.key,
    @required this.shadow,
    @required this.clipper,
    @required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      key: UniqueKey(),
      painter: _ClipShadowShadowPainter(
        clipper: clipper!,
        shadow: shadow!,
      ),
      child: ClipPath(child: child, clipper: this.clipper),
    );
  }
}

class _ClipShadowPainter extends CustomPainter {
  final Shadow? shadow;
  final CustomClipper<Path>? clipper;

  _ClipShadowPainter({@required this.shadow, @required this.clipper});

  @override
  void paint(Canvas canvas, Size size) {
    var paint = shadow!.toPaint();
    var clipPath = clipper!.getClip(size).shift(shadow!.offset);
    canvas.drawPath(clipPath, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

Solution

  • Try this ShapeBorder

    class CustomShapeBorder extends ShapeBorder {
      @override
      EdgeInsetsGeometry get dimensions =>
          EdgeInsets.only(left: 8, right: 9, bottom: 20, top: 8); //todo
    
      @override
      Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
        Path path0 = Path();
        path0.addRect(rect);
        Path bottomCurve = Path()
          ..moveTo(rect.bottomLeft.dx + rect.width * .2, rect.bottom)
          ..lineTo(rect.bottomLeft.dx + rect.width * .2, rect.bottom + 40)
          ..lineTo(rect.bottomLeft.dx + rect.width * .2 + 80, rect.bottom);
    
        path0.close();
        return Path.combine(PathOperation.union, path0, bottomCurve);
      }
    
      @override
      Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
        return getInnerPath(rect);
      }
    
      @override
      void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}
    
      @override
      ShapeBorder scale(double t) => this;
    }
    

    And use it like

    Container(
      constraints: BoxConstraints(
        maxHeight: MediaQuery.of(context).size.height * 0.6,
        maxWidth: MediaQuery.of(context).size.width,
      ),
      decoration:
          ShapeDecoration(shape: CustomShapeBorder(), color: Colors.green),
      child: Text(
        "Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum  Lorem Impsum Lorem    Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem Impsum Lorem       Impsum",
        style: Theme.of(context)
            .textTheme
            .displaySmall!
            .copyWith(color: Colors.black),
      ),
    ),