使容器颤动,使曲线/凹面如下图所示?
make curve/ concave like below image with container in flutter?
我比较熟悉 ClipPath
小部件,但是借助于此,我只能制作角圆或边框圆和圆。我知道这将由 ClipPath
或 CustomPainter
小部件修复。但不知道该怎么做。
预期图像:
实际结果:
代码:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleExample(),
);
}
}
class SampleExample extends StatelessWidget {
const SampleExample({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
body: Container(
alignment: Alignment.bottomCenter,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.elliptical(
MediaQuery.of(context).size.width, 120.0)),
),
),
),
);
}
}
通过使用 Stack 小部件,我实现了您想要的布局。
- 绘制白色背景
- 堆叠底部椭圆红色矩形小部件
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleExample(),
);
}
}
class SampleExample extends StatelessWidget {
const SampleExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.vertical(
bottom: Radius.elliptical(
MediaQuery.of(context).size.width, 120.0)),
),
),
],
),
);
}
}
在 decoration>borderRadius
上用 bottom
替换 top
并在正文 Container
.
上使用 alignment: Alignment.topCenter
而不是 bottomCenter
body: Container(
alignment: Alignment.topCenter,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.elliptical(
MediaQuery.of(context).size.width, 120.0)),
),
),
),
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ClipPath(
clipper: CurveClipper(),
child: Container(
color: Colors.lightGreen,
height: 250.0,
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 50),
child: Text(
"Curved View",
style: TextStyle(
fontSize: 25,
color: Colors.white,
),
),
)),
),
),
),
);
}
}
class CurveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
int curveHeight = 40;
Offset controlPoint = Offset(size.width / 2, size.height + curveHeight);
Offset endPoint = Offset(size.width, size.height - curveHeight);
Path path = Path()
..lineTo(0, size.height - curveHeight)
..quadraticBezierTo(controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy)
..lineTo(size.width, 0)
..close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
一种方法是使用 CustomPainter
。
class SampleExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Scaffold(
backgroundColor: Colors.red,
body: Align(
alignment: Alignment.bottomCenter,
child: CustomPaint(
painter: MyCustomPainter(),
child: SizedBox(
width: double.infinity,
height: 250,
child: Center(child: Text('Cool!')),
),
),
),
);
}
}
class MyCustomPainter extends CustomPainter {
const MyCustomPainter();
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.white
..style = PaintingStyle.fill;
final path = Path()
..moveTo(0, 0)
..quadraticBezierTo(size.width / 2, size.height / 4, size.width, 0)
..lineTo(size.width, size.height)
..lineTo(0, size.height)
..close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
我比较熟悉 ClipPath
小部件,但是借助于此,我只能制作角圆或边框圆和圆。我知道这将由 ClipPath
或 CustomPainter
小部件修复。但不知道该怎么做。
预期图像:
实际结果:
代码:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleExample(),
);
}
}
class SampleExample extends StatelessWidget {
const SampleExample({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
body: Container(
alignment: Alignment.bottomCenter,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.elliptical(
MediaQuery.of(context).size.width, 120.0)),
),
),
),
);
}
}
通过使用 Stack 小部件,我实现了您想要的布局。
- 绘制白色背景
- 堆叠底部椭圆红色矩形小部件
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleExample(),
);
}
}
class SampleExample extends StatelessWidget {
const SampleExample({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.vertical(
bottom: Radius.elliptical(
MediaQuery.of(context).size.width, 120.0)),
),
),
],
),
);
}
}
在 decoration>borderRadius
上用 bottom
替换 top
并在正文 Container
.
alignment: Alignment.topCenter
而不是 bottomCenter
body: Container(
alignment: Alignment.topCenter,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Container(
height: 250.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
bottom: Radius.elliptical(
MediaQuery.of(context).size.width, 120.0)),
),
),
),
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ClipPath(
clipper: CurveClipper(),
child: Container(
color: Colors.lightGreen,
height: 250.0,
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 50),
child: Text(
"Curved View",
style: TextStyle(
fontSize: 25,
color: Colors.white,
),
),
)),
),
),
),
);
}
}
class CurveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
int curveHeight = 40;
Offset controlPoint = Offset(size.width / 2, size.height + curveHeight);
Offset endPoint = Offset(size.width, size.height - curveHeight);
Path path = Path()
..lineTo(0, size.height - curveHeight)
..quadraticBezierTo(controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy)
..lineTo(size.width, 0)
..close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
一种方法是使用 CustomPainter
。
class SampleExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Scaffold(
backgroundColor: Colors.red,
body: Align(
alignment: Alignment.bottomCenter,
child: CustomPaint(
painter: MyCustomPainter(),
child: SizedBox(
width: double.infinity,
height: 250,
child: Center(child: Text('Cool!')),
),
),
),
);
}
}
class MyCustomPainter extends CustomPainter {
const MyCustomPainter();
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.white
..style = PaintingStyle.fill;
final path = Path()
..moveTo(0, 0)
..quadraticBezierTo(size.width / 2, size.height / 4, size.width, 0)
..lineTo(size.width, size.height)
..lineTo(0, size.height)
..close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}