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

Flutter中TextFormField导致首次导航至LoginView延迟问题求助

Flutter首次导航至含自定义TextFormField的页面延迟问题

问题详情

  • 技术栈:Flutter应用,采用Stacked架构及Stacked Services实现导航
  • 现象:从route1首次导航至LoginView页面时出现约1秒延迟,仅在应用启动后首次出现;退出LoginView后再次导航流畅无延迟;注释掉LoginView中的2个基于TextFormField封装的CommonTextField组件后,导航恢复流畅。

自定义CommonTextField代码

class CommonTextField extends StatelessWidget {
  final TextEditingController? controller;
  final String? labelText;
  final String? fieldHeading;
  final Color? fillcolor;
  final TextStyle? textStyle;
  final Color? bordercolor;
  final bool? isTextHidden;
  final String? hintText;
  final String? prefixIcon;
  final bool? togglePassword;
  final int? maxLength;
  final int? maxlines;
  final void Function()? toggleFunction;
  final String? toggleIcon;
  final TextInputType? keyboardType;
  final void Function()? prefixIconTap;
  final Function(String)? onChanged;
  final FocusNode? focus;
  final double? prefixIconHeihgt;

  const CommonTextField(
      {super.key,
      this.controller,
      this.textStyle,
      this.maxlines = 1,
      this.bordercolor,
      this.labelText,
      this.fillcolor,
      this.hintText,
      this.isTextHidden,
      this.prefixIcon,
      this.onChanged,
      this.togglePassword = false,
      this.toggleFunction,
      this.toggleIcon,
      this.keyboardType,
      this.maxLength,
      this.prefixIconTap,
      this.fieldHeading,
      this.prefixIconHeihgt,
      this.focus});

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: controller,
      style: TextStyles.body,
      onChanged: onChanged,
      obscureText: isTextHidden ?? false,
      maxLength: maxLength,
      cursorColor: AppConstants.primaryColor,
      focusNode: focus,
      keyboardType: keyboardType ?? TextInputType.text,
      textInputAction: TextInputAction.done,
      maxLines: maxlines,
      decoration: InputDecoration(
        counterText: "",
        suffixIcon: toggleIcon != null
            ? GestureDetector(
                onTap: toggleFunction,
                child: Padding(
                    padding: const EdgeInsets.all(AppConstants.space12),
                    child: SvgAsset(src: toggleIcon)))
            : null,
        enabledBorder: const OutlineInputBorder(
          borderSide: BorderSide(
            width: 0.2,
            color: AppConstants.primaryColor,
          ),
          borderRadius: BorderRadius.all(
            Radius.circular(AppConstants.space12),
          ),
        ),
        focusedBorder: const OutlineInputBorder(
          borderSide: BorderSide(
            width: 0.2,
            color: AppConstants.primaryColor,
          ),
          borderRadius: BorderRadius.all(
            Radius.circular(AppConstants.space12),
          ),
        ),
        hintText: hintText,
        fillColor: AppConstants.whiteColor.withOpacity(0.1),
        filled: true,
        hintStyle: TextStyles.body,
        contentPadding:
            const EdgeInsets.symmetric(vertical: 11.0, horizontal: 18.0),
        labelText: labelText,
        labelStyle: TextStyles.body,
      ),
    );
  }
}

解决办法

1. 预加载自定义字体

TextFormField首次渲染时会加载TextStyles.body使用的字体,首次启动时字体未缓存是延迟的常见原因。在应用启动阶段预加载字体:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 替换为你的字体路径
  await Future.wait([
    DefaultAssetBundle.of(WidgetsFlutterBinding.instance.window)
        .load('fonts/your-custom-font.ttf'),
  ]);
  runApp(const MyApp());
}

2. 预缓存SVG资源

如果toggleIcon使用的SVG是首次加载,会增加渲染耗时。在进入LoginView之前(比如route1页面的initState)预缓存SVG:

@override
void initState() {
  super.initState();
  // 替换为你的toggleIcon路径
  precachePicture(
    ExactAssetPicture(SvgPicture.svgStringDecoder, 'assets/icons/toggle-password.svg'),
    context,
  );
}

3. 延迟加载TextField

通过延迟加载避免TextField渲染阻塞导航动画,修改CommonTextField的build方法:

@override
Widget build(BuildContext context) {
  return FutureBuilder(
    future: Future.delayed(const Duration(milliseconds: 100)),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        // 原TextFormField代码
        return TextFormField(
          controller: controller,
          style: TextStyles.body,
          onChanged: onChanged,
          obscureText: isTextHidden ?? false,
          maxLength: maxLength,
          cursorColor: AppConstants.primaryColor,
          focusNode: focus,
          keyboardType: keyboardType ?? TextInputType.text,
          textInputAction: TextInputAction.done,
          maxLines: maxlines,
          decoration: InputDecoration(
            counterText: "",
            suffixIcon: toggleIcon != null
                ? GestureDetector(
                    onTap: toggleFunction,
                    child: Padding(
                        padding: const EdgeInsets.all(AppConstants.space12),
                        child: SvgAsset(src: toggleIcon)))
                : null,
            enabledBorder: const OutlineInputBorder(
              borderSide: BorderSide(
                width: 0.2,
                color: AppConstants.primaryColor,
              ),
              borderRadius: BorderRadius.all(
                Radius.circular(AppConstants.space12),
              ),
            ),
            focusedBorder: const OutlineInputBorder(
              borderSide: BorderSide(
                width: 0.2,
                color: AppConstants.primaryColor,
              ),
              borderRadius: BorderRadius.all(
                Radius.circular(AppConstants.space12),
              ),
            ),
            hintText: hintText,
            fillColor: AppConstants.whiteColor.withOpacity(0.1),
            filled: true,
            hintStyle: TextStyles.body,
            contentPadding:
                const EdgeInsets.symmetric(vertical: 11.0, horizontal: 18.0),
            labelText: labelText,
            labelStyle: TextStyles.body,
          ),
        );
      }
      // 占位Widget,避免布局跳动
      return const SizedBox(
        height: 50, // 匹配TextField高度
      );
    },
  );
}

4. 检查字体配置

确保pubspec.yaml中正确声明了自定义字体,避免字体加载失败或延迟:

flutter:
  fonts:
    - family: YourFontFamily
      fonts:
        - asset: fonts/your-custom-font.ttf

内容的提问来源于stack exchange,提问作者Usman Hafeez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:30:56