【问题标题】:Constructor of screen is called every time a change occurs in that screen每次屏幕发生变化时都会调用屏幕的构造函数
【发布时间】:2020-03-05 01:23:46
【问题描述】:

在推送的屏幕中点击textformfield 时,屏幕的构造函数会再次被调用,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();
  }
}

【问题讨论】:

  • 请添加一些代码。
  • 如果您可以添加几行代码,我们会很容易回答吗?
  • 我已经编辑了问题并添加了重现错误的代码。

标签: flutter dart


【解决方案1】:

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

controller: widget._bloc.controller,

对我有用的解决方案是删除此行。

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

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

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

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

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多