Flutter ListView.Builder () в прокручиваемом столбце с другими виджетами

У меня есть TabBarView () с множеством разных представлений. Я хочу, чтобы они были столбцом с TextField вверху и ListView.Builder () внизу, но оба виджета должны находиться в одной и той же прокручиваемой области (scrollview). То, как я это реализовал, вызывало некоторые ошибки:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder)
    ],
   );
}

Ошибка:

I/flutter (23520): The following assertion was thrown during performResize():
I/flutter (23520): Vertical viewport was given unbounded height.
I/flutter (23520): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (23520): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (23520): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (23520): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (23520): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (23520): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (23520): the height of the viewport to the sum of the heights of its children.

Я читал о размещении ListView.builder () в расширенной области, но это сделало текстовое поле «липким», чего я не хочу. :-)

Я также наткнулся на CustomScrollView, но не совсем понимал, как его реализовать.

Оберните ListView расширенным виджетом

Vinoth Kumar 11.06.2018 16:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
67
1
63 652
15

Ответы 15

Column не прокручивается, поэтому TextField вверху не прокручивается, а ListView внизу -.

На мой взгляд, лучший способ решить эту проблему - сделать ваш TextField первым элементом в вашем ListView.

Таким образом, столбец вам не понадобится, ваш родительский виджет - это ListView, а его дочерние элементы - это TextField, за которыми следуют остальные элементы, которые вы создаете с помощью _postBuilder.

Размещение ListView внутри виджета Expanded должно решить вашу проблему:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new Expanded(child: ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder))
    ],
   );
}

Насколько я понял, Expanded и ListView работают вместе, потому что расширенный использует остальную часть экрана. Итак, если вам нужна кнопка под расширенным, у вас сначала есть текстовое поле с заполнением, затем расширенное (с возможностью прокрутки), а затем кнопка в нижней части экрана.

NullPointer 28.04.2020 14:27

Если у вас возникли проблемы с этим решением, проверьте, находится ли столбец внутри Positioned. Если это так, вам нужно указать верх и низ. Так дротик может рассчитать размер. Если указать только верхнюю часть, для расчета не хватит данных.

Thiago Silva 15.12.2020 00:46

Лучше всего сделать столбец прокручиваемым, сделав столбец дочерним элементом SingleChildScrollView, а затем назначив один и тот же ScrollController как для SingleChildScrollView, так и для ListView.builder. Это сделает текстовое поле и расположенный ниже ListView прокручиваемым.

Причина ошибки:

Column расширяется до максимального размера в направлении главной оси (вертикальной оси), как и ListView.

Решение

Вам необходимо ограничить высоту ListView, чтобы он расширялся, чтобы соответствовать Column. Есть несколько способов решения этой проблемы, я перечисляю некоторые из них:


  1. Если вы хотите, чтобы ListView занимал все оставшееся пространство внутри Column, используйте Flexible.

    Column(
      children: <Widget>[
        Flexible(
          child: ListView(...),
        )
      ],
    )
    

  1. Если вы хотите ограничить свой ListView определенным height, вы можете использовать SizedBox.

    Column(
      children: <Widget>[
        SizedBox(
          height: 200, // constrain height
          child: ListView(),
        )
      ],
    )
    

  1. Если ваш ListView маленький, вы можете попробовать на нем свойство shrinkWrap.

    Column(
      children: <Widget>[
        ListView(
          shrinkWrap: true, // use it
        )
      ],
    )
    

Номер 3 спас мою проблему. Спасибо, отличный ответ!

victommasi 23.11.2019 16:42

Я получаю Incorrect use of ParentDataWidget. с помощью метода 1

Piyush Chauhan 08.05.2020 01:05

@PiyushChauhan Вы могли пропустить включение Column. Если это не так, задайте отдельный вопрос, и я буду рад вам помочь.

CopsOnRoad 08.05.2020 02:35

У меня не было гибкого виджета вокруг моего Listview - только расширенный виджет вокруг части столбца, потомком которого он был. Это мне очень помогло, спасибо!

Tristan Bennett 03.06.2020 00:41

Вот решение:

SingleChildScrollView(
        physics: ScrollPhysics(),
        child: Column(
          children: <Widget>[
             Text('Hey'),
             ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemCount:18,
                itemBuilder: (context,index){
                  return  Text('Some text');
                })
          ],
        ),
      ),

Боже мой, ты лучший. Я искал это решение 1 месяц

N Sivaram 18.06.2020 16:52

у меня это не сработало, мне нужно было добавить атрибут для columnMainAxisSize.min, чтобы он работал.

Pedro Molina 08.07.2020 11:38

Хотел бы я проголосовать за это 100 раз ... Наконец-то это заработало.

rohan koshti 04.08.2020 05:59

Приемлемый ответ :)

Al Mamun 16.09.2020 06:48

@PedroMolina Вы добавили shrinkWrap: true в свой ListView, потому что он работает без него. Однако благодаря @SunpreetSingh

Abhishek Kumar 08.10.2020 22:13

«Физика: NeverScrollableScrollPhysics ()» спасла меня. Спасибо!

Karsten Silz 16.11.2020 19:46

Спасибо тебе большое, братан

Qutbuddin Bohra 08.12.2020 15:10

Ты спас мне день. Мне всегда было интересно, почему NeverScrollableScrollPhysics () вообще существует. Теперь я знаю почему: D

Ferda Nahit FIDANCI 10.02.2021 06:01

@ Санприт Сингх, ты легенда!

edn 09.04.2021 16:12

сэкономил мне столько часов !! "физика: NeverScrollableScrollPhysics ()"

Aashwiin Roghan 14.06.2021 07:31

Используйте виджет Расширенный, чтобы ограничить, не переполняя эти пиксели, :)

Column(
  children: <Widget>[
    Expanded(
      child: ListView(),
    ),
    Expanded(
      child: ListView(),
    ),
  ],
)

Просто добавьте физика: NeverScrollableScrollPhysics () в ListView.builder (), чтобы можно было прокручивать

Пожалуйста, включите больше контекста в ответы

hardillb 29.01.2020 15:08

Добавьте physics: NeverScrollableScrollPhysics() в метод Listview.builder(), и вложенный Listview будет прокручиваться

Решение

SingleChildScrollView(
          child: Column(
            children: <Widget>[
                      ListView.builder(
                      shrinkWrap: true,
                      physics: NeverScrollableScrollPhysics(),

Здесь используются два свойства

shrinkWrap: true

занимает только необходимое пространство (он все равно будет прокручиваться, когда будет больше элементов).

physics: NeverScrollableScrollPhysics()

Физика прокрутки, которая не позволяет пользователю прокручивать. Имеется ввиду только работа Column + SingleChildScrollView Scrolling.

Это решение неэффективно, потому что в представлении списка все элементы будут немедленно построены, что устранит выигрыш в производительности.

jinyus 16.12.2020 07:34

@kemist: Какое тогда будет идеальное решение?

Jitesh Mohite 16.12.2020 14:34

@ jitsm555 Вы хотите использовать CustomScrollView с SliverList и SliverChildBuilderDelegate.

jinyus 17.12.2020 12:43

@ jitsm555 проверьте мое решение: stackoverflow.com/a/65340391/9695723

jinyus 17.12.2020 13:04

спасибо, чувак, действительно круто

mohamed elyamani 03.01.2021 14:36

В моем случае с будущим я сделал это так:

SingleChildScrollView(
      physics: ScrollPhysics(),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text("Hey ho let's go!"),
          
          Flexible(
            child: FutureBuilder(
              future: getData(),
              builder: (BuildContext context,
                  AsyncSnapshot<List<Sale>> snapshot) {
                

                if (snapshot.connectionState != ConnectionState.done ||
                    snapshot.hasData == null) {
                  
                    return CircularProgressIndicator();

                } else {
                  data = snapshot.data;
                  return ListView.builder(
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemBuilder: (BuildContext context, int index) {
                        return dataItemWidget(size, data[index], context);
                      },
                      itemCount: data.length,
                    );
                }
              },
            ),
          ),
        ],
      ),
    ),

Используйте физика: NeverScrollableScrollPhysics () и shrinkWrap: true внутри ListView.Builder () и наслаждайтесь

Вот эффективное решение:

class NestedListExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        const SliverToBoxAdapter(
          child: Text('Header'),
        ),
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (ctx, index) {
              return ListTile(title:Text('Item $index'));
            },
          ),
        ),
      ],
    );
  }
}

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

Вы можете использовать SliverToBoxAdapter для других дочерних элементов, поскольку только Slivers могут быть прямыми дочерними элементами CustomScrollView.

Если все элементы списка имеют одинаковую высоту, вы можете использовать SliverFixedExtentList, что более эффективно, потому что высота каждого дочернего элемента не рассчитывается на лету, но вам нужно будет знать точную высоту в пикселях. Вы также можете использовать SliverPrototypeExtentList, где вы указываете первый элемент в списке (прототип), а все остальные дочерние элементы будут использовать высоту прототипа, поэтому вам не нужно знать точную высоту в пикселях.

это абсолютно лучшее решение для любого списка приличного размера

john mason 01.06.2021 19:17
//If you want Listview.builder inside ListView and want to scroll the parent ListView// //whenever the Items in ListView.builder ends or start you can do it like this
       body: ListView(
                  physics: ScrollPhysics(),
                  children: [
                    SizedBox(height: 20),
                    Container( height: 110.0 *5, // *5 to give size to the container //according to items in the ListView.builder. Otherwise will give hasSize Error
                    child:ListView.builder(
                       physics: NeverScrollableScrollPhysics(),
                       scrollDirection: Axis.vertical,
                       itemCount: 5,
                        itemBuilder: (BuildContext context, int indexChild) {
                         return InkWell(child:Container(height:100));}))                
                    ),]),
  1. столбец возврата ( дети: [ Текст («Популярная категория»), Расширенный ( дочерний: ListView.builder (enter code here shrinkWrap: false, scrollDirection: Axis.horizontal, itemCount: 3, itemBuilder: (контекст, индекс) { return Row ( crossAxisAlignment: CrossAxisAlignment.start, дети: [ Текст («привет»), ], ); }),) ],);

просто добавь

Column(
mainAxisSize: MainAxisSize.max, //Add this line onyour column
children:[
    SomeWidget(),
    Expanded(child:ListView.builder())
  ]
)

Другие вопросы по теме