You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter修改名称后再次编辑文本框内容自动回退问题求助

问题描述

在Flutter应用中实现了用户名修改功能,名称在页面加载前从SharedPreferences获取。首次修改名称功能正常,但再次打开编辑对话框时,文本框内容会自动回退到旧名称。

问题截图

  • 修改前:修改前
  • 修改时:修改时
  • 回退至旧名称:回退至旧名称

相关代码

class ProfileInfo extends StatefulWidget {
  String? name;
  String? email;

  ProfileInfo({widget.name, widget.email});

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

class _ProfileInfoState extends State<ProfileInfo> {
  var nameController = TextEditingController();

  void updateName(String newName) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setString('name', newName);

    setState(() {
      nameController.text = newName;
      widget.name = newName;
    });
  }

  void _showEditNameDialog(BuildContext context) {
    // Set the nameController.text to the current name
    nameController.text = widget.name ?? '';

    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Edit Name'),
          content: TextField(
            controller: nameController,
            decoration: InputDecoration(hintText: 'Enter your name'),
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () {
                // Save the edited name if needed
                updateName(nameController.text);
                Navigator.of(context).pop();
              },
              child: Text('Save'),
            ),
          ],
        );
      },
    );
  }

  void redirtohome() async {
    var t = await getQuote();
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        fullscreenDialog: true,
        builder: (context) => home_page(quotes: t),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Column(
      children: [
        SizedBox(
            width: size.width * .9,
            child: Row(
              children: [
                InkWell(
                  onTap: Navigator.of(context).pop,
                  child: Image.asset(
                    "assets/images/whitebackarrow.png",
                    width: size.width * .05,
                  ),
                ),
                SizedBox(width: 10),
                Text(
                  'Edit Profile',
                  style: TextStyle(color: Colors.white, fontSize: 20),
                ),
                Spacer(),
                SizedBox(
                  width: size.width * .3,
                  height: size.height * .065,
                  child: ElevatedButton(
                    style: ElevatedButton.styleFrom(
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20),
                      ),
                      backgroundColor: Colors.transparent,
                      shadowColor: Colors.transparent,
                    ),
                    onPressed: () {
                      redirtohome();
                    },
                    child: Text(
                      'JustLift',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 16.0,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
              ],
            )),
        SizedBox(height: 10),
        SizedBox(height: 10),
        Container(
          height: size.height * 0.3,
          width: size.width * .9,
          child: Stack(
            alignment: Alignment.center,
            children: <Widget>[
              Icon(
                Icons.circle,
                color: Color(0xff11b779),
                size: size.height * 0.3,
              ),
              Text(
                widget.name!.length >= 2
                    ? widget.name!.substring(0, 2).toUpperCase()
                    : widget.name!,
                style: TextStyle(
                    fontSize: size.height * 0.13,
                    color: Colors.white,
                    fontWeight: FontWeight.bold),
              ),
            ],
          ),
        ),
        SizedBox(height: 10),
        Container(
          width: size.width * .9,
          height: 30,
          color: Colors.grey.withOpacity(.14),
          padding: EdgeInsets.only(top: 4, left: 10),
          child: Text(
            'NAME',
            style: TextStyle(
              fontSize: 18,
              color: Colors.grey.withOpacity(.8),
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
        Container(
            width: size.width * .9,
            child: TextButton(
                onPressed: () {
                  _showEditNameDialog(context);
                },
                child: Row(children: [
                  Text(
                    widget.name!,
                    style: const TextStyle(
                      color: Color(0xFFCECECE),
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Spacer(),
                  Icon(Icons.edit, color: Color(0xFFCECECE)),
                ]))),
        Container(
          width: size.width * .9,
          height: 30,
          color: Colors.grey.withOpacity(.14),
          padding: EdgeInsets.only(top: 4, left: 10),
          child: Text(
            'EMAIL',
            style: TextStyle(
              fontSize: 18,
              color: Colors.grey.withOpacity(.8),
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
        Container(
          width: size.width * .9,
          padding: EdgeInsets.all(10),
          child: Text(
            widget.email!,
            style: const TextStyle(
              color: Color(0xFFCECECE),
              fontSize: 18,
              fontWeight: FontWeight.bold,
            ),
          ),
        )
      ],
    );
  }
}

class EditProfilePage extends StatefulWidget {
  @override
  _EditProfilePageState createState() => _EditProfilePageState();
}

class _EditProfilePageState extends State<EditProfilePage> {
  String? name = '';
  String? email = '';

  @override
  void initState() {
    super.initState();
    getInfo();
  }

  Future<void> getInfo() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      name = prefs.getString('name');
      email = prefs.getString('email');
    });
  }

  @override
  Widget build(BuildContext context) {
    if (name == null || email == null) {
      return Center(
        child: SizedBox(
          height: 50.0, // or another size
          width: 50.0,
          child: CircularProgressIndicator(),
        ),
      );
    } else {
      return buildPage(context);
    }
  }

  @override
  Widget buildPage(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    double height = MediaQuery.of(context).viewPadding.top;
    return Scaffold(
        resizeToAvoidBottomInset: false,
        backgroundColor: AppColors('Default').main2,
        body: Column(children: [
          SizedBox(height: MediaQuery.of(context).padding.top + 10),
          Expanded(
            child: ProfileInfo(name: name, email: email),
          ),
          Align(alignment: Alignment.bottomCenter, child: Footer(tab: 'More'))
        ]));
  }
}
问题原因
  1. 直接修改widget.name违反了Flutter的状态管理原则:StatefulWidget的属性应该是不可变的,修改后无法触发父组件的状态更新。
  2. EditProfilePage中的name状态没有同步更新,导致ProfileInfo接收的始终是旧值,再次打开对话框时文本框被设置回旧名称。
解决方案

修改ProfileInfo组件

添加回调函数通知父组件更新状态,同步控制器文本与最新名称:

class ProfileInfo extends StatefulWidget {
  final String? name;
  final String? email;
  final Function(String) onNameUpdated; // 添加回调

  const ProfileInfo({
    super.key,
    required this.name,
    required this.email,
    required this.onNameUpdated,
  });

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

class _ProfileInfoState extends State<ProfileInfo> {
  late TextEditingController nameController;

  @override
  void initState() {
    super.initState();
    nameController = TextEditingController(text: widget.name ?? '');
  }

  @override
  void didUpdateWidget(covariant ProfileInfo oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 父组件name更新时同步控制器文本
    if (oldWidget.name != widget.name) {
      nameController.text = widget.name ?? '';
    }
  }

  void updateName(String newName) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('name', newName);
    // 通知父组件更新状态
    widget.onNameUpdated(newName);
  }

  // _showEditNameDialog及其他代码保持不变...
}

修改EditProfilePage组件

接收回调更新自身的name状态,确保子组件获取最新值:

class EditProfilePage extends StatefulWidget {
  @override
  _EditProfilePageState createState() => _EditProfilePageState();
}

class _EditProfilePageState extends State<EditProfilePage> {
  String? name = '';
  String? email = '';

  @override
  void initState() {
    super.initState();
    getInfo();
  }

  Future<void> getInfo() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      name = prefs.getString('name');
      email = prefs.getString('email');
    });
  }

  @override
  Widget build(BuildContext context) {
    if (name == null || email == null) {
      return const Center(
        child: SizedBox(
          height: 50.0,
          width: 50.0,
          child: CircularProgressIndicator(),
        ),
      );
    } else {
      return buildPage(context);
    }
  }

  Widget buildPage(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      resizeToAvoidBottomInset: false,
      backgroundColor: AppColors('Default').main2,
      body: Column(children: [
        SizedBox(height: MediaQuery.of(context).padding.top + 10),
        Expanded(
          child: ProfileInfo(
            name: name,
            email: email,
            onNameUpdated: (newName) {
              // 更新自身name状态
              setState(() {
                name = newName;
              });
            },
          ),
        ),
        const Align(alignment: Alignment.bottomCenter, child: Footer(tab: 'More'))
      ]),
    );
  }
}

修复说明

  1. 通过回调实现父子组件状态同步,符合Flutter单向数据流原则。
  2. 利用didUpdateWidget方法确保控制器文本始终与最新名称一致。
  3. 不再直接修改widget属性,避免状态不一致问题。

内容的提问来源于stack exchange,提问作者Cidiko Andorem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:17:03