Flutter 使用技巧

91 阅读2分钟

本地存储

场景:flutter编译为H5时,从本地存储中读取数据
// WebViewController 中存储
final Map<String, dynamic> data = {
  "name": "Some Name",
  "id": "666",
};
final String jsonString = json.encode(data);
// 这里可以在取名上做区分:web.data
final script = "window.sessionStorage.setItem('web.data', JSON.stringify($jsonString));";
controller.runJavaScript(script);

// flutter中取出使用
final data = html.window.sessionStorage["web.data"];
if (data != null) {
  final Map<String, dynamic> jsonData = json.decode(data);
  final String name = jsonData["name"];
  final String id = jsonData["id"];
}

按钮置于底部

Spacer 可以灵活配置你的Row/Column

官方文档中描述:Spacer创建一个可调整的空间隔,可用于调整Flex容器(如行或列)中窗口小部件之间的间距。

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: "按钮置于底部",
    ),
    body: SafeArea(
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            const SizedBox(height: 20),
            // some widget ...
            const Spacer(),
            CustomButton.normal(
              text: "按钮",
              onPressed: () => {
                  // do something...
              }),
            ),
          ],
        ),
      ),
    ),
  );
}

相关文档:
Dart API
Flutter Spacer
Flutter Spacer教程

输入框赋值

TextEditingController someController = TextEditingController();

TextFormField(
  controller: securitiesIdController,
  onChanged: (text) {
    // 处理文本变化
    someController.value = someController.value.copyWith(
      text: text,
    );
  },
),

// 注意不要在onChanged回调中处理文本变化:
// 在onChanged回调中,确保只将文本内容设置回TextEditingController,
// 而不是直接将整个text参数赋值给TextEditingController。这可以避免循环更新的问题。
// 错误示范
TextFormField(
  controller: securitiesIdController,
  onChanged: (text) {
    someController.text = text;
  },
),

后台倒计时

Timer有个属性:tick
既使callback停止回调了,tick也是一直在累加的。
利用这个tick,只需要一行代码就可以解决此问题:

int _resCount = 60;
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
    setState(() {
        _resCount = 60 - timer.tick
    })
});

点击按钮时隐藏键盘

给输入框添加focusNode属性;
并在按钮点击事件中调用方法:FocusScope.of(context).unfocus();

FocusNode _focusNode = FocusNode();

TextField(
  focusNode: _focusNode,
  // 其他属性...
)

ElevatedButton(
  onPressed: () {
    FocusScope.of(context).unfocus();
    // 处理按钮点击事件
  },
  child: Text('按钮'),
)

横向滚动-禁止弹性效果

ScrollController _scrollController = ScrollController();

CupertinoScrollbar(
  controller: _scrollController,
  child: SingleChildScrollView(
    controller: _scrollController,
    physics: const ClampingScrollPhysics(),
    child: Column(
      children: [
        // Your content here
      ],
    ),
  ),
),

父组件调用子组件方法

/// 父组件
class FatherPage extends StatefulWidget {
  const FatherPage({Key? key}) : super(key: key);

  @override
  State<FatherPage> createState() => _FatherPageState();
}

class _FatherPageState extends State<FatherPage> with SingleTickerProviderStateMixin {
  // 使用 GlobalKey 来获取对’子组件’的引用
  final GlobalKey<SonPageState> _SonPageStateKey = GlobalKey<SonPageState>();
  
  // 父组件方法
  void faSomeFun() {
    // 调用子组件的方法
    _SonPageStateKey.currentState?.someFun(),
  );

  @override
  Widget build(BuildContext context) {
    return Column(
        children: [
            SonPage(
              // 给子组件添加key
              key: _SonPageStateKey,
            ),
        ]
    )
  }

}

/// 子组件
class SonPageState extends StatefulWidget {
  const SonPageState({Key? key}) : super(key: key);

  @override
  State<SonPageState> createState() => SonPageStateState();
}

class SonPageStateState extends State<SonPageState> {
  // 需要被调用的方法
  void someFun() {
    // 做一些事
  }

  @override
  Widget build(BuildContext context) {
    return // some widget
  }
}

报错集合

// 1
// pub finished with exit code 78
// flutter pub run build_runner build 时报错
// 解决:
flutter packages pub run build_runner build --delete-conflicting-outputs