How to Give BorderRadius to SliverList

3,870

Solution 1

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

Solution 2

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

Solution 3

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),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  )
                ],
              ),
            ),
          )

Solution 4

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))
        ],
      ),
    );
  }
}
Share:
3,870
black-hacker
Author by

black-hacker

Updated on December 15, 2022

Comments

  • black-hacker
    black-hacker over 1 year

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

  • black-hacker
    black-hacker almost 4 years
    More description about that 2 Container can help me better.
  • yathavan
    yathavan almost 4 years
    @black-hacker I add the exact code what I used, and I updated the explanation.
  • Mo Bdair
    Mo Bdair almost 4 years
    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.
  • Tomas Baran
    Tomas Baran over 3 years
    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: stackoverflow.com/questions/63265729/…
  • Admin
    Admin over 2 years
    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.