Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wants to add Elevation on CustomClipper<Path> border only not the whole material beneath

I'm trying to add elevation on the custom path by using Material's elevation but looks like is not doing anything, I've tried other method but got elevation on whole material (rectangular).

import 'package:flutter/material.dart';

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

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

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.pink[300],
        body: Column(
          children: <Widget>[
            TopContainer(),
          ],
        ));
  }
}

class TopContainer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ClipPath(
        clipper: ImageClipper(),
        child: Material(
          elevation: 15.0,
          child: Container(
            decoration: BoxDecoration(
              image: DecorationImage(
                fit: BoxFit.cover,
                image: NetworkImage(
                  'https://images.pexels.com/photos/3309467/pexels-photo-3309467.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
                ),
              ),
            ),
            constraints: BoxConstraints.expand(
              width: double.infinity,
              height: MediaQuery.of(context).size.height * 0.5,
            ),
          ),
        ));
  }
}

class ImageClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    var path = Path();
    path.lineTo(0.0, size.height);
    var firstControlPoint = Offset(size.width * 0.35, size.height * 0.75);
    var firstEndPoint = Offset(size.width * 0.65, size.height * 0.85);
    path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
        firstEndPoint.dx, firstEndPoint.dy);
    ///////////////////////////////////////////////
    var secondControlPoint = Offset(size.width * 0.85, size.height * 0.90);
    var secondEndPoint = Offset(size.width, size.height * 0.75);
    path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
        secondEndPoint.dx, secondEndPoint.dy);

    //    path.lineTo(size.width, size.height * 0.9);
    path.lineTo(size.width, 0.0);
    path.close();
    return path;
  }

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

I'm trying to add elevation on the custom path by using Material's elevation but looks like is not doing anything, I've tried other method but got elevation on whole material (rectangular).

enter image description here

like image 412
Mahamat Avatar asked Oct 15 '25 14:10

Mahamat


1 Answers

use that custom ShapeBorder

class WaveShapeBorder extends ShapeBorder {
  @override EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
  @override ui.Path getInnerPath(ui.Rect rect, {ui.TextDirection textDirection}) => null;

  @override
  ui.Path getOuterPath(ui.Rect rect, {ui.TextDirection textDirection}) {
    var ctrl1 = FractionalOffset(0.35, 0.75).withinRect(rect);
    var end1  = FractionalOffset(0.65, 0.85).withinRect(rect);
    var ctrl2 = FractionalOffset(0.85, 0.90).withinRect(rect);
    var end2  = FractionalOffset(1.0,  0.75).withinRect(rect);
    return Path()
      ..moveTo(rect.topLeft.dx, rect.topLeft.dy)
      ..lineTo(rect.bottomLeft.dx, rect.bottomLeft.dy)
      ..quadraticBezierTo(ctrl1.dx, ctrl1.dy, end1.dx, end1.dy)
      ..quadraticBezierTo(ctrl2.dx, ctrl2.dy, end2.dx, end2.dy)
      ..lineTo(rect.topRight.dx, rect.topRight.dy)
      ..close();
  }

  @override void paint(ui.Canvas canvas, ui.Rect rect, {ui.TextDirection textDirection}) {}
  @override ShapeBorder scale(double t) => this;
}

and this sample code for testing:

class WaveShapeBorderTest extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [Colors.teal, Colors.green],
          begin: Alignment.topRight,
          end: Alignment.centerLeft,
        ),
      ),
      child: Stack(
        children: [
          Material(
            elevation: 6,
            shape: WaveShapeBorder(),
            clipBehavior: Clip.antiAlias,
            child: Image.asset('images/someImage.png'),
          ),
        ],
      ),
    );
  }
}

of course you have a freedom on how you use it but the main idea is to use Material.shape and Material.clipBehavior properties

this is a final result:

enter image description here

EDIT and if you think your shadow is too "light" you can add one additional Container with custom shadows:

class WaveShapeBorderTest extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [Colors.teal, Colors.green],
          begin: Alignment.topRight,
          end: Alignment.centerLeft,
        ),
      ),
      child: Stack(
        children: [
          Container(
            decoration: ShapeDecoration(
              shape: WaveShapeBorder(),
              shadows: [
                BoxShadow(color: Colors.black, blurRadius: 16, offset: Offset(2, 2), spreadRadius: 8),
              ]
            ),
            child: Material(
              clipBehavior: Clip.antiAlias,
              shape: WaveShapeBorder(),
              child: Image.asset('images/someImage.png',),
            ),
          ),
          Icon(Icons.photo, size: 64,),
        ],
      ),
    );
  }
}

and you will see this:

enter image description here

like image 181
pskink Avatar answered Oct 18 '25 05:10

pskink



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!