flutterflutter-image

Create curved transparent gradient on photo


I want to create this filter effect:

Now my image looks like this:

Is there any best practice or a package that does that? Or do I have to create my own bézier curve for that?

Thanks!


Solution

  • It somehow depends on the size of your images as well. the image on behind ratio should be vertically bigger than your UI component. and if we use the BoxFit.cover it will cover its parent. vertically will exceed the parent (so the head of the girl is being cut) and horizontally will cover. For this behind image I applied a little blur effect as well, you can customize the effect to any way you want.

    For the image on top to achieve the white semi-transparent overlay, you can put a container on top and clip it the way you want with ClipPath with a CustomClipper:

    import 'dart:ui';
    
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return const Scaffold(
          body: Center(
            child: SizedBox(
              width: 600,
              height: 400,
              child: BezierBlurImage(imagePath: 'assets/test_image.png'),
            ),
          ),
        );
      }
    }
    
    class BezierBlurImage extends StatelessWidget {
      const BezierBlurImage({Key? key, required this.imagePath}) : super(key: key);
    
      final String imagePath;
    
      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(
          builder: (context, constraints) {
            final width = constraints.maxWidth;
            final height = constraints.maxHeight;
            return Stack(
              fit: StackFit.expand,
              children: [
                Container(
                  width: width,
                  height: height,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: AssetImage(imagePath),
                      colorFilter: ColorFilter.mode(
                        Colors.blue[300]!,
                        BlendMode.modulate,
                      ),
                      fit: BoxFit.cover,
                    ),
                  ),
                  child: BackdropFilter(
                    filter: ImageFilter.blur(sigmaX: 2, sigmaY: 2),
                    child: Container(
                      color: Colors.black.withOpacity(0),
                    ),
                  ),
                ),
                Center(
                  child: Container(
                    width: 200,
                    height: 250,
                    decoration: BoxDecoration(
                      color: Colors.blueAccent,
                      image: DecorationImage(
                        image: AssetImage(imagePath),
                        fit: BoxFit.cover,
                      ),
                    ),
                    child: ClipPath(
                      clipper: BezierClipper(),
                      child: Container(
                        color: Colors.white.withOpacity(0.4),
                      ),
                    ),
                  ),
                ),
              ],
            );
          },
        );
      }
    }
    
    class BezierClipper extends CustomClipper<Path> {
      @override
      Path getClip(Size size) {
        final width = size.width;
        final height = size.height;
        return Path()
          ..moveTo(0, 0)
          ..lineTo(width, 0)
          ..conicTo(0, 0, 0, height * 0.6, 0.3);
      }
    
      @override
      bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
    }
    
    

    enter image description here