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

Flutter中TextFormField点击后键盘不弹出问题求助

Flutter TextFormField点击后键盘无法弹出的问题

点击TextFormField准备输入时,键盘无法弹出。已尝试以下方案均无效:

  • 在无状态组件与有状态组件间相互转换
  • 在导入后、Cubit文件、共享文件中声明全局TextEditingController
  • 不使用Form组件
  • 移除onFieldSubmitted属性
  • 执行flutter run --release命令但终端无输出
  • 检查Google Play控制台的崩溃日志

搜索页面代码

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

  @override
  State<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    var width = size.width;
    return BlocConsumer<HomeCubit, HomeStates>(
      listener: (context, state) {},
      builder: (context, state) {
        var cubit = HomeCubit.get(context);
        return Directionality(
          textDirection: TextDirection.rtl,
          child: Scaffold(
            body: SingleChildScrollView(
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 10.0),
                    child: Row(
                      children: [
                        // which zone text
                        SizedBox(
                          width: width * .30,
                          child: FittedBox(child: Text('اختر المنطقة',style: TextStyle(fontSize: 24,fontWeight:FontWeight.normal))))
                        const SizedBox(width: 25.0),
                        Expanded(
                          child: Center(
                            child: DropdownButton(
                              alignment: Alignment.center,
                              value: cubit.zonePopupValue,
                              hint: const Text('كل المناطق', textAlign: TextAlign.center),
                              style: TextStyle(
                                color: HexColor('#ECB365'),
                                fontSize:  24,
                                fontWeight: FontWeight.normal,
                              ),
                              items: cubit.list,
                              onChanged: (value) => cubit.changePopupZoneValue(int.parse(value.toString())),
                            ),
                          ),
                        ),
                      ],
                    )
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 10),
                    child: TextFormField(
                      textInputAction: TextInputAction.search,
                      onFieldSubmitted: (_) async => cubit.search(),
                      controller: cubit.searchController,
                      keyboardType: TextInputType.text,
                      maxLines: 1,
                      maxLength: 100,
                      textAlign: TextAlign.right,
                      textDirection: TextDirection.rtl,
                      decoration: InputDecoration(
                        contentPadding: const EdgeInsets.only(right: 20, left: 10),
                        labelText: "إبحث",
                        alignLabelWithHint: true,
                        labelStyle: TextStyle(
                          color: HexColor('#ECB365'),
                          fontSize: 24,
                          fontWeight: FontWeight.normal,
                        ),
                        suffixIcon: cubit.isLoadingAuth? CircularProgressIndicator(color: HexColor('#ECB365')): IconButton(
                          onPressed: () => cubit.search(),
                          icon: Icon(Icons.search,color: HexColor('#ECB365')),
                          iconSize: 35,
                          color: HexColor('#081C31'),
                        ),
                        border: OutlineInputBorder(borderSide:BorderSide(color: HexColor('#ECB365'))),
                        focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: HexColor('#ECB365'))),
                        enabledBorder: OutlineInputBorder(borderSide:BorderSide(color: HexColor('#ECB365'))),
                        fillColor: HexColor('#ECB365')
                      ),
                    )
                  ),
                  Container(
                    margin: const EdgeInsets.only(left: 10.0, right: 20.0),
                    child: const Divider(color: Colors.black,height: 36)
                  ),
                  cubit.responseBodySearch == null
                    ? const Center(child: Text("أبدأ البحث"))
                    : cubit.responseBodySearch.isEmpty
                    ? const Center(child: Text("غير متوفر حاليا"))  
                    : ListView.builder(
                      physics: const NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: cubit.responseBodySearch!.length,
                      itemBuilder: (context, index) => buildSearchItem(cubit, context, index)
                    )
                ],
              ),
            ),
          )
        );
      }
    );
  }
}

HomeCubit代码

class HomeCubit extends Cubit<HomeStates> {
  HomeCubit() : super(HomeInitState());

  static HomeCubit get(context) => BlocProvider.of(context);

  String api = 'https://hadayekhof.com/dalel/api/';

  var searchController = TextEditingController();

  int? zonePopupValue;
  void changePopupZoneValue(int value) {
    zonePopupValue = value;
    getCategoriesData(zoneIds[value].toString());
    emit(HomeChangePopupButtonState());
  }

  var responseBodySearch;
  Future search() async {
    emit(HomeSearchLoadingState());
    responseBodySubCategories = null;
    var data = {
      'zone_id':  zonePopupValue == null ? '' : zoneIds[zonePopupValue!].toString(),
      // 'parent_cat': categoryPopupValue == null ? '' : categoryIds[categoryPopupValue!].toString(),
      'term': searchController.text.toString()
    };
    var uri = Uri.parse('${api}stores/searchStores');
    var header = {'Authorization': 'Bearer $ciphertext'};
    if (searchController.text == '') {
      Fluttertoast.showToast(msg: 'من فضلك اكتب شئ');
    } else {
      await http.post(uri, body: data, headers:header ).then((value) async {
        responseBodySearch = await jsonDecode(value.body);
        if (value.body.toString().contains('[') == false) {
          responseBodySearch = null;
          Fluttertoast.showToast(msg: 'no stores found');
        }
        emit(HomeSearchSuccessState());
      }).catchError((error) {
        debugPrint("search error is : $error");
        emit(HomeSearchErrorState());
      });
    }
  }
}

排查与解决方案

  1. 调整TextEditingController初始化逻辑
    Cubit中直接初始化searchController可能导致生命周期不匹配,建议在Cubit构造函数内初始化,或者在SearchScreen的initState中创建控制器并与Cubit关联,避免全局控制器绑定异常。

  2. 手动控制焦点获取
    给TextFormField添加FocusNode,强制请求焦点:

    final FocusNode _searchFocusNode = FocusNode();
    
    @override
    void dispose() {
      _searchFocusNode.dispose();
      super.dispose();
    }
    
    // 绑定到TextFormField
    TextFormField(
      focusNode: _searchFocusNode,
      onTap: () {
        FocusScope.of(context).requestFocus(_searchFocusNode);
      },
      // 其他属性...
    )
    
  3. 检查Scaffold布局属性
    确保Scaffold未设置resizeToAvoidBottomInset: false,该属性会阻止页面适配键盘,可能间接导致键盘无法弹出。

  4. 优化Bloc重建范围
    Bloc状态更新会触发builder重建,若重建频繁可能导致TextFormField失焦。将TextFormField部分提取为独立StatefulWidget,或用const关键字减少不必要的组件重建。

  5. 测试极简场景
    创建仅包含TextFormField和控制器的测试页面,验证键盘是否正常弹出。若正常,再逐步添加Bloc、DropdownButton等元素,定位冲突点。

  6. 检查设备输入法设置
    确认设备/模拟器的输入法未被禁用,比如iOS模拟器需关闭硬件键盘,Android设备需确保默认输入法正常工作。

内容的提问来源于stack exchange,提问作者Saayeed M Daawoud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:50:37