Flutter:如何根据Expanded和itemCount

时间:2020-06-05 03:22:31

标签: listview flutter dart

我有一个这样的页面:

  1. 第一列表视图:默认为Axis.vertical
  2. 第一列表视图内的第二个列表视图:Axis.horizontalitemCount = 3。为避免错误,我为此设置了height:50的{​​{1}} width:100

但是,我想找到一种使其在所有屏幕上都能正常显示的方法,特别是在第二个ListView中:

  • Container(1:1:1),并且它适合屏幕的右侧,无法滚动。
  • Expanded中的Width将基于Container自动调整大小。
  • Expanded flex中的
  • fontSizeText中的Height将基于Container自动调整大小

enter image description here

所以请帮我,这是JSON文件

maxLine

这是主文件

[
  {
    "id": 1,
    "continent": "North America",
    "countries": [
      {
        "name": "United States",
        "capital": "Washington, D.C.",
        "language": ["English"]
      },
      {
        "country": "Canada",
        "capital": "Ottawa",
        "language": ["English", "French"]
      },
      {
        "country": "Mexico",
        "capital": "Mexico City",
        "language": ["Spanish"]
      }
    ]
  },
  {
    "id": 2,
    "continent": "Europe",
    "countries": [
      {
        "country":  "Germany",
        "capital": "Berlin",
        "language":  ["German"]
      },
      {
        "country":  "United Kingdom",
        "capital": "London",
        "language":  ["English"]
      }
    ]
  },
  {
    "id": 3,
    "continent": "Asia",
    "country": [
      {
        "country":  "Singapore",
        "capital": "Singapore",
        "language":  ["English","Malay","Mandarin","Tamil"]
      }
    ]
  }
]

1 个答案:

答案 0 :(得分:1)

import 'dart:math'; //useful to check the longest list of countries 

class ContinentPage2 extends StatefulWidget {
  ContinentPage2() : super();

  @override
  _ContinentPageState createState() => _ContinentPageState();
}

class _ContinentPageState extends State<ContinentPage2> {
  List<Continent> _continent = []; //initialize empty to avoid problem with the table
  int maxLength; //we need to check for the longest list of countries in all the continents

  @override
  void initState() {
    super.initState();

    ContinentServices.getContinent().then((continents) {
      setState(() {
        _continent = continents;
        maxLength = _continent.map((continent) => continent.country.length).reduce(max); 
        /*max uses dart:math, I made a list of the length of all the List<countries>
        and then check for the list with the maximum length*/
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('')),
        body: SingleChildScrollView(
            child: Table(
          defaultVerticalAlignment: TableCellVerticalAlignment.middle,
          columnWidths: {0: FlexColumnWidth(0.5)}, //accept a map and gives to the index the width I want, in this case the first widget a flex of 0.5, and the others will have the default 1, so it's the same as using expanded with flex: 1 and then flex: 2
          children: [
            for (Continent continent in _continent)
              TableRow(children: [
                TableCell(
                  verticalAlignment: TableCellVerticalAlignment.middle,
                  child: Text(continent.continent),
                ),
                for (Country country in continent.country)
                  Padding(
                    padding: const EdgeInsets.symmetric(vertical: 5),
                    child: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: <Widget>[
                          Flexible(
                            child: FittedBox(
                              fit: BoxFit.scaleDown,
                              child: Text(country.name),
                            ),
                          ),
                          Flexible(
                            child: FittedBox(
                                fit: BoxFit.scaleDown,
                                child: Text(
                                  country.capital,
                                  style: TextStyle(
                                    color: Colors.blue,
                                  ),
                                  textAlign: TextAlign.center,
                                )),
                          ),
                          //OPTION 1 create a String with all the languages as a single text
                          if(country.languages.isNotempty)
                          Flexible(
                            child: MyLanguages(
                                lang: country.languages.reduce((prev, curr) => '$prev, $curr')
                            )
                          ),
                          // Option 2 using a for to create multiple text widgets inside the column widget with all the languages per country
                          if(country.languages.isNotempty)
                          for(String language in country.language)
                          Flexible(
                            child: Text(language)
                          )
                        ]),
                  ),
                if (continent.country.length < maxLength)
                  for (int i = 0; i < maxLength - continent.country.length; i++)
                    const SizedBox()
              ])
          ],
        )));
  }
}


// Used in Option 1
class MyLanguages extends StatelessWidget{
  final String languages;

  MyLanguages({String lang, Key key}) : languages = lang.replaceFirst(',', ' and', lang.lastIndexOf(',').clamp(0, double.infinity)), super(key: key);

  @override
  Widget build(BuildContext context){
    return Text(languages);
  }


}

对于所有嵌套的行和列,我认为最好的方法是使用Table小部件,它允许用y列创建x行的表,但是只有一个问题,所有行都必须具有相同的列数(矩形或方形表格)。因此,要解决此问题,我做了一个int maxLength,然后:

maxLength = _continent.map((continent) => continent.country.length).reduce(max); 

制作一个包含所有国家/地区长度且具有减少最大值的列表,我检索了具有最大长度的列表值,这对下一部分很有用

if (continent.country.length < maxLength)
for (int i = 0; i < maxLength - continent.country.length; i++)
   const SizedBox()

在这里,我检查是否制作了整行,或者该行是否具有少于任何行中最大数量的小部件,然后仅添加虚拟const SizedBox()来欺骗具有相同数量小部件的表在每一行中(如果您对此部分进行注释,则将需要输入相同的列数,这将给您带来错误)。

columnWidths: {0: FlexColumnWidth(0.5)},

此行与Expanded一起用作flex,它接受map Map,其中key int是每一行中列的索引,在这种情况下,我为0,而flex为0.5,其他保留默认值1.0。如果您想尝试一下,还有其他TableColumnWidth

最后,我将“国家/地区”包裹在垂直5的填充中,使其看起来像您的splitterbuilder SizedBox(height:10),在“列”内部,我使用了带有fit.scaleDown的Flexible和FittedBox包裹了文本,从而减小了如果文本充满所有宽度,并添加textAlign.center以使文本居中。如果您有一个很大的大文本,它将减小它的大小。如果您不希望这样做,可以只保留“文本”小部件并添加maxLines和softWrap

Text(
  country.capital,
  style: TextStyle(color: Colors.blue),
  textAlign: TextAlign.center,
  maxLines: 2, softWrap: true,
)

或者,如果您确实想要更多的自定义文字大小,则可以选中Auto_Size_Text Package

fittedBox的结果

With FittedBox

不包含FittedBox和maxLines的结果:2,softwrap:true

enter image description here