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

Flutter切换页面时保持TextField输入值不变的实现问题

Flutter页面切换时保留TextField输入内容解决方案

我已经在Flutter中实现了ExpenseScreen和IncomeScreen两个页面,通过切换按钮可以在两个页面间来回跳转。现在需要实现切换页面时,页面中金额输入框TextField的内容保持不变。以下是我的主文件代码和ExpenseScreen代码(IncomeScreen与前者基本一致),要求不使用自定义Widget解决该问题。

原主文件代码

class _MyAppState extends State<MyApp> {
  bool isexpense=true;

  void toogleit()
  {
    setState(() {
      isexpense=!isexpense;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: isexpense==true? ExpenseScreen(ontap: toogleit,txtvalue: '',):IncomeScreen(ontap: toogleit,txtvalue: '',)
    );
  }
}

原ExpenseScreen代码

class ExpenseScreen extends StatefulWidget {
  final VoidCallback ontap;
  String txtvalue;
  ExpenseScreen({Key? key, required this.ontap,required this.txtvalue}) : super(key: key);

  @override
  State<ExpenseScreen> createState() => _ExpenseScreenState();
}

class _ExpenseScreenState extends State<ExpenseScreen> {
  TextEditingController txtcontroller = TextEditingController();

  @override
  void initState() {
    super.initState();
    txtcontroller.text=widget.txtvalue;
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20.0),
          child: Container(
            height: 300,
            decoration: kboxdecoration1,
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  IntrinsicWidth(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 40.0),
                      child: TextField(
                        onChanged: (x) {
                          setState(() {

                          });
                        },
                        controller: txtcontroller,
                        keyboardType: TextInputType.number,
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          fontSize: 30,
                        ),
                        decoration: kinputdecoration1.copyWith(
                            hintText:
                            txtcontroller.text == '' ? 'Amount' : null),
                      ),
                    ),
                  ),
                  SizedBox(
                    height: 10,
                  ),
                  ElevatedButton(
                      style: kelevetedbutton1,
                      onPressed: () {},
                      child: Text('Save Expense')),
                  SizedBox(
                    height: 10,
                  ),
                  TextButton(
                      onPressed: widget.ontap, child: Text('Jump To Income')),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

解决方案

问题根源在于当前切换页面时,每次都会重新创建页面实例,且传入的txtvalue是空字符串,导致输入内容无法保留。我们需要在父组件中维护两个页面的输入值,切换时传递对应的值,并在页面输入变化时同步更新父组件的存储值。

修改后的主文件代码

class _MyAppState extends State<MyApp> {
  bool isexpense = true;
  // 分别存储支出和收入页面的输入内容
  String expenseInput = '';
  String incomeInput = '';

  void toggleIt() {
    setState(() {
      isexpense = !isexpense;
    });
  }

  // 更新支出输入内容的回调
  void updateExpenseInput(String value) {
    setState(() {
      expenseInput = value;
    });
  }

  // 更新收入输入内容的回调
  void updateIncomeInput(String value) {
    setState(() {
      incomeInput = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: isexpense
          ? ExpenseScreen(
              ontap: toggleIt,
              txtvalue: expenseInput,
              onInputChanged: updateExpenseInput,
            )
          : IncomeScreen(
              ontap: toggleIt,
              txtvalue: incomeInput,
              onInputChanged: updateIncomeInput,
            ),
    );
  }
}

修改后的ExpenseScreen代码

class ExpenseScreen extends StatefulWidget {
  final VoidCallback ontap;
  final String txtvalue;
  // 添加输入变化的回调,用于同步到父组件
  final Function(String) onInputChanged;

  ExpenseScreen({
    Key? key,
    required this.ontap,
    required this.txtvalue,
    required this.onInputChanged,
  }) : super(key: key);

  @override
  State<ExpenseScreen> createState() => _ExpenseScreenState();
}

class _ExpenseScreenState extends State<ExpenseScreen> {
  late TextEditingController txtcontroller;

  @override
  void initState() {
    super.initState();
    txtcontroller = TextEditingController(text: widget.txtvalue);
  }

  @override
  void didUpdateWidget(covariant ExpenseScreen oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 当父组件传递的txtvalue变化时,更新控制器内容
    if (oldWidget.txtvalue != widget.txtvalue) {
      txtcontroller.text = widget.txtvalue;
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      body: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20.0),
          child: Container(
            height: 300,
            decoration: kboxdecoration1,
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  IntrinsicWidth(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 40.0),
                      child: TextField(
                        onChanged: (x) {
                          // 输入变化时调用回调,同步到父组件
                          widget.onInputChanged(x);
                        },
                        controller: txtcontroller,
                        keyboardType: TextInputType.number,
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          fontSize: 30,
                        ),
                        decoration: kinputdecoration1.copyWith(
                          hintText: txtcontroller.text == '' ? 'Amount' : null,
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 10),
                  ElevatedButton(
                    style: kelevetedbutton1,
                    onPressed: () {},
                    child: const Text('Save Expense'),
                  ),
                  const SizedBox(height: 10),
                  TextButton(
                    onPressed: widget.ontap,
                    child: const Text('Jump To Income'),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

IncomeScreen修改说明

IncomeScreen的修改逻辑和ExpenseScreen完全一致:

  1. 添加final Function(String) onInputChanged参数
  2. 在TextField的onChanged中调用widget.onInputChanged(x)
  3. 实现didUpdateWidget方法同步父组件传递的输入值

这样切换页面时,两个页面的输入内容都会被父组件保存,再次切换回来时会自动恢复之前的输入内容。

内容的提问来源于stack exchange,提问作者Irfan Ganatra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:42:03