问题
I want to make an appbar with a rounded bottom, like so:
How would I go about implementing such an appbar? I have tried reading up on the documentation for CustomPainter, but I don't feel like that is the way to go.
回答1:
In Flutter you can have custom shape in AppBar widget with shape property.
AppBar(
title: Text('My App'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(30),
),
),
),
回答2:
You can use BoxDecoration
to add border-radius and shadow to a Container
/DecoratedBox
.
new Container(
height: 200.0,
decoration: new BoxDecoration(
color: Colors.orange,
boxShadow: [
new BoxShadow(blurRadius: 40.0)
],
borderRadius: new BorderRadius.vertical(
bottom: new Radius.elliptical(
MediaQuery.of(context).size.width, 100.0)),
),
),
Although you may notice : That's not pixel perfect. The border is not an actual circle, but an ellipsis. Which may be undesired.
A more realistic, but more complex approach, is to draw a circle with a radius based on the width of your screen. Which will overflow the container. And then clip it.
You'll need a few things : LayoutBuilder
, to get the width. ClipRect
to not paint outside the container's constraints. And OverflowBox
, to layout a circle that is larger than it's parent.
class RoundedAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return new SizedBox.fromSize(
size: preferredSize,
child: new LayoutBuilder(builder: (context, constraint) {
final width = constraint.maxWidth * 8;
return new ClipRect(
child: new OverflowBox(
maxHeight: double.infinity,
maxWidth: double.infinity,
child: new SizedBox(
width: width,
height: width,
child: new Padding(
padding: new EdgeInsets.only(
bottom: width / 2 - preferredSize.height / 2),
child: new DecoratedBox(
decoration: new BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
boxShadow: [
new BoxShadow(color: Colors.black54, blurRadius: 10.0)
],
),
),
),
),
),
);
}),
);
}
@override
Size get preferredSize => const Size.fromHeight(200.0);
}
Centered on purpose, just to show how clip works
回答3:
There is one simple way to achieve this using ClipPath -
Apply background color to AppBar
Create A SizedBox/Container of some height (say 240) right below AppBar in body and apply same background color
Use ClipPath widget to wrap that SizedBox/Container
ClipPath( clipper: CustomShape(), // this is my own class which extendsCustomClipper child: Container( height: 150, color: kPrimaryColor, ), ),
Now create a class like CustomShape which extends CustomClipper like below
class CustomShape extends CustomClipper<Path> {
@override
getClip(Size size) {
double height = size.height;
double width = size.width;
var path = Path();
path.lineTo(0, height - 50);
path.quadraticBezierTo(width / 2, height, width, height - 50);
path.lineTo(width, 0);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper oldClipper) {
return true;
}
}
Change your heights fraction, I kept heights-50 for a nice curve you want
The output is like below -
回答4:
Your above helped me a lot, I am just struggling with one thing, and that is to make the rounded bar a lot smaller in its height.
I change the height in this line
Size get preferredSize => const Size.fromHeight(200.0);
but it doesn't affect it enough, i even set it down to 0 and still the bar is to high.
来源:https://stackoverflow.com/questions/50242087/rounded-bottom-on-appbar