What is a good approach to dynamically create a column of rows in Flutter

999

The good approach to a dynamic column of widgets is to use a ListView.builder instead. Find the documentation here: https://api.flutter.dev/flutter/widgets/ListView/ListView.builder.html

ListView.builder(
  itemCount: rowMap.length,
  itemBuilder: (context, index) {
    return buildPartsRow(rowMap[index]);
  }
)
Share:
999
alfredyang
Author by

alfredyang

Updated on December 17, 2022

Comments

  • alfredyang
    alfredyang over 1 year

    So ideally, I would like to let users to dynamically add or delete a row from my column when a button is hit. Like when the + button is hit, a row is added to the column and vice versa when the X is hit. However, the problem comes when I try to delete a row with the correspoding X button. It seems like my approachs can only delete a random row when the x is hit, but not the intended row. Such behavior might be good enough for the users if the user had already put in data in a certain row then wanted to delete this row only.

    r0..... +

    r1..... X (when X is hit here r2 or some other row might be deleted, same for other X button)

    r2..... X

    So far I have adopted two approaches to achieve my intended functions. The first one is to use a simple valuenotifier and a for loop. Such as

    final number = new ValueNotifier(0);
    
    new IconButton(
      icon: Icon(Icons.add),
      onPressed: () {
        number.value++;
        print(number.value);
        setState(() {});
      })
    
    new Column(
      children: buildPartsWidget(number.value),
    )
    
    List<Widget> buildPartsWidget(int counts){
        List<Widget> ret = [];
        for(int i = 0; i < counts; i++){
          var temp = buildPartsRow();
          ret = List.from(ret)..add(temp);
        }
        return ret;
      }
    
    Row buildPartsRow(int key) {
        return new Row(children: <Widget>[
    
          new IconButton(
            icon: Icon(Icons.clear), 
            onPressed: () {
              number.value--;
              setState(() {});
            })
        ]);
      }
    
    

    The second one is to use a map to pair a row with a number, which doesnt work neither,such as:

    Map<int, Row> rowMap = new Map();
    int rowIndex;
    
    List<Widget> rowList(){
        List<Widget> ret = [];
        rowMap.forEach((k, v) => ret.add(v));
        return ret;
      } 
    
    new IconButton(
      icon: Icon(Icons.add),
      onPressed: () {
        rowMap[rowIndex] = buildPartsRow(rowIndex);
        rowIndex++;
        setState(() {});
      })
    
    new Column(
      children: rowList
    )
    
    
    Row buildPartsRow(int key) {
        return new Row(children: <Widget>[
    
          new IconButton(
            icon: Icon(Icons.clear), 
            onPressed: () {
              rowMap.remove(key);
              setState(() {});
            })
        ]);
      }
    

    I feel like I understand the underlying problems of these two approaches. To my understanding, such behavior occurs because in both approaches the flutter rebuild the entrie columns and has no way nor does it 'care' about the input data in the row. How should I fix my approach? Or is there a better way to achieve my intended functionalities?

    I have also tried using the listView but it didnt work for me. As all these widgets I am using are already inside a listview, using a listview inside a listview seems require me to limit the inner listview's size by using a container or sizedbox, which would give me a box on my form. I do not want the box on my form. Is there a way using the listview but doesnt require a box to limit its size?

  • alfredyang
    alfredyang about 4 years
    sorry, I forgot to mention one thing. I have already tried this approach but it didnt work for me. As all these widgets I am using are already inside a listview, using a listview inside a listview seems require me to limit the inner listview's size by using a container or sizedbox, which would give me a box on my form. I do not want the box on my form. Is there a way using the listview but doesnt require a box to limit its size?
  • ArthurEKing
    ArthurEKing about 4 years
    I think your list view inside list view issue might be a size/constraints issue? If so, try placing them inside an Expanded widget. The issue with constraints is that if you try to put something without constraints into something without constraints, it becomes an overflow error. (Like a column inside a column, row inside a row, or textfield inside a row, for a few examples) but wrapping them in an expanded widget works.
  • alfredyang
    alfredyang about 4 years
    @ArthurEKing I tried that as well. I had listview wrapped in an expanded wrapped in a column. But its not gonna compile unless the column is wrapped by a container or the expanded is wrapped by a sizedbox