'Flutter how to display a Custom Clipper when (or inside) using a Custom Scroll View

so here's the deal. I created (sort of) a custom clipper shaped like a wave inside a class called WaveClipper

the wave clipper class:

class WaveClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    var path = Path();
    path.lineTo(0, 220);
    path.quadraticBezierTo(size.width / 4, 160 , size.width / 2, 175);
    path.quadraticBezierTo(3 / 4 * size.width, 190, size.width, 130);
    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

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

And whenever I display it using a scaffold it shows fine however when I try to push it inside a SliverListView which is inside a CustomScrollView then nothing appears and there are no errors either. Is the clipper under the content? And how can I display it.

the clipper I am trying to show:

         Stack(
            children: [
              ClipPath(
                  clipper: WaveClipper(),
                  child: Container(
                    color: Colors.cyanAccent,
                  ))
               ],
             ),

where I am trying to show it:

Scaffold(
  appBar: AppBar(
    backgroundColor: Colors.white,
    elevation: 0.0,
    iconTheme: IconThemeData(
      color: Colors.cyanAccent,
    ),
  ),
  backgroundColor: Colors.white,
  body: CustomScrollView(
    physics: const BouncingScrollPhysics(),
    slivers: [
      SliverList(
        delegate: SliverChildListDelegate([
          //here 
          //there rest of the content (mostly buttons)
        ]),
      ),
    ],
  ),
)

Any help is appreciated and thank you for taking the time.



Solution 1:[1]

Try to give some dimension to your Container:

enter image description here

Stack(
  children: [
    ClipPath(
      clipper: WaveClipper(),
      child: Container(
        height: 300,
        color: Colors.amber.shade200,
      ),
    ),
  ],
),

Full source code

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      home: HomePage(),
    ),
  );
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0.0,
        iconTheme: IconThemeData(
          color: Colors.cyanAccent,
        ),
      ),
      backgroundColor: Colors.white,
      body: CustomScrollView(
        physics: const BouncingScrollPhysics(),
        slivers: [
          SliverList(
            delegate: SliverChildListDelegate([
              Stack(
                children: [
                  ClipPath(
                    clipper: WaveClipper(),
                    child: Container(
                      height: 300,
                      color: Colors.amber.shade200,
                    ),
                  ),
                ],
              ),
            ]),
          ),
        ],
      ),
    );
  }
}

class WaveClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    var path = Path();
    path.lineTo(0, 220);
    path.quadraticBezierTo(size.width / 4, 160, size.width / 2, 175);
    path.quadraticBezierTo(3 / 4 * size.width, 190, size.width, 130);
    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

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

Solution 2:[2]

        Container(
            height: device.size.height * 0.3,
            child: Scaffold(
              body: Stack(
                clipBehavior: Clip.none,
                children: [
                  ClipPath(
                      clipper: WaveClipper(),
                      child: Container(
                        color: Colors.cyanAccent,
                      ))
                ],
              ),
            ),
          ),

Wrap with a Scaffold and give that Scaffold a size using a Container, if anyone has a better solution by all means post it.

Solution 3:[3]

import 'package:flutter/material.dart';

class LoginScreen extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
   return Scaffold(
     body: Container(
       child: Stack(
         children: [
           Opacity(opacity: 0.5,
           child: ClipPath(
             clipper: WaveClipper(),
             child: Container(color: Colors.red,
             height: 200,),
           ),
           ),
           ClipPath(
             clipper: WaveClipper(),
             child: Container(color: Colors.deepOrange,
             height: 180,),
           ),
         ],
       ),
     ),
   );
  }
}

class WaveClipper extends CustomClipper<Path>{
  @override
  Path getClip(Size size){
    debugPrint(size.width.toString());
    var path = new Path();
    path.lineTo(0,size.height);
    var firstStart = Offset(size.width / 5,size.height);
    var firstEnd = Offset(size.width / 2.25,size.height - 50);
     path.quadraticBezierTo(firstStart.dx, firstStart.dy, firstEnd.dx, firstEnd.dy);

 var secondStart = Offset(size.width -(size.width/3.24), size.height - 105);
    var secondEnd = Offset(size.width, size.height - 10);
    path.quadraticBezierTo(secondStart.dx, secondStart.dy, secondEnd.dx, secondEnd.dy);

    path.lineTo(size.width, 0);
    path.close();
    return path;

  }

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

Solution 4:[4]

Optionally add dotted_decoration package if needed: https://pub.dev/packages/dotted_decoration

enter image description here

import 'package:flutter/material.dart';
import 'package:dotted_decoration/dotted_decoration.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: DiscountTile()),
    );
  }
}

class DiscountTile extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ClipPath(
      clipper: _DiscountTileClipper(),
      child: Container(
        clipBehavior: Clip.antiAlias,
        decoration: const BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(16)),
        ),
        child: ColoredBox(
          color: Colors.blue,
          child: Row(
            children: [
              SizedBox(width: 100),
              Expanded(
                child: DecoratedBox(
                  decoration: DottedDecoration(
                    linePosition: LinePosition.left,
                    color: Colors.red,
                    strokeWidth: 3,
                  ),
                  child: Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Text('hello world' * 20),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _DiscountTileClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    const Radius radius = Radius.circular(1);
    const bool clockwise = false;
    const double clipRadius = 20;
    const double decreaseValueWidgetWidth = 100.0;
    const double leftPadding = decreaseValueWidgetWidth + 9;

    return Path()
      ..lineTo(leftPadding - clipRadius, 0)
      ..arcToPoint(
        const Offset(leftPadding, 0),
        clockwise: clockwise,
        radius: radius,
      )
      ..lineTo(size.width, 0)
      ..lineTo(size.width, size.height)
      ..lineTo(leftPadding, size.height)
      ..arcToPoint(
        Offset(leftPadding - clipRadius, size.height),
        clockwise: clockwise,
        radius: radius,
      )
      ..lineTo(0, size.height)
      ..close();
  }

  @override
  bool shouldReclip(_DiscountTileClipper oldClipper) => true;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Andrea herrera
Solution 3 Rohit Kushwaha
Solution 4 Yauheni Prakapenka