Flutter запускает курсор текстового поля при изменении текста контроллера

#flutter #dart

#flutter #dart

Вопрос:

У меня есть повторно используемый класс текстового поля, например:

 import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String value = "";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: MyTextField(
            value: value,
            onChange: (val) {
              setState(() {
                value = val;
              });
            },
          ),
        ),
      ),
    );
  }
}

typedef ChangeCallback = void Function(String value);

class MyTextField extends StatefulWidget {
  final ChangeCallback onChange;
  final String value;

  const MyTextField({this.onChange = _myDefaultFunc, this.value = ""});
  
  static _myDefaultFunc(String value){}

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

class _MyTextFieldState extends State<MyTextField> {
  final controller = TextEditingController();

  @override
  void initState() {
    controller.text = widget.value;
    super.initState();
  }

  @override
  void didUpdateWidget(covariant MyTextField oldWidget) {
    controller.text = widget.value;
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: controller,
      onChanged: (value) {
        widget.onChange(value);
      },
    );
  }
}

 

Как вы можете видеть, если значение изменено onChange , вызывается обратный вызов, а также значение снова отправляется обратно TextField . Проблема с этим заключается в том, что каждый раз, когда я обновляю значение, TextField курсор всегда устанавливается в начало. Возможно, потому, что обновленное значение отправляется обратно TextField каждый раз? Не уверен. Можете ли вы мне помочь с этим?

Ответ №1:

Нет необходимости обновлять значения в didUpdateWidget

 //@override
//   void didUpdateWidget(covariant MyTextField oldWidget) {
//     controller.text = widget.value;
//     super.didUpdateWidget(oldWidget);
//   }
 

Я только что прокомментировал эту функцию, и код работает нормально
, ниже приведен полный код

 import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String value = "";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(children: [
          SizedBox(height:50),
          Text("text input: $value"),
          SizedBox(height:50),
          Center(
            child: MyTextField(
              value: value,
              onChange: (val) {
                setState(() {
                  value = val;
                });
              },
            ),
          ),
        ]),
      ),
    );
  }
}

typedef ChangeCallback = void Function(String value);

class MyTextField extends StatefulWidget {
  final ChangeCallback onChange;
  final String value;

  const MyTextField({this.onChange = _myDefaultFunc, this.value = ""});

  static _myDefaultFunc(String value) {}

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

class _MyTextFieldState extends State<MyTextField> {
  final controller = TextEditingController();

  @override
  void initState() {
    controller.text = widget.value;
    super.initState();
  }

//   @override
//   void didUpdateWidget(covariant MyTextField oldWidget) {
//     controller.text = widget.value;
//     super.didUpdateWidget(oldWidget);
//   }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: controller,
      onChanged: (value) {
        widget.onChange(value);
      },
    );
  }
}
 

Ответ №2:

Вместо того, чтобы использовать onChanged метод для получения значения текстового поля, передайте a TextEditingController .

 class MyTextField extends StatefulWidget {
  final TextEditingController controller;
  final String defaultValue;

  const MyTextField({@required this.controller, this.defaultValue = ''});

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

class _MyTextFieldState extends State<MyTextField> {
  @override
  void initState() {
    widget.controller.text = widget.defaultValue;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: widget.controller,
    );
  }
}
 

Таким образом, вы можете объявить a TextEditingController в родительском виджете, чтобы получить значение, как вы обычно делаете с собственным Flutter TextFormField .