One way is to use Stack to stack the background image and the column which contains the top textfield and the bottom white container. Then you clip the bottom container
Code example:
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Material App Bar'),
),
body: Builder(
builder: (context) {
return Stack(
alignment: Alignment.topCenter,
children: [
Container(
color: Color.fromRGBO(4, 20, 31, 1),
),
Padding(
padding: const EdgeInsets.only(top: 50.0),
child: Column(
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
child: TextField(
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
)
),
),
),
Expanded(
child: ClipPath(
clipper: MyClipper(radius: 50),
child: Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
),
),
)
],
),
)
],
);
}
),
),
);
}
}
class MyClipper extends CustomClipper<Path>{
final double radius;
MyClipper({required this.radius});
@override
Path getClip(Size size) {
return Path()
..lineTo(0, 2*radius)
..arcTo(
Rect.fromCircle(center: Offset(radius, 2*radius), radius: radius),
math.pi,
math.pi/2,
false
)
..lineTo(radius, radius)
..lineTo(size.width-radius, radius)
..arcTo(
Rect.fromCircle(center: Offset(size.width-radius, 0), radius: radius),
math.pi/2,
-math.pi/2,
false
)
..lineTo(size.width, size.height)
..lineTo(0, size.height)
..close()
;
}
@override
bool shouldReclip(MyClipper oldClipper) {
return false;
}
}