Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Created February 27, 2020 20:00
Show Gist options
  • Save slightfoot/4c2b504959e7fcd793aaaf8f0e0ee0a1 to your computer and use it in GitHub Desktop.
Save slightfoot/4c2b504959e7fcd793aaaf8f0e0ee0a1 to your computer and use it in GitHub Desktop.
Curved Background Login Form Example - Utilises overdraw of the CustomPaint to draw the curve behind the content even when the keyboard appears.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Color(0xFF3A455C),
inputDecorationTheme: InputDecorationTheme(
contentPadding: EdgeInsets.all(8.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(48.0),
),
),
buttonColor: Color(0xFF3A455C),
buttonTheme: ButtonThemeData(
buttonColor: Color(0xFF3A455C),
textTheme: ButtonTextTheme.primary,
shape: StadiumBorder(),
height: kMinInteractiveDimension,
),
),
home: LoginScreen(),
);
}
}
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Scaffold(
body: LoginForm(
height: constraints.maxHeight,
),
);
},
);
}
}
class LoginForm extends StatelessWidget {
const LoginForm({
Key key,
@required this.height,
}) : super(key: key);
final double height;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
CustomPaint(
painter: _CurvePainter(
height: height,
foreground: Theme.of(context).primaryColor,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.person),
),
),
SizedBox(height: 16.0),
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
),
),
SizedBox(height: 16.0),
RaisedButton(
onPressed: () {},
child: Text('SIGN IN'),
),
SizedBox(height: 8.0),
FlatButton(
onPressed: () {},
child: Text(
'Forgot Password?',
style: TextStyle(
color: Color(0xFF8fA4f7),
decoration: TextDecoration.underline,
),
textAlign: TextAlign.left,
),
),
SizedBox(height: 8.0),
Row(
children: <Widget>[
Expanded(
child: RaisedButton(
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2.0),
),
color: Color(0xFF404988),
child: Text(
'FACEBOOK',
style: TextStyle(
fontSize: 18.0,
letterSpacing: 1.25,
),
),
),
),
const SizedBox(width: 4.0),
Expanded(
child: RaisedButton(
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2.0),
),
color: Color(0xFF5C6EE8),
child: Text(
'GOOGLE',
style: TextStyle(
fontSize: 18.0,
letterSpacing: 1.25,
),
),
),
),
],
),
SizedBox(height: 8.0),
FlatButton(
onPressed: () {},
child: Text.rich(
TextSpan(
children: <TextSpan>[
TextSpan(
text: 'Don’t have an account? ',
),
TextSpan(
text: 'Sign up',
style: TextStyle(
color: Color(0xFF8fA4f7),
decoration: TextDecoration.underline,
),
),
],
),
style: TextStyle(
color: Color(0xFF656565),
),
textAlign: TextAlign.left,
),
),
SizedBox(height: 32.0),
],
),
),
],
);
}
}
class _CurvePainter extends CustomPainter {
const _CurvePainter({
@required this.height,
@required this.foreground,
});
final double height;
final Color foreground;
@override
void paint(Canvas canvas, Size size) {
final height20 = height / 5.0;
final top = height20;
final mid = height20 * 2.0;
final bottom = height20 * 2.5;
final center = size.width / 2.0;
canvas.save();
canvas.translate(0.0, -(height * 0.5) + 32.0);
canvas.drawPath(
Path()
..moveTo(0.0, top)
..quadraticBezierTo(0.0, mid, center, mid)
..quadraticBezierTo(size.width, mid, size.width, bottom)
..lineTo(size.width, -height)
..lineTo(0.0, -height)
..close(),
Paint()
..style = PaintingStyle.fill
..color = foreground);
canvas.restore();
}
@override
bool shouldRepaint(_CurvePainter oldDelegate) {
return height != oldDelegate.height || foreground != oldDelegate.foreground;
}
}
@slightfoot
Copy link
Author

screenshot-2020-02-27_20 01 03 393 screenshot-2020-02-27_20 01 28 516

@pishguy
Copy link

pishguy commented Apr 16, 2020

@slightfoot woooooooooow, thanks a lot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment