dart 在setState之后,TextField的抖动光标移动到位置0

b1payxdu  于 2023-07-31  发布在  其他
关注(0)|答案(3)|浏览(73)

每当TextFields文本更改时,我希望在文本中显示某些内容:

class _MyPageState extends State<MyPage> {

String name;

@override
  Widget build(BuildContext context) {
      TextEditingController c = new TextEditingController(text: name);
      c.addListener(() {
         setState(() { name = c.text;});
      });
      return Scaffold(
         body: Center(
            child: Column(children: [ 
               Text('Hello, ' + name + '!'),
               TextField(controller: c)
      ])));
  }
}

字符串
Text将按exspected更新,但问题是每次输入字符时,TextField的光标都会移动到位置0。

lymnna71

lymnna711#

问题是每次重新构建小部件时都要创建一个新的TextEditingController。正在根据键入的每个字符重新构建小部件。
您只需要将TextEditingController移出小部件构建函数。同时将c.addListener移动到小部件的initState函数中。这样,TextEditingController只创建一次,监听器只添加一次。
PS:处置小部件的时候处置你的控制器也不错

class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  String name = '';
  TextEditingController c = new TextEditingController();

  @override
  void initState() {
    c.addListener(() {
      setState(() {
        name = c.text;
      });
    });
    super.initState();
  }

  @override
  void dispose() {
    c.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Column(children: [
      Text('Hello, ' + name + '!'),
      TextField(controller: c)
    ])));
  }
}

字符串

pdtvr36n

pdtvr36n2#

我已经修改了你的代码,你只需要改变你的TextEditingController,见下文。

class _MyPageState extends State<MyWidget> {
  // initialize to empty string
  String name = "";
  
 @override
  Widget build(BuildContext context) {
    // this is how textEditingController should be
    final TextEditingController c = TextEditingController.fromValue(
            new TextEditingValue(
                text: name,
                selection: new TextSelection.collapsed(
                    offset: name.length)));
    
    c.addListener(() {
         setState(() { name = c.text;});
      });
    
      return Scaffold(
         body: Center(
            child: Column(children: [ 
               Text('Hello, ' + name + '!'),
               TextField(controller: c)
      ])));
  }
}

字符串

c86crjj0

c86crjj03#

在我例子中,我必须自定义TextField样式。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class ClearableTextField extends StatefulWidget {
  const ClearableTextField({
    Key? key,
    this.prefixText,
    this.suffixText,
    this.prefix,
    this.suffix,
    this.inputFormatters,
    this.crossAxisAlignment = CrossAxisAlignment.center,
    this.hintText,
    this.margin,
    this.keyboardType,
    this.fontSize = 16,
    this.height = 1.5,
    this.maxLength,
    required this.value,
    required this.onChanged,
  }) : super(key: key);

  final String? prefixText;
  final String? suffixText;
  final Widget? prefix;
  final Widget? suffix;
  final List<TextInputFormatter>? inputFormatters;
  final CrossAxisAlignment crossAxisAlignment;
  final String? hintText;
  final EdgeInsetsGeometry? margin;
  final TextInputType? keyboardType;
  final double? fontSize;
  final double? height;
  final int? maxLength;
  final dynamic value;
  final ValueChanged<String> onChanged;

  @override
  State<ClearableTextField> createState() => _ClearableTextFieldState();
}

class _ClearableTextFieldState extends State<ClearableTextField> {
  Color _underlineColor = const Color(0xFFE2E5EF);
  bool _showClear = false;
  late TextEditingController _controller;
  final FocusNode _focusNode = FocusNode();

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController(text: widget.value);
    _controller.addListener(_onTextChanged);
    if (_controller.text.isNotEmpty) _showClear = true;
    _focusNode.addListener(_handleFocusChange);
  }

  @override
  void didUpdateWidget(ClearableTextField oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.value == widget.value) return;
    // _controller.text = widget.value; // this would make the cursor weird
    _controller.value = TextEditingValue(
      text: widget.value,
      selection: TextSelection.collapsed(offset: widget.value.length),
    ); // this works fine
  }

  @override
  void dispose() {
    _controller.dispose();
    _focusNode.dispose();
    super.dispose();
  }

  void _onTextChanged() {
    setState(() {
      _showClear = _controller.text.isNotEmpty;
    });
    widget.onChanged(_controller.text);
  }

  void _handleFocusChange() {
    if (!_focusNode.hasFocus) {
      FocusManager.instance.primaryFocus?.unfocus();
      _underlineColor = const Color(0xFFE2E5EF);
    } else {
      _underlineColor = Theme.of(context).primaryColor;
    }
    setState(() {});
  }

  void _clearText() {
    widget.onChanged('');
    setState(() {
      _controller.clear();
      _showClear = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: widget.margin,
      padding: EdgeInsets.symmetric(vertical: 5.w),
      decoration: BoxDecoration(
        border: Border(bottom: BorderSide(color: _underlineColor)),
      ),
      child: Row(
        crossAxisAlignment: widget.crossAxisAlignment,
        children: [
          if (widget.prefix != null || widget.prefixText != null) ...{
            if (widget.prefix != null) widget.prefix!,
            if (widget.prefixText != null) SizedBox(width: 8.w),
          },
          Expanded(
            child: TextField(
              controller: _controller,
              // or use this
              // _controller..selection =
              //     TextSelection.collapsed(offset: widget.value.length),
              focusNode: _focusNode,
              inputFormatters: widget.inputFormatters,
              keyboardType: widget.keyboardType,
              maxLength: widget.maxLength,
              style: TextStyle(
                fontWeight: FontWeight.w500,
                fontSize: widget.fontSize,
                height: widget.height,
              ),
              decoration: InputDecoration(
                counterText: '',
                contentPadding: EdgeInsets.zero,
                border: InputBorder.none,
                hintText: widget.hintText,
                hintStyle: TextStyle(
                  fontSize: 16.sp,
                  color: const Color(0xFF9498AB),
                  fontWeight: FontWeight.w400,
                ),
              ),
            ),
          ),
          if (_showClear)
            SizedBox(
              width: 32.w,
              height: 32.w,
              child: IconButton(
                iconSize: 18.w,
                icon: Image.asset('assets/images/public/clear_input.png'),
                onPressed: _clearText,
              ),
            ),
          if (widget.suffix != null || widget.suffixText != null) ...{
            if (widget.suffix != null) widget.suffix!,
            if (widget.suffixText != null)
              Text(
                widget.suffixText!,
                style: TextStyle(
                  fontSize: 24.sp,
                  fontWeight: FontWeight.w500,
                ),
              ),
          },
        ],
      ),
    );
  }
}

字符串
如果得到didUpdateWidget,请小心使用_controller.value而不是_controller.text,或者直接删除它。

相关问题