Как создать горизонтально прокручиваемую таблицу с фиксированным столбцом во флаттере? - PullRequest
0 голосов
/ 08 июля 2019

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

В каждой таблице я бы хотел, чтобы крайний левый столбец был зафиксирован на месте, а оставшиеся столбцы в этой таблице можно было прокручивать по горизонтали, если есть ряд столбцов, которые не помещаются по ширине экрана. Смотреть скриншот:

example

Мой первоначальный план состоял в том, чтобы использовать ListView для вертикальной прокрутки на уровне страницы между таблицами, и внутри каждой таблицы есть ряд столбцов, где первый столбец является статической шириной, а остальные столбцы заключены в горизонтальная прокрутка ListView. Ошибка, которую я получаю от Flutter, не помогает мне определить, что мне нужно делать, но она явно связана с необходимостью устанавливать границы для дочерних виджетов.

Ошибка: (исправлено 7/9/19 путем оборачивания горизонтального ListView в контейнер с фиксированной высотой и сжатие ListView)

Следующее утверждение было брошено во время executeResize (): Горизонтальный видовой экран получил неограниченную ширину. Окна просмотра расширяются в направлении прокрутки, чтобы заполнить их контейнер. В этом случае горизонтальный Вьюпорту было предоставлено неограниченное количество горизонтального пространства для расширения. Эта ситуация обычно происходит, когда прокручиваемый виджет вложен в другой прокручиваемый виджет. Если этот виджет всегда вложен в прокручиваемый виджет, нет необходимости использовать область просмотра, потому что всегда будет достаточно горизонтального пространства для детей. В этом случае рассмотрите возможность использования строки вместо. В противном случае рассмотрите возможность использования свойства "shrinkWrap" (или ShrinkWrappingViewport) для изменения размера. ширина окна просмотра в сумме ширины его дочерних элементов.

Новая ошибка 7/9/19:

Во время макета было выдано следующее сообщение: RenderFlex переполнен на 74 пикселя справа. Переполненный RenderFlex имеет ориентацию Axis.horizontal. Переполняющийся край RenderFlex был отмечен при рендеринге желтым и черный полосатый рисунок. Обычно это вызвано тем, что содержимое слишком велико для RenderFlex. Рассмотрите возможность применения гибкого фактора (например, с помощью расширенного виджета), чтобы заставить дочерние элементы RenderFlex для размещения в пределах доступного пространства, а не в натуральную величину. Это считается ошибочным условием, поскольку оно указывает на наличие контента, который не может быть видел. Если содержимое на законных основаниях превышает доступное пространство, подумайте об Виджет ClipRect перед тем, как поместить его в flex или использовать прокручиваемый контейнер, а не Flex, как ListView. Конкретный вопрос о RenderFlex:
RenderFlex # 9bf67 relayoutBoundary = up5 OVERFLOWING
создатель: Row ← RepaintBoundary - [<0>] ← IndexedSemantics ←
NotificationListener ← KeepAlive ← AutomaticKeepAlive ← SliverList ←
SliverPadding ← Окно просмотра ← IgnorePointer- [GlobalKey # 74513] ← Семантика ← Слушатель ← ⋯
parentData: (можно использовать размер)
ограничения: BoxConstraints (w = 404,0, 0,0 <= h <= бесконечность) <br> размер: размер (404.0, 300.0)
направление: горизонтальное
mainAxisAlignment: начало
mainAxisSize: max
CrossAxisAlignment: центр
textDirection: ltr

Это была проблема, с которой я столкнулся первоначально, прежде чем занялся сторонним исследованием первой сообщенной проблемы; Я не могу понять, почему мой ListView не создает прокручиваемый контейнер.

Код:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      home: Scaffold(
        appBar: AppBar(
          title: Text('My App'),
          backgroundColor: Colors.teal[400],
        ),
        body: MyClass(),
      ),
    );
  }
}

const double headerCellWidth = 108.0;
const double cellPadding = 8.0;
const double focusedColumnWidth = 185.0;
const double rowHeight = 36.0;

class MyClass extends StatefulWidget {
  @override
  _MyClassState createState() => _MyClassState();
}

class _MyClassState extends State<MyClass> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(5.0),
      children: <Widget>[
        Row(
          children: <Widget>[
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Container(
                  color: Colors.grey,
                  padding: EdgeInsets.all(cellPadding),
                  width: headerCellWidth,
                ),
                HeaderCell('ABC'),
                HeaderCell('123'),
                HeaderCell('XYZ'),
              ],
            ),
            Container(
              height: 300.0,  // Could compute height with fixed rows and known number of rows in advance
              child: ListView(
                shrinkWrap: true,
                scrollDirection: Axis.horizontal,
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      Container(
                        color: Colors.grey[300],
                        padding: EdgeInsets.all(cellPadding),
                        height: rowHeight,
                        width: focusedColumnWidth,
                      ),
                      NumberCell('89'),
                      NumberCell('92'),
                      NumberCell('91'),
                      NumberCell('90'),
                      NumberCell('91'),
                      NumberCell('89'),
                    ],
                  ),
                  Column(
                    children: <Widget>[
                      Container(
                        color: Colors.grey[300],
                        padding: EdgeInsets.all(cellPadding),
                        height: rowHeight,
                        width: focusedColumnWidth,
                      ),
                      NumberCell('89'),
                      NumberCell('92'),
                      NumberCell('91'),
                      NumberCell('90'),
                      NumberCell('91'),
                      NumberCell('89'),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      ],
    );
  }
}

class HeaderCell extends StatelessWidget {
  HeaderCell(this.text);

  final String text;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: rowHeight,
      padding: EdgeInsets.all(cellPadding),
      width: headerCellWidth,
      child: Text(
        text,
        textAlign: TextAlign.left,
        overflow: TextOverflow.ellipsis,
        maxLines: 1,
        style: TextStyle(
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

class NumberCell extends StatelessWidget {
  NumberCell(this.text);

  final String text;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: rowHeight,
      width: focusedColumnWidth,
      padding: EdgeInsets.all(cellPadding),
      child: Text(
        text,
      ),
    );
  }
}

Ответы [ 2 ]

0 голосов
/ 09 июля 2019

Поэтому я попытался создать минимальный рабочий бит кода и в результате получил работоспособное решение (даже если не детализированы все детали, например, первый заблокированный столбец имеет гибкую ширину вместо фиксированной ширины по желанию). ). Надеюсь, это поможет другим, пытающимся создать нечто подобное. Интересно то, что здесь необходима конструкция Table, поскольку замена TableRow (обернутый Table) просто строкой вызывает ошибку переполнения. Мне все равно было бы интересно понять, почему это так, поскольку это кажется решающим для механизма компоновки.

@override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(5.0),
      children: <Widget>[
        Table(
          children: <TableRow>[
            TableRow(
              children: <Widget>[
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    // first locked column items
                  ],
                ),
                SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Row(
                        children: <Widget>[
                          // table header items
                        ],
                      ),
                      Row(
                        children: <Widget>[
                          // data cells
                        ],
                      ),
                      Row(
                        children: <Widget>[
                          // data cells
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ],
        ),
      ],
    );
  }
0 голосов
/ 09 июля 2019

Вы пробовали установить shrinkWrap: true в горизонтальный список?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...