简体   繁体   中英

Flutter list of stateful widgets bug - What am i doing wrong

I want to make a upcoming tasks sort of UI, with slider buttons for task start and stop. These buttons render the slider animation when slid horizontally. I also want to make the tasks disappear from list when finished.

However, i'm running into an issue with a list of stateful buttons where I don't add one to the list, but it still keeps showing, instead the button that was added to the list disappears. Here's my code:

import 'dart:core';
import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  State createState() => new MyAppState();
}

class MyAppState extends State<MyApp> {
  int state = 0;

  @override
  Widget build(BuildContext context) {
    var redButton = new IconButton(
      icon: new Icon(Icons.send, color: Colors.red),
      onPressed: null
    );
    var blueButton = new IconButton(
      icon: new Icon(Icons.send, color: Colors.blue),
      onPressed: null
    );
    var clicker = new IconButton(
      icon: new Icon(Icons.refresh, color: Colors.green),
      onPressed: () {
        setState(() {
          state = state + 1;
        });
      }
    );

    List<Widget> list = new List();
    list.add(new Text('$state'));
    list.add(clicker);
    if (state < 1) {
      list.add(new _Button(redButton));
    } else {
      print ('Not showing red button');
    }

    print ('Showing blue button');
    list.add(new _Button(blueButton));

    return new MaterialApp(
      title: 'Slide animation',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Center(child: new Text('Flutter stateful widget list bug')),
        ),
        body: new Column(
          children: list,
        ),
      ),
    );
  }
}

// Includes animation and other stuff - stripped for now
class _Button extends StatefulWidget {
  static int counter = 0;
  final Widget button;
  final int id = counter++;
  _SlidableButtonState state;
  _Button(this.button);

  @override
  State createState() {
    state = new _SlidableButtonState(button);
    print ('${id} -> $state');
    return state;
  }
}

class _SlidableButtonState extends State<_Button> {
  final Widget button;
  _SlidableButtonState(this.button);

  @override
  void dispose() {
    super.dispose();
    print ('$this: dispose');
  }

  @override
  Widget build(BuildContext context) {
    // Some rendering stuff will come here
    return button;
  }
}

When the clicker button is clicked, i expect the red button to disappear and the blue button to show. However, the red button is still showing and its the blue button that disappears. Here's the logs showing the blue button was disposed off:

Launching lib/examples/list_bug_flutter.dart on Android SDK built for x86 in debug mode...
Initializing gradle...
Resolving dependencies...
Running 'gradlew assembleDebug'...
Built build/app/outputs/apk/debug/app-debug.apk (31.4MB).
Installing build/app/outputs/apk/app.apk...
I/FlutterActivityDelegate(26592): onResume setting current activity to this
I/flutter (26592): Showing blue button
Syncing files to device Android SDK built for x86...
I/flutter (26592): 0 -> _SlidableButtonState#cfe2f(lifecycle state: created, no widget, not mounted)
I/flutter (26592): 1 -> _SlidableButtonState#2d165(lifecycle state: created, no widget, not mounted)
I/flutter (26592): Not showing red button
I/flutter (26592): Showing blue button
I/flutter (26592): _SlidableButtonState#2d165(lifecycle state: defunct): dispose
I/flutter (26592): Not showing red button
I/flutter (26592): Showing blue button

应用启动时点击后

As you guessed, the issue was passing widget to the State.

State objects can be reused with different widgets. See https://docs.flutter.io/flutter/widgets/State-class.html

During this time, a parent widget might rebuild and request that this location in the tree update to display a new widget with the same runtimeType and Widget.key. When this happens, the framework will update the widget property to refer to the new widget and then call the didUpdateWidget method with the previous widget as an argument

You can check this by overriding didUpdateWidget and adding some logs.

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