Как передать BorderRadius в SliverList

Я использую SliverAppBar и SliverListView в своем проекте.

Мне нужно BorderRadius для моего SliverList, который приближается к моему SliverAppBar.

Вот что мне нужно:

введите описание изображения здесь

А вот мой код:

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

Итак, с этим кодом пользовательский интерфейс выглядит так ...

введите описание изображения здесь

могу предложить любой другой подход, который я могу использовать для достижения такого дизайна ...


person black-hacker    schedule 26.10.2019    source источник
comment
На данный момент это НЕ представляется возможным. Я только что разместил на GitHub проблему: github.com/flutter/flutter/issues/62781 Удалось ли вам пока найти какое-либо решение?   -  person Tomas Baran    schedule 03.08.2020
comment
Чтобы обойти эту проблему, я удалил все, что связано с полосами, и добавил контроллер прокрутки для настраиваемого эффекта прокрутки. Не гладкая, как щепки, но пока работает.   -  person black-hacker    schedule 04.08.2020


Ответы (3)


Я достиг этого дизайна, используя SliverToBoxAdapter свой код, подобный этому.

введите описание изображения здесь

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

Я использовал 2 контейнера внутри SliverToBoxAdapter.

SliverToBoxAdapter находится между панелью приложений Sliver и списком Sliver List.

  1. Сначала я создаю синий (должен быть цвета панели приложений) контейнер для углового края.
  2. затем я создаю белый контейнер той же высоты с радиусом границы внутри синего контейнера для просмотра списка.

Предварительный просмотр на дартпаде

person yathavan    schedule 18.04.2020
comment
Более подробное описание этого контейнера 2 может помочь мне лучше. - person black-hacker; 13.05.2020
comment
@ black-hacker Я добавил точный код, который использовал, и обновил объяснение. - person yathavan; 15.05.2020
comment
Это не сработает, если у вас есть изображение ... оно работает, потому что ваш цвет соответствует цвету приложения, но если у вас есть изображение, изображение будет отделено от списка лент, вам нужно, чтобы изображение было ложным за списком ленты. - person Mo Bdair; 08.06.2020

Решение

На момент написания не было виджета, который поддерживал бы эту функцию. Это можно сделать с помощью Stack виджета и вашего собственного 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;
}

После

введите описание изображения здесь

А вот ваш код с виджетами Stack и SliveWidget:

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

person Tomas Baran    schedule 04.08.2020
comment
На самом деле есть даже лучший ответ, поскольку мой код выдает ошибку и, следовательно, снижает частоту кадров. Ознакомьтесь с решением @Kherel - оно идеально! Вы также можете узнать больше об ошибке и лучший ответ здесь: stackoverflow.com/questions/63265729/ - person Tomas Baran; 14.08.2020

Идея хороша, но в некоторых случаях выглядит странно.

Вы можете поставить borderRadius своему первому элементу в вашем списке

Container(
  decoration: BoxDecoration(
    borderRadius: BorderRadius.only(
      topRight: Radius.circular(index == 0 ? 15 : 0),
      topLeft: Radius.circular(index == 0 ? 15 : 0),
    ),
  ),
)

Надеюсь, это кому-то поможет

person Jerin    schedule 16.05.2020