我正在使用抖动构建应用程序,并且在SliverGrid
内使用CustomScrollView
构建项目网格时陷入困境,并且无法在其背景中添加边框半径。注意,我可以为单个网格项添加半径。
这是我尝试过的
Scaffold(
backgroundColor: Colors.orange,
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
floating: true,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
background: Image.asset(
'assets/images/000.png',
fit: BoxFit.cover,
),
title: Text('Hello there')),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 30,
),
),
],
),
);
下面的图片是我上面的代码所得到的。 现在我需要在橙色部分的topLeft和topRight中添加一个圆形边框半径。
答案 0 :(得分:2)
您可以将形状添加到sliverAppBar
return Scaffold(
backgroundColor: Colors.orange,
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
floating: true,
expandedHeight: 250.0,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(16))), //like this
flexibleSpace: FlexibleSpaceBar(
background: Container(color: Colors.blueAccent), //changed it because I dont have the image asset
title: Text('Hello there')),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 100,
),
),
],
),
);
}
如果您希望以其他方式使用它,则可能应该创建一个自定义ShapeBorder并覆盖getOuterPath以获取形状之外的内容,并使其看起来像橙色的一面是该形状。让我知道您是否想要尝试更新答案的方式
更新
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.orange,
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
floating: true,
expandedHeight: 250.0,
shape: _CustomShape(), //like this
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&h=350",
fit: BoxFit.cover,
),
title: Text('Hello there'),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 100,
),
),
],
),
);
}
}
class _CustomShape extends ShapeBorder {
const _CustomShape({
this.side = BorderSide.none,
this.borderRadius = BorderRadius.zero,
}) : assert(side != null),
assert(borderRadius != null);
final BorderRadiusGeometry borderRadius;
/// The style of this border.
final BorderSide side;
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width);
@override
ShapeBorder scale(double t) {
return _CustomShape(
side: side.scale(t),
borderRadius: borderRadius * t,
);
}
@override
ShapeBorder lerpFrom(ShapeBorder a, double t) {
assert(t != null);
if (a is ContinuousRectangleBorder) {
return ContinuousRectangleBorder(
side: BorderSide.lerp(a.side, side, t),
borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, borderRadius, t),
);
}
return super.lerpFrom(a, t);
}
@override
ShapeBorder lerpTo(ShapeBorder b, double t) {
assert(t != null);
if (b is ContinuousRectangleBorder) {
return ContinuousRectangleBorder(
side: BorderSide.lerp(side, b.side, t),
borderRadius: BorderRadiusGeometry.lerp(borderRadius, b.borderRadius, t),
);
}
return super.lerpTo(b, t);
}
@override
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
double length = 16;
return Path()
..lineTo(0, rect.height - length)
..lineTo(rect.width, rect.height - length)
..lineTo(rect.width, 0)
..close();
}
@override
Path getOuterPath(rect, {TextDirection textDirection}) {
double length = 16; //its just a random number I came up with to test the border
return Path()
..lineTo(0, rect.height)
..quadraticBezierTo(length / 4, rect.height - length, length, rect.height - length)
..lineTo(rect.width - length, rect.height - length)
..quadraticBezierTo(rect.width - (length / 4), rect.height - length, rect.width, rect.height)
..lineTo(rect.width, 0)
..close();
}
@override
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) {
if (rect.isEmpty)
return;
switch (side.style) {
case BorderStyle.none:
break;
case BorderStyle.solid:
final Path path = getOuterPath(rect, textDirection: textDirection);
final Paint paint = side.toPaint();
canvas.drawPath(path, paint);
break;
}
}
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
return false;
return other is ContinuousRectangleBorder
&& other.side == side
&& other.borderRadius == borderRadius;
}
@override
int get hashCode => hashValues(side, borderRadius);
}
我所做的是创建一个基于ContinuousRectangleBorder的自定义ShapeBorder,但将getOuterPath和getInnerPath更改为一个常量值使其看起来像这样(这是示例,如果您想要一个可以在多个应用程序中使用的自定义类,情况可能会在构造函数中更改其他一些值。
我仍然在SliverAppBar中使用,因为那是允许我使用shape属性更改形状的小部件,但是使用getOuterPath,我绘制了从小部件的最大高度到maxHeight-16(只是一个随机数)的曲线我上来了,就像添加BorderRadius.vertical(bottom: Radius.circular(16))
时的前一个例子一样。如果您没有Sliver AppBar,而是在脚手架中有AppBar,则可以将CustomScrollView包裹在无边距且形状为RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)))
的卡片中
包装更新
将flutter_group_sliver: ^0.0.2
添加到您的pubspec.yaml依赖项
dependencies:
flutter:
sdk: flutter
flutter_group_sliver: ^0.0.2
将其导入项目并在CustomScrollView中使用新的SliverGroupBuilder()类,它基本上是制成Sliver的容器,因此您可以在Sliver中使用边距,装饰,填充选项
import 'package:flutter_group_sliver/flutter_group_sliver.dart';
Scaffold(
backgroundColor: Colors.pink[100],
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
floating: true,
expandedHeight: 250.0,
elevation: 0.0,
forceElevated: false,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://happypixelmedia.com/wp-content/uploads/2019/10/Web-design-ideas-to-look-forward-to-in-2020-cover-1.jpg",
fit: BoxFit.cover,
),
title: Text('Hello there'),
),
),
SliverGroupBuilder(
margin: EdgeInsets.zero,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 100,
),
),
)
],
),
)
支架背景为粉红色,而SliverGroupBuilder为橙色,带有BorderRadius.vertical(top: Radius.circular(16))
,
关闭SliverAppBar
这种方法可以为您提供所需的内容,但是您必须注意脚手架背景的颜色以使其与众不同,以便您可以看到边框半径
检查https://pub.dev/packages/flutter_group_sliver#-readme-tab-以获得该软件包的更多信息
答案 1 :(得分:0)
这是我的方法
SliverAppBar(
elevation: 0,//remove elevetion
backgroundColor: Colors.white, // match the color of sliver grid/list
leading: SizedBox(), // // hide arrow icon
leadingWidth: 0.0, // hide arrow icon
expandedHeight: 200,
stretch: true,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin, // to make radius remain if scrolled
title: _myTitle,
titlePadding: EdgeInsets.all(30),
centerTitle: true,
stretchModes: [
StretchMode.zoomBackground, // zoom effect
StretchMode.fadeTitle, // fade effect
],
background: Container(
color: Colors.white,
child: Stack(
fit: StackFit.expand, // expand stack
children: [
ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.5),
BlendMode.srcOver,
),
child: Container(
child: Image.network(
"$imageLink",
fit: BoxFit.cover,
),
),
),
Positioned(
child: Container(
height: 30,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(50),
),
border: Border.all(
color: Colors.white,
width: 0,
)),
),
bottom: -1,
left: 0,
right: 0,
),
Positioned(
bottom: 0, // to bottom
right: 45, // to right 45
child: ClipRRect(
borderRadius: BorderRadius.circular(120),
child: Container(
color: darkBlue,
width: 60,
height: 60,
child: Icon(
LineIcons.store,
size: 26,
color: Colors.white,
),
),
),
),
],
),
),
),
)
)