flutter疑难杂症

730 阅读5分钟

其他杂项

Flutter解决两个组件之间出现间隙的问题

键盘问题

Flutter 疑难杂症系列:键盘原理及常见问题解决方案 - 掘金 (juejin.cn)

延时执行的2种方式

Future.delayed(const Duration(milliseconds: 3000), () { 
    //延时执行的代码 
    print("3秒后执行"); 
});
Timer(Duration(seconds: 3), () {
  //延时执行的代码
   print("3秒后执行");
});

页面绘制完毕的回调钩子

@override
void initState() {
  WidgetsBinding.instance.addPostFrameCallback((_){
    /// 接口请求
  });
}

Flutter Tips 小技巧(更新中) - 掘金 (juejin.cn)

宽高不统一的布局开发

Flutter 搞定宽高不统一的布局开发 - 掘金 (juejin.cn)

字体问题

image.png

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

class TextDemo extends StatelessWidget {
  const TextDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(
            '文本示例',
            style: const TextStyle().useSystemChineseFont(),
          ),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text(
                '123单ajiLgzZAB个1296内容ajiLgzZAB(不使用本地字体)',
                style: TextStyle(fontSize: 20),
              ),
              Text(
                '123单ajiLgzZAB个1296内容ajiLgzZAB(用本地默认字体)',
                style: const TextStyle(fontSize: 20).useSystemChineseFont(),
              ),
              Text(
                '123单ajiLgzZAB个1296内容ajiLgzZAB',
                style:
                    const TextStyle(fontSize: 20, backgroundColor: Colors.blue)
                        .useSystemChineseFont(),
              ),
              Text(
                '123单ajiLgzZAB个1296内容ajiLgzZAB(解决不同类型字符之间行高不一致问题)',
                style: const TextStyle(
                        fontSize: 20, backgroundColor: Colors.red, height: 1.5)
                    .useSystemChineseFont(),
              ),
              DecoratedBox(
                  decoration: const BoxDecoration(
                    color: Colors.green,
                  ),
                  child: Text(
                    '123单ajiLgzZAB个1296内容ajiLgzZAB(解决设置背景色后,中文字符与其他字符之间有白色间隙问题)',
                    style: const TextStyle(fontSize: 20, height: 1.5)
                        .useSystemChineseFont(),
                  )),
              DecoratedBox(
                decoration: const BoxDecoration(color: Colors.blueGrey),
                child: Text.rich(TextSpan(
                    style: const TextStyle(fontSize: 20, height: 1.5),
                    children: [
                      const TextSpan(text: '多节文本'),
                      TextSpan(
                          text: '123',
                          style: TextStyle(
                                  fontSize: 30,
                                  foreground: Paint()..color = Colors.red)
                              .useSystemChineseFont()),
                      TextSpan(
                          text: '多节文本',
                          style: const TextStyle().useSystemChineseFont()),
                      const TextSpan(text: 'ajiLgzZAB'),
                      const TextSpan(text: '多节文本'),
                    ])),
              ),
              const SizedBox(
                width: 100,
                child: Text(
                  '很长很长很长很长很长很长很长',
                  style: TextStyle(overflow: TextOverflow.ellipsis),
                ),
              )
            ],
          ),
        ));
  }
}

不同文字垂直对齐问题(如:中/英文,数字,标点符号)

设置统一的height, flutter中的height值,是一个比例值,最终的文字高度是fontSize * height

image.png

image.png 文字占据的实际高度(lineHeight)是多少?

文字实际占据的高度= fontSize占据的高度 + 上/下leading占据的高度

Flutter 小技巧之玩转字体渲染和问题修复 - 掘金 (juejin.cn)

这一次,彻底弄懂line-height和vertical-align - 掘金 (juejin.cn)

文字渲染时,flutter如何选择字体

image.png

  1. 先在fontFamily指定的字体中找,是否有当前需要渲染的文字
  2. 如有,则使用fontFamily字体中的文字渲染
  3. 如果没有,则使用fontFamilyFallback字体中找对应的文字
  4. 如果fontFamilyFallback中也找不到对应的文字,则采用系统默认字体
  5. 如果系统默认字体中也找不到对应的文字,则渲染不出来

Flutter 小技巧之玩转字体渲染和问题修复 - 掘金 (juejin.cn)

Flutter - Using StrutStyle Widget Examples - Woolha

image.png

chinese_font_library | Flutter Package (flutter-io.cn)

Text组件中文与其他文字/字符之间会有白色间隙

03b7b8c46bbce57c9ec3c8e5fc724ba.jpg

字的左右两侧都有根竖线。

解决方案: 不要直接设置Text组件的背景颜色,使用装饰盒子(DecoratedBox)对Text进行一层包裹,然后设置DecoratedBox的背景色,来代替Text的背景色,中文字符与其他字符之间就不会有间隙导致的白色竖线了。

flutter 两个Container交界处出现白线的解决

flutter 两个Container交界处出现白线的解决_flutter container 缝隙-CSDN博客

flutter两个container之间出现分隔线_flutter row container 间隙-CSDN博客

GitHub - erlangparasu/space_fixer: space_fixer: Hide unexpected gap between widgets (nuaa.cf)

使用了某些自定义的字体之后,文字下面自动加了下划线

Flutter Text文字下方出现黄色双下划线 - 掘金 (juejin.cn)

android平台

用户在多个TextField之间切换时,TextField可能会因为键盘类型的不同而失去焦点

解决方案伪代码

class _FormTextFieldState extends State<FormTextField> {
    final FocusNode _accountFocusNode = FocusNode();
    
    @override
    Widget build(BuildContext context) {
        Widget textField = TextField(
            focusNode: _pwdFocusNode,
            keyboardType: TextInputType.visiblePassword,
            obscureText: true,
            decoration:
                const InputDecoration(labelText: '密码', hintText: '请输入密码'),
        )
        if(Platform.isAndroid){
          // 是android平台,则使用Listener对TextField进行一次包装,并加入onPointerDown事件监听,事件触发时,再次强制TextField获取焦点
          textField = Listener(
              onPointerDown: (e) => FocusScope.of(context).requestFocus(_pwdFocusNode),
              child: textField
          )
        }
        return textField;
    }
}

Flutter 触摸事件监听 Listener 、手势识别示例_flutter判断当前触控有几个手指-CSDN博客

flutter帮助方法

将指定大小的数组转换为组件

int widgetCount = 30;
final List<Widget> list = List.generate(
            widgetCount,
            (index) => Container(
                  width: size,
                  height: size,
                  decoration: const BoxDecoration(color: Colors.red),
                  alignment: Alignment.center,
                  child: Text(
                    '$index',
                    style: const TextStyle(color: Colors.white, fontSize: 30),
                  ),
                ),
            growable: true)
        .toList();

sliver布局

异常:

══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown while notifying status listeners for AnimationController:
The Scrollbar's ScrollController has no ScrollPosition attached.
A Scrollbar cannot be painted without a ScrollPosition.
The Scrollbar attempted to use the provided ScrollController. This ScrollController should be
associated with the ScrollView that the Scrollbar is being applied to.When providing your own
ScrollController, ensure both the Scrollbar and the Scrollable widget use the same one.

原因: Scrollbar和ScrollView组件都要求提供ScrollController实例,并且这两者要求必须是同一个ScrollController示例

解决方案:

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

class SingleChildScrollViewDemo extends StatelessWidget {
  final ScrollController controller = ScrollController();
  SingleChildScrollViewDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Widget> childrenList = List.generate(
        25,
        (index) => Container(
              width: 150,
              height: 150,
              alignment: Alignment.center,
              decoration: const BoxDecoration(color: Colors.pink),
              child: Text(
                '$index',
                style: const TextStyle(fontSize: 20).useSystemChineseFont(),
              ),
            ),
        growable: true);
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'single child scroll view 示例',
          style: const TextStyle().useSystemChineseFont(),
        ),
      ),
      body: Scrollbar(
          // 给Scrollbar指定ScrollController实例
          controller: controller,
          child: SingleChildScrollView(
            //这里的ScrollView就是SingleChildScrollView,因此这个也需要指定ScrollController实例,且必须与对应的Scrollbar中提供的controller是同一个实例
            controller: controller,
            scrollDirection: Axis.horizontal,
            // padding: const EdgeInsets.all(10),
            child: Center(
                child: Row(
              children: childrenList,
            )),
          )),
    );
  }
}

滚动容器中多个子盒子之后,各个盒子之间有白色细线

image.png

错误代码示例

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

class SingleChildScrollViewDemo extends StatelessWidget {
  final ScrollController controller = ScrollController();
  SingleChildScrollViewDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Widget> childrenList = List.generate(
        25,
        (index) => Container(
              width: 150,
              height: 150,
              alignment: Alignment.center,
              // 不应该给子盒子设置背景色,因为连续的盒子之间可能会出现一丝间隙,如上图所示
              decoration: const BoxDecoration(color: Colors.pink),
              child: Text(
                '$index',
                style: const TextStyle(fontSize: 20).useSystemChineseFont(),
              ),
            ),
        growable: true);
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'single child scroll view 示例',
          style: const TextStyle().useSystemChineseFont(),
        ),
      ),
      body: Scrollbar(
          controller: controller,
          child: SingleChildScrollView(
            controller: controller,
            scrollDirection: Axis.horizontal,
            // padding: const EdgeInsets.all(10),
            child: Center(
                child: Row(
                children: childrenList,
              )),
          )),
    );
  }
}

解决方案: 这里期望的是没有细线,因此不要给子盒子设置背景,而是给大盒子设置背景色

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

class SingleChildScrollViewDemo extends StatelessWidget {
  final ScrollController controller = ScrollController();
  SingleChildScrollViewDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Widget> childrenList = List.generate(
        25,
        (index) => Container(
              width: 150,
              height: 150,
              alignment: Alignment.center,
              // 去掉子盒子的背景色,而改为在大盒子设置背景色,避免造成整体的割裂感
              // decoration: const BoxDecoration(color: Colors.pink),
              child: Text(
                '$index',
                style: const TextStyle(fontSize: 20).useSystemChineseFont(),
              ),
            ),
        growable: true);
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'single child scroll view 示例',
          style: const TextStyle().useSystemChineseFont(),
        ),
      ),
      body: Scrollbar(
          controller: controller,
          child: SingleChildScrollView(
            controller: controller,
            scrollDirection: Axis.horizontal,
            // padding: const EdgeInsets.all(10),
            child: Center(
                child: DecoratedBox(
                // 给大盒子设置背景色,子盒子不设置背景色,这样子盒子的间隙就看不出来了
              decoration: const BoxDecoration(color: Colors.pink),
              child: Row(
                children: childrenList,
              ),
            )),
          )),
    );
  }
}

效果如下

image.png

ListView中shrinkWrap作用

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性 - 掘金 (juejin.cn)

参考资料

【Flutter】实战问题集锦(一) - 掘金 (juejin.cn)

Flutter 搞定宽高不统一的布局开发 - 掘金 (juejin.cn)