简体   繁体   中英

Show list items in a stateful widget linked to the item

I have a list of integers. Each of this item is displayed in a statefull widget by iterating the list in the build method.

import 'package:flutter/material.dart';
import 'package:widget_list/ItemWidget.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Item list state demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Item list state demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static int itemsCount = 0;

  final List<int> _items = List.empty(growable: true);

  void _add() {
    setState(() {
      _items.add(itemsCount++);
    });
  }

  void _remove() {
    setState(() {
      _items.removeAt(0);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Row(
              children: [
                TextButton(
                  onPressed: () => _add(),
                  child: const Text('Add item'),
                ),
                TextButton(
                  onPressed: () => _items.isNotEmpty ? _remove() : null,
                  child: const Text('Remove item'),
                ),
              ],
            ),
            for (var item in _items) ItemWidget(item: item),
          ],
        ),
      ),
    );
  }
}

Each of this widget, has a statically incremented integer "id" in it's state. Both the item and the widget id are displayed.

import 'package:flutter/material.dart';

var widgetCount = 0;

class ItemWidget extends StatefulWidget {
  final int item;

  const ItemWidget({
    required this.item,
    Key? key,
  }) : super(key: key);

  @override
  State<ItemWidget> createState() => _ItemWidgetState();
}

class _ItemWidgetState extends State<ItemWidget> {
  final int widgetId = widgetCount++;

  @override
  Widget build(BuildContext context) {
    print("Item ${widget.item} / Widget $widgetId");
    return Text("Item ${widget.item} / Widget $widgetId");
  }
}

When I add an item in the list, it is displayed in a newly generated widget. Eg first item 0 is displayed in widget 0.

在此处输入图像描述

But if I remove an item at the beginning of the list (eg item 0), it's not the first widget that is destoyed, but the last one. The item 1 is then displayed in widget 0.

在此处输入图像描述

The widget item is final, so it cannot change. The widget ids are still the same, so the states were not rebuild. Then, why are the states no more consistent with the widgets?

This is done in FLutter desktop for Linux, v3.0.1

In the itemWidget you are creating a value from 0 so for each element that is rendered it will start from 0. please check the code below

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Item list state demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Item list state demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static int itemsCount = 0;

  final List<ItemInfo> _items = List.empty(growable: true);

  void _add() {
    setState(() {
      itemsCount++;
      _items.add(ItemInfo(itemsCount, itemsCount));
    });
  }

  void _remove() {
    setState(() {
      _items.removeAt(0);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Row(
              children: [
                TextButton(
                  onPressed: () => _add(),
                  child: const Text('Add item'),
                ),
                TextButton(
                  onPressed: () => _items.isNotEmpty ? _remove() : null,
                  child: const Text('Remove item'),
                ),
              ],
            ),
            for (var item in _items) ItemWidget(item: item),
          ],
        ),
      ),
    );
  }
}

and Itemwidget to be like this

class ItemWidget extends StatefulWidget {
  final ItemInfo item;

  const ItemWidget({
    required this.item,
    Key? key,
  }) : super(key: key);

  @override
  State<ItemWidget> createState() => _ItemWidgetState();
}

class _ItemWidgetState extends State<ItemWidget> {
  @override
  Widget build(BuildContext context) {
    return Text(
        "Item ${widget.item.itemVal} / Widget ${widget.item.itemIndex}");
  }
}

also I created a class named ItemInfo which will hold both the value and its index.

class ItemInfo {
  int itemVal;
  int itemIndex;
  ItemInfo(this.itemVal, this.itemIndex);
}

预习

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM