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

Android Studio Flutter下TextFormField输入值无法更新变量问题求助

问题解决方案

核心问题点

  • TextFormField的onSaved回调不会自动执行,必须将输入控件包裹在Form组件内,主动调用Form状态的save()方法才会触发该回调
  • 你当前的代码没有使用Form组件包裹输入框,也没有主动触发保存逻辑,所以_valueAlarm变量始终不会更新
  • onSaved回调拿到的输入值是String类型,直接强转为int会抛出类型异常,需要显式做类型转换

实现步骤

  1. 为Form组件创建全局唯一的Key,用于后续操作Form状态
  2. 将输入框包裹在Form组件中,绑定刚才创建的Key
  3. 点击启动按钮时,先校验输入合法性,校验通过后执行保存操作,再触发闹钟逻辑
  4. 修正onSaved中的类型转换逻辑

修正后完整代码

import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  bool isOn = false;
  int alarmId = 1;
  final _controller = TextEditingController();
  // 新增Form的全局Key
  final _formKey = GlobalKey<FormState>();
  int _valueAlarm = 0;
  var now = DateTime.now();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Alarm',
          style: TextStyle(fontSize: 30.0,),
        ),
        centerTitle: true,
      ),
      body: Column(
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(50.0),
            // 输入框包裹在Form组件内
            child: Form(
              key: _formKey,
              child: minAlarmFormField(context),
            ),
          ),
          startButton()
        ],
      ),
    );
  }

  TextFormField minAlarmFormField(BuildContext context) {
    return TextFormField(
      controller: _controller,
      keyboardType: TextInputType.number,
      textInputAction: TextInputAction.next,
      validator: (value){
        if(value == null || value.isEmpty){
          return '请输入分钟数';
        }
        int? inputNum = int.tryParse(value);
        if(inputNum == null || inputNum < 0 || inputNum >59){
          return '请输入0-59之间的整数';
        }
        return null;
      },
      onSaved: (value) {
        // 修正类型转换逻辑
        _valueAlarm = int.parse(value!);
      },
      decoration: const InputDecoration(
        hintText: 'e.g.) 55',
        labelText: 'Minute',
      ),
    );
  }

  ElevatedButton startButton(){
    return ElevatedButton(
      onPressed: () async {
        // 先校验输入,再执行保存
        if(_formKey.currentState!.validate()){
          _formKey.currentState!.save();
          print("alarm start at ${DateTime.now()}");
          print("minAlarm value is $_valueAlarm");
          await AndroidAlarmManager.oneShot(
            Duration(minutes: _valueAlarm),
            alarmId,
            fireAlarm,
            exact: true,
            wakeup: true,
          );
        }
      },
      child:const Text(
        'Start',
        style: TextStyle(fontSize: 17.0),
      ),
    );
  }

}

void fireAlarm() {
  print('Alarm Fired at ${DateTime.now()}');
  FlutterRingtonePlayer.play(
    android: AndroidSounds.notification,
    ios: IosSounds.glass,
    looping: false,
    volume: 0.5,
    asAlarm: true,
  );
}

可选简化方案

如果你不需要用到Form的校验能力,也可以直接在点击按钮时读取输入框控制器的值,不用依赖onSaved回调:

// 按钮点击逻辑直接修改为
onPressed: () async {
  int? inputNum = int.tryParse(_controller.text);
  if(inputNum != null && inputNum >=0 && inputNum <=59){
    _valueAlarm = inputNum;
    // 后续闹钟逻辑
  }
}

内容的提问来源于stack exchange,提问作者Tyler E

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 07:24:07