Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
477 views
in Technique[技术] by (71.8m points)

state - Flutter - TextField is empty every time I re-open the widget

So, I'm new to Flutter and was trying to code a simple notes app to learn my way around it. The layout of the app is a HomePage with a ListView of NoteTiles that when tapped open a corresponding NotePage where you can write down things. The issue I got is that every time I leave the NotePage and then re-open it from the HomePage, the NotePage loses its content.
My first idea was to keep the content in the corresponding NoteTile so that when I leave the NotePage I would pop with the content, and when needed I would push to the NotePage with the previously saved content. The problem is that I didn't find any simple way to push and set the content. I've seen there are Notification and Route methods but they come with quite a lot of boilerplate and they look like it's more for passing data from child to parent, which I can do easily when popping.
So, is there a way to avoid the reset of the content of the NotePage? Or maybe is there a simple way to initState with the content previously saved?
Here is the code I have so far:

class NoteTile extends ListTile {

  final NotePage note;
  final Text title;
  final BuildContext context;

  NoteTile(this.title, this.note, this.context) : super(
    title: title,
    onTap: () => {
      Navigator.of(context).push(
        MaterialPageRoute(builder: (context) => note),
      ),
    },
    onLongPress: () => null,
    );

  void switchToNote() async {
    Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => note),
    );
  }

}

onLongPress will later be used to delete the note.

class NotePage extends StatefulWidget {
  final String title;
  NotePage({Key key, this.title}) : super(key: key);

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

class _NotePageState extends State<NotePage> {
  TextEditingController _controller;
  String _value;

  void initState() {
    super.initState();
    _controller = TextEditingController();
    _controller.addListener(_updateValue);
    _value = '';
  }

  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _updateValue(){
    _value = _controller.text;
  }

  Future<bool> _onWillPop() async {
    Navigator.pop(context, _value);
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
        child: Scaffold(
          appBar: AppBar(
            title:  Text(widget.title),
          ),
          body: Container(
            child: TextField(
              decoration: InputDecoration(
                border: InputBorder.none,
                hintStyle: TextStyle(fontStyle: FontStyle.italic),
                hintText: 'New note',
              ),
              maxLines: null,
              controller: _controller,
            ),
            padding: EdgeInsets.all(12.0),
          ),
        ),
        onWillPop: _onWillPop,
    );
  }
}

The _onWillPop is to send back the content to the NoteTile, which currently disregards the return data because I failed to find a way to use that data later when pushing the NotePage again.

question from:https://stackoverflow.com/questions/65857779/flutter-textfield-is-empty-every-time-i-re-open-the-widget

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

ListTile is StatelessWidget widget, so you cannot reserve the state, the NoteTile should be StatefulWidget.

Here is a sample of NoteTile:

class NoteTile extends StatefulWidget {
  final Text title;

  const NoteTile({Key key, this.title}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _NoteTileState();
  }
}

class _NoteTileState extends State<NoteTile> {
  String _result;

  @override
  void initState() {
    super.initState();
    _result = "";
  }

  void _onOpenNote() async {
    String result = await Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => NotePage(title: _result)),
    );
    if (result != null) {
      _result = result;
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: widget.title,
      onTap: _onOpenNote,
    );
  }
}

And NotePage should be edit in some lines:

TextEditingController can have initialize string & have to initialize by title:

_controller = TextEditingController(text: widget.title);

Navigator.pop can post result and you did it correctly, but if you want to get the result, should wait for Navigator.of(context).push, because its run in another thread.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...