首页 > 解决方案 > 每次屏幕发生变化时都会调用屏幕的构造函数

问题描述

textformfield在推送的屏幕中点击 a 时,屏幕的构造函数会再次被调用,并且textformfield会失去它的值。另外,我认为该屏幕中发生的每次更改都会导致再次调用其构造函数,而我根本不知道原因。

这是生成错误的示例代码:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Hello',
              style: TextStyle(color: Colors.black, fontSize: 30.0),
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(context).push(
              MaterialPageRoute(builder: (context) => NextScreen(Bloc())));
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

这是要推送的屏幕

class NextScreen extends StatefulWidget {
  final _bloc;
  NextScreen(this._bloc);

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

class _NextScreenState extends State<NextScreen> {
  @override
  void dispose() {
    widget._bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.all(100.0),
            child: IconButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              icon: Icon(Icons.arrow_back),
              iconSize: 20.0,
            ),
          ),
          StreamBuilder<String>(
              stream: widget._bloc.stream,
              builder: (context, snapshot) {
                return TextFormField(
                  controller: widget._bloc.controller,
                  onFieldSubmitted: widget._bloc.submitData(),
                  decoration: InputDecoration(
                    hintText: 'Enter your name..',
                    errorText: snapshot.data,
                  ),
                );
              })
        ],
      ),
    );
  }
}

验证用户输入的块

class Bloc {
  TextEditingController _controller;
  TextEditingController get controller => _controller;

  BehaviorSubject<String> _subject;

  BehaviorSubject<String> _validatorSubject;
  Stream<String> get stream => _validatorSubject.stream;

  void submitData() {
    _subject.sink.add(controller.text);
  }

  void _validate(String text) {
    if (!RegExp(r'[0-9]').hasMatch(text)) {
      _validatorSubject.sink.add('numbers only');
    } else {
      _validatorSubject.sink.add(null);
    }
  }

  Bloc() {
    _controller = TextEditingController();
    _subject = BehaviorSubject<String>();
    _validatorSubject = BehaviorSubject<String>();
    _subject.stream.listen(_validate);
  }

  void dispose() {
    _subject.close();
    _validatorSubject.close();
  }
}

标签: flutterdart

解决方案


打开和关闭键盘将重建整个屏幕。真正的罪魁祸首是 textController :

controller: widget._bloc.controller,

对我有用的解决方案是删除这条线。

此外,要获取和验证更改的文本,您可以在文本字段中使用 onChanged,它会返回一个字符串。像这样 :

.
.
.
 return TextFormField(
       onChanged: widget._bloc.submitData,
       decoration: InputDecoration
.
.
.

你 submitData() 方法会是这样的:

    void submitData(String data) {
    _subject.sink.add(data);
  }

推荐阅读