How to Give BorderRadius to SliverList
Asked Answered
U

11

16

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 :

enter image description here

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...

enter image description here

can suggest any other approach that i can take to achieve this kind of design...

Umbra answered 26/10, 2019 at 11:9 Comment(2)
Does NOT seem to be possible at the moment. I just posted an issue on GitHub: github.com/flutter/flutter/issues/62781 Have you been able to find any workaround in the meantime?Sofar
For work around I removed everything related to the slivers and added scroll controller for custom scrolling effect. Not smooth as slivers but works for now.Umbra
F
10

I achieved this design using SliverToBoxAdapter my code like this.

enter image description here

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.

  1. first I create a blue (should be Appbar color) container for the corner edge.
  2. then I create the same height white container with border-radius inside the blue container for list view.

Preview on dartpad

Filicide answered 18/4, 2020 at 17:46 Comment(3)
More description about that 2 Container can help me better.Umbra
@Umbra I add the exact code what I used, and I updated the explanation.Filicide
That wont work in case you have an image... it is working with because your color matches the app color, but if you have an image,, the image will be separated from the sliver list,, you need to have the image false behind the sliver list.Unemployed
S
7

Solution

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

Before:

enter image description here Here is your default code:


 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;
}

After

enter image description here

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);
  }
}

Sofar answered 4/8, 2020 at 17:11 Comment(1)
There is actually even a better answer since my code produces an error and therefore curbs down the frame rate. Check out the @Kherel's solution—it's perfect! You can also read more about the error and the better answer here: #63266229Sofar
A
5

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))
        ],
      ),
    );
  }
}
Accouchement answered 31/1, 2022 at 11:37 Comment(1)
In my case, I've added the second positioned container within my SliverPersistentHeader at bottom: 0. This solution works like a charm.Winifredwinikka
C
2

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),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
Caracaraballo answered 4/12, 2022 at 14:8 Comment(0)
B
1

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),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  )
                ],
              ),
            ),
          )
Baun answered 28/10, 2021 at 3:4 Comment(0)
N
0

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),
                          ),
                        ),
                      ),
                    )
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
Nila answered 22/12, 2021 at 7:2 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Zarathustra
N
0
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,
                      ),
                    ),
                  )
                ],
              ))

enter image description here

Nertie answered 13/7, 2022 at 13:38 Comment(0)
A
0

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

Accommodative answered 25/7, 2023 at 18:59 Comment(0)
K
0

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.

Khalid answered 8/9, 2023 at 16:43 Comment(0)
I
0
 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

Illbred answered 11/1 at 11:57 Comment(0)
T
-1

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

Thermy answered 16/5, 2020 at 3:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.