Reputation: 293
I am using SliverAppBar
and SliverListView
in my project.
I need BorderRadius
to my SliverList
that is coming bottom of my SliverAppBar
.
Here is screenshot what I need :
And here is my code:
Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
backgroundColor: Colors.transparent,
brightness: Brightness.dark,
actions: <Widget>[
IconButton(icon: Icon(Icons.favorite), onPressed: () {}),
IconButton(icon: Icon(Icons.share), onPressed: () {})
],
floating: false,
pinned: false,
//title: Text("Flexible space title"),
expandedHeight: getHeight(context) - MediaQuery.of(context).padding.top,
flexibleSpace: Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage("assets/images/Rectangle-image.png")
)
),
),
bottom: _bottomWidget(context),
),
SliverList(
delegate: SliverChildListDelegate(listview),
),
],
),
)
So, with this code the UI is coming like this...
can suggest any other approach that i can take to achieve this kind of design...
Upvotes: 16
Views: 11453
Reputation: 136
I've been struggling for some time to achieve it; I know it is too late, but to help those who will come.
Here is the following approach I made, and it worked like a charm. Using Positioned widget to achieve it.
background: Stack(
fit: StackFit.expand,
children: [
CustomNetworkImage(imageUrl: "https://static.mubasher.info/File.Story_Image/edaffba12626fb56d0144d9a3087ffb6/1024.jpg"),
Positioned(
bottom: 0,
right: 0,
left: 0,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topLeft: const Radius.circular(20.0), topRight: const Radius.circular(20.0))),
child: const SizedBox(height: 20),
),
),
],
),
Upvotes: 0
Reputation: 2678
return Scaffold(
backgroundColor: ColorName.primary,
body: NestedScrollView(headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
backgroundColor: ColorName.primary,
centerTitle: true,
pinned: true,
floating: true,
expandedHeight: 150.0,
flexibleSpace: FlexibleSpaceBar(
title: Text("TITLE"),
),
)
];
},
body: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorName.black
),
height: 300,[![enter image description here][1]][1]width: double.infinity,),
),
);
check this code [1]: https://i.sstatic.net/MrfH3.png
Upvotes: 0
Reputation: 1
You can try this.
SliverAppBar(
backgroundColor: Colors.blue,
pinned: true,
expandedHeight: 200,
flexibleSpace: const FlexibleSpaceBar(
title: Text("Sliver Animated List"),
collapseMode: CollapseMode.pin,
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(30.0),
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
color: Colors.white,
),
child: const Center(
child: Text(
"Preferred Size Widget",
style: TextStyle(color: Colors.blue),
),
),
),
),
),
by doing this you can achieve the desire design that you want.
Upvotes: 0
Reputation: 66
Apparently they will add a "DecoratedSliver" so that you can use decorations in slivers, I imagine this will attend the question posted here. The conversation went a long way (to the point it was accepted and reverted in Flutter 3.7 - 3.7 Release Notes, search "SliverDecoration") and is yet to be published I assume in the next Flutter update.
As of now, Flutter 3.10 was released in May 10th 2023 while the commit in question was approved on June 20th 2023. Check the change history here: https://github.com/flutter/flutter/pull/127823
Upvotes: 0
Reputation: 116
So the best way to achieve your result is to use "bottom" poperty inside SliverAppBar. This will add your rounded container to bottom of appbar / start of sliverlist
bottom: PreferredSize(
preferredSize: const Size.fromHeight(24),
child: Container(
width: double.infinity,
decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12),
),
color: Colors.white,
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(2),
),
),
),
],
),
),
),
Upvotes: 2
Reputation: 520
FlexibleSpaceBar(
title: CustomText(
text: "Renaissance Concourse Hotel",
textSize: kSubtitle3FontSize,
fontWeight: kBold),
centerTitle: true,
collapseMode: CollapseMode.pin,
background: Stack(
children: [
CachedNetworkImage(
imageUrl:
"url",
width: DeviceUtils.getWidth(context),
fit: BoxFit.cover,
placeholder: (context, url) => const Center(
child: CircularProgressIndicator(),
),
errorWidget: (context, url, error) =>
const Icon(Icons.error_rounded),
),
Positioned(
bottom: 50,
right: 0,
left: 0,
child: ContainerPlus(
color: kWhiteColor,
child: const SizedBox(
height: 20,
),
radius: RadiusPlus.only(
topLeft: kBorderRadiusValue10,
topRight: kBorderRadiusValue10,
),
),
)
],
))
Upvotes: 0
Reputation: 129
Use Stack. It's the best and smooth way I found and used. Preview
import 'dart:math';
import 'package:agro_prep/views/structure/constant.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class CropDetailsPage extends StatelessWidget {
const CropDetailsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: Colors.white,
actions: <Widget>[
IconButton(icon: Icon(Icons.share), onPressed: () {})
],
floating: false,
pinned: false,
//title: Text("Flexible space title"),
expandedHeight: 281.h,
flexibleSpace: Stack(
children: [
const Positioned.fill(
child: FadeInImage(
image: NetworkImage(tempImage),
placeholder: const NetworkImage(tempImage),
// imageErrorBuilder: (context, error, stackTrace) {
// return Image.asset('assets/images/background.jpg',
// fit: BoxFit.cover);
// },
fit: BoxFit.cover,
),
),
Positioned(
child: Container(
height: 33.h,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(40),
),
),
),
bottom: -7,
left: 0,
right: 0,
)
],
),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return ListTile(
tileColor: whiteColor,
title: Text(Random().nextInt(100).toString()),
);
}, childCount: 15))
],
),
);
}
}
Upvotes: 7
Reputation: 13
Try This, It's a Simple Solution
import 'package:flutter/material.dart';
class SliveR extends StatelessWidget {
const SliveR({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
SizedBox(
width: double.infinity,
child: Image.network(
'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2700&q=80',
fit: BoxFit.cover,
height: MediaQuery.of(context).size.height * 0.35,
),
),
Align(
alignment: Alignment.topCenter,
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30)),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(30)),
child: CustomScrollView(
anchor: 0.3,
slivers: [
SliverToBoxAdapter(
child: Container(
height: 900,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(40.0),
topRight: Radius.circular(40.0),
),
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 16.0,
),
],
),
child: const Center(
child: Text(
'Hello',
style: TextStyle(color: Colors.grey),
),
),
),
)
],
),
),
),
),
],
),
);
}
}
Upvotes: 0
Reputation: 396
Worked for me!
SliverAppBar(
pinned: true,
floating: false,
centerTitle: true,
title: TextWidget(detail.title,
weight: FontWeight.bold
),
expandedHeight: MediaQuery.of(context).size.height/2.5,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
collapseMode: CollapseMode.parallax,
background: Stack(
children: [
// Carousel images
Swiper(
itemWidth: MediaQuery.of(context).size.width,
itemHeight: MediaQuery.of(context).size.height /3.5,
itemCount: 2,
pagination: SwiperPagination.dots,
loop: detail.banners.length > 1,
itemBuilder: (BuildContext context, int index) {
return Image.network(
'https://image.com?image=123.png',
fit: BoxFit.cover
);
}
),
//Border radius
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.transparent,
height: 20,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
height: 10,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(10),
topRight: const Radius.circular(10),
),
),
),
],
),
),
)
],
),
),
)
Upvotes: 2
Reputation: 1983
At the time of writing, there is no widget that would support this functionality. The way to do it is with Stack
widget and with your own SliveWidget
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flexible space title',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
backgroundColor: Colors.transparent,
brightness: Brightness.dark,
actions: <Widget>[IconButton(icon: Icon(Icons.favorite), onPressed: () {}), IconButton(icon: Icon(Icons.share), onPressed: () {})],
floating: false,
pinned: false,
expandedHeight: 250 - MediaQuery.of(context).padding.top,
flexibleSpace: Container(
height: 550,
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://images.unsplash.com/photo-1561752888-21eb3b67eb4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=967&q=80'))),
),
//bottom: _bottomWidget(context),
),
SliverList(
delegate: SliverChildListDelegate(_listview(50)),
),
],
),
),
);
}
}
List _listview(int count) {
List<Widget> listItems = List();
listItems.add(Container(
color: Colors.black,
height: 50,
child: TabBar(
tabs: [FlutterLogo(), FlutterLogo()],
),
));
for (int i = 0; i < count; i++) {
listItems.add(new Padding(padding: new EdgeInsets.all(20.0), child: new Text('Item ${i.toString()}', style: new TextStyle(fontSize: 25.0))));
}
return listItems;
}
And here is your code done with Stack
and SliveWidget
widgets:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flexible space title',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
body: Stack(
children: [
Container(
height: 550,
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://images.unsplash.com/photo-1561752888-21eb3b67eb4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=967&q=80'))),
),
CustomScrollView(
anchor: 0.4,
slivers: <Widget>[
SliverWidget(
child: Container(
width: double.infinity,
height: 100,
decoration: BoxDecoration(
color: Colors.yellow, borderRadius: BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30))),
child: TabBar(
tabs: [FlutterLogo(), FlutterLogo()],
),
),
),
SliverList(
delegate: SliverChildListDelegate(_listview(50)),
),
],
),
],
),
),
);
}
}
List _listview(int count) {
List<Widget> listItems = List();
for (int i = 0; i < count; i++) {
listItems.add(
Container( //NOTE: workaround to prevent antialiasing according to: https://github.com/flutter/flutter/issues/25009
decoration: BoxDecoration(
color: Colors.white, //the color of the main container
border: Border.all(
//apply border to only that side where the line is appearing i.e. top | bottom | right | left.
width: 2.0, //depends on the width of the unintended line
color: Colors.white)),
child: Container(
padding: EdgeInsets.all(20),
color: Colors.white,
child: new Text(
'Item ${i.toString()}',
style: new TextStyle(fontSize: 25.0),
),
),
),
);
}
return listItems;
}
class SliverWidget extends SingleChildRenderObjectWidget {
SliverWidget({Widget child, Key key}) : super(child: child, key: key);
@override
RenderObject createRenderObject(BuildContext context) {
// TODO: implement createRenderObject
return RenderSliverWidget();
}
}
class RenderSliverWidget extends RenderSliverToBoxAdapter {
RenderSliverWidget({
RenderBox child,
}) : super(child: child);
@override
void performResize() {}
@override
void performLayout() {
if (child == null) {
geometry = SliverGeometry.zero;
return;
}
final SliverConstraints constraints = this.constraints;
child.layout(constraints.asBoxConstraints(/* crossAxisExtent: double.infinity */), parentUsesSize: true);
double childExtent;
switch (constraints.axis) {
case Axis.horizontal:
childExtent = child.size.width;
break;
case Axis.vertical:
childExtent = child.size.height;
break;
}
assert(childExtent != null);
final double paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: childExtent);
final double cacheExtent = calculateCacheOffset(constraints, from: 0.0, to: childExtent);
assert(paintedChildSize.isFinite);
assert(paintedChildSize >= 0.0);
geometry = SliverGeometry(
scrollExtent: childExtent,
paintExtent: 100,
paintOrigin: constraints.scrollOffset,
cacheExtent: cacheExtent,
maxPaintExtent: childExtent,
hitTestExtent: paintedChildSize,
);
setChildParentData(child, constraints, geometry);
}
}
Upvotes: 7
Reputation: 2376
I achieved this design using SliverToBoxAdapter
my code like this.
final sliver = CustomScrollView(
slivers: <Widget>[
SliverAppBar(),
SliverToBoxAdapter(
child: Container(
color: Color(0xff5c63f1),
height: 20,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
height: 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0),
),
),
),
],
),
),
),
SliverList(),
],
);
I used 2 containers inside SliverToBoxAdapter.
SliverToBoxAdapter is between the Sliver Appbar and the Sliver List.
Upvotes: 10
Reputation: 801
The idea is good but it looks odd in some cases.
You could give a borderRadius
to your first element in your list
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(index == 0 ? 15 : 0),
topLeft: Radius.circular(index == 0 ? 15 : 0),
),
),
)
Hope this helps someone
Upvotes: -1