web-dev-qa-db-fra.com

Comment créer un tableau à défilement horizontal avec une colonne fixe dans Flutter?

Je voudrais créer une série de tableaux que vous pouvez faire défiler verticalement, chacun pouvant avoir un nombre différent de lignes/colonnes les uns des autres.

Dans chaque tableau, je voudrais que la colonne la plus à gauche soit figée et que les colonnes restantes de ce tableau soient défilables horizontalement, au cas où il y aurait un certain nombre de colonnes qui ne correspondent pas à la largeur de l'écran. Voir capture d'écran:

example

Mon plan initial était d'utiliser un ListView pour le défilement vertical au niveau de la page entre les tableaux, et dans chaque tableau, il y a une rangée de colonnes, où la première colonne est une largeur statique et les colonnes restantes sont enfermées dans un ListView défilant horizontalement . L'erreur que je reçois de Flutter ne m'aide pas à déterminer ce que je dois faire, mais cela a clairement à voir avec la nécessité de définir des limites pour les widgets enfants.

Erreur: (Correction du 7/9/19 en enveloppant ListView horizontal avec un conteneur à hauteur fixe et en rétrécissant ListView)

L'assertion suivante a été émise lors de performResize (): la fenêtre horizontale a reçu une largeur illimitée. Les fenêtres se développent dans le sens du défilement pour remplir leur conteneur. Dans ce cas, une fenêtre horizontale a reçu une quantité illimitée d'espace horizontal pour se développer. Cette situation se produit généralement lorsqu'un widget déroulant est imbriqué dans un autre widget déroulant. Si ce widget est toujours imbriqué dans un widget déroulant, il n'est pas nécessaire d'utiliser une fenêtre car il y aura toujours suffisamment d'espace horizontal pour les enfants. Dans ce cas, envisagez d'utiliser une ligne à la place. Sinon, envisagez d'utiliser la propriété "shrinkWrap" (ou un ShrinkWrappingViewport) pour dimensionner la largeur de la fenêtre à la somme des largeurs de ses enfants.

Nouvelle erreur 7/9/19:

Le message suivant a été émis lors de la mise en page: Un RenderFlex a débordé de 74 pixels à droite. Le RenderFlex débordant a une orientation de l'axe horizontal. Le bord du RenderFlex qui déborde a été marqué dans le rendu avec un motif rayé jaune et noir. Cela est généralement dû au fait que le contenu est trop volumineux pour le RenderFlex. Envisagez d'appliquer un facteur de flexibilité (par exemple, en utilisant un widget étendu) pour forcer les enfants du RenderFlex à tenir dans l'espace disponible au lieu d'être dimensionnés à leur taille naturelle. Ceci est considéré comme une condition d'erreur car il indique qu'il y a du contenu qui ne peut pas être vu. Si le contenu est légitimement plus grand que l'espace disponible, envisagez de le découper avec un widget ClipRect avant de le placer dans le flex, ou d'utiliser un conteneur déroulant plutôt qu'un Flex, comme un ListView. Le RenderFlex spécifique en question est:
RenderFlex # 9bf67 relayoutBoundary = up5 TROP PLEIN
créateur: Row ← RepaintBoundary- [<0>] ← IndexedSemantics ←
NotificationListener ← KeepAlive ← AutomaticKeepAlive ← SliverList ←
SliverPadding ← Fenêtre d'affichage ← IgnorePointer- [GlobalKey # 74513] ← Sémantique ← Écouteur ← ⋯
parentData: (peut utiliser la taille)
contraintes: BoxConstraints (w = 404,0, 0,0 <= h <= Infinity)
taille: Taille (404,0, 300,0)
direction: horizontale
mainAxisAlignment: démarrer
mainAxisSize: max
crossAxisAlignment: centre
textDirection: ltr

C'est le problème que j'ai rencontré à l'origine avant d'être mis de côté avec le premier problème signalé; Je ne comprends pas pourquoi mon ListView ne crée pas de conteneur déroulant.

Code:

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,
      ),
    );
  }
}
6
Daniel Allen

S'il n'y a pas beaucoup de personnalisation nécessaire, pour ceux nécessaires, une table d'en-tête fixe et de première colonne peut également envisager d'utiliser le package horizontal_data_table: https://pub.dev/packages/horizontal_data_table

Il utilise essentiellement l'approche des deux listes.

0
CbL

Avez-vous essayé de définir shrinkWrap: true dans la liste horizontale

0
Sergio Bernal