Добавьте радиус границы к фону SliverGrid во флаттере
Я создаю приложение с флаттером и застреваю при построении сетки элементов, используя 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,
),
),
],
),
);
Это изображение ниже - это то, что я получил с приведенным выше кодом. И теперь мне нужно добавить круговой border-radius к topLeft и topRight оранжевой части.
2 ответа
Вы можете добавить фигуру к slverAppBar
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);
}
Что я сделал, так это создал настраиваемый ShapeBorder на основе ContinuousRectangleBorder, но изменил getOuterPath и getInnerPath на постоянное значение, чтобы он выглядел так (это было для примера, если вам нужен настраиваемый класс, который можно использовать более чем в одной ситуации, возможно, изменение некоторые другие значения в конструкторе).
Я все еще использовал в SliverAppBar, потому что это виджет, который позволяет мне изменять форму с помощью атрибута shape, но с помощью getOuterPath я нарисовал кривые, идущие от максимальной высоты виджета до maxHeight - 16 (просто случайное число, которое я придумал, это похоже на предыдущий пример, когда я добавил BorderRadius.vertical(bottom: Radius.circular(16))
). Если у вас не было Sliver AppBar, а вместо него AppBar в Scaffold, вы могли бы просто обернуть CustomScrollView в Card без полей и в форме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
импортируйте его в свой проект и используйте новый класс SliverGroupBuilder() внутри CustomScrollView, это в основном Контейнер, превращенный в 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,
),
),
)
],
),
)
Фон Scaffold розовый, а SliverGroupBuilder оранжевый с BorderRadius.vertical(top: Radius.circular(16))
,
Закрытый SliverAppBar
Этот подход дает вам то, что вы хотите, но вы должны быть осторожны с цветом фона лесов, чтобы сделать его другим, чтобы вы могли видеть радиус границы.
проверьте https://pub.dev/packages/flutter_group_sliver для получения дополнительной информации о пакете
Это мой подход
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,
),
),
),
),
],
),
),
),
)
)