为了在日常前端开发中提高效率,我们经常会运用一些常用的技巧和语法糖。这些技巧和语法糖能够简化代码,使得我们能够更加轻松地编写优雅高效的代码。在本文中,我们将分享一些在 Dart 和 Flutter 中常用的小技巧,帮助你更好地应用它们开发。
函数扩展
在 Dart 中,我们可以扩展任何数据类型,将任何函数转换为数据类型。因此,我们也可以在 Dart 中扩展任何类型的函数。通过使用extension
关键字,可以实现函数扩展,用于提高代码的可读性和可维护性。
定义 String 扩展:
extension StringExtensions on String { String capitalize() { if (isEmpty) { return this; } return substring(0, 1).toUpperCase() + substring(1); } }
调用扩展:
class DartTipsPage extends StatefulWidget { const DartTipsPage({Key? key}) : super(key: key); @override State<DartTipsPage> createState() => _DartTipsPageState(); } class _DartTipsPageState extends State<DartTipsPage> { @override void initState() { super.initState(); String text = "hello"; print(text.capitalize()); // "Hello" } }
我们还可以直接创建 extensions
到函数类型,以在函数之上添加功能。例如,将延迟调用功能添加到函数类型。
extension on VoidCallback { Future<void> delayedCall( Duration duration, ) => Future<void>.delayed(duration, this); }
class DartTipsPage extends StatefulWidget { const DartTipsPage({Key? key}) : super(key: key); @override State<DartTipsPage> createState() => _DartTipsPageState(); } class _DartTipsPageState extends State<DartTipsPage> { @override void initState() { super.initState(); _click.delayedCall(const Duration(seconds: 1)); } _click(){ print("delayedCall"); } }
这里的
VoidCallback
是一个已转换为数据类型的函数类型,因此我们也可以向其添加扩展。
Secure array
在 Flutter 开发过程中,遇到数组越界或访问不存在的数组元素会导致运行时错误。
List<int> numbers = [1, 2, 3, 4, 5]; print(numbers[5]);
尝试访问索引为 5 的元素,但数组长度仅为 5 个元素,将触发数组越界错误, Flutter
错误消息:
RangeError (index): Index out of range: index should be less than 5: 5
为了避免这种情况,我们可以自定义一个安全的数组类 SafeList,继承自 ListBase,用于处理数组越界情况。
class SafeList<T> extends ListBase<T> { final List<T> _list; // 调用 set 方法修改 length 的时候,若大于当前数组的长度时,就使用 defaultValue 填充 final T defaultValue; // 在数组中查询不存在的值时,即数组越界时,返回 absentValue final T absentValue; SafeList({ required this.defaultValue, required this.absentValue, List<T>? values, }) : _list = values ?? []; @override T operator [](int index) => index < _list.length ? _list[index] : absentValue; @override void operator []=(int index, T value) => _list[index] = value; @override int get length => _list.length; @override T get first => _list.isNotEmpty ? _list.first : absentValue; @override T get last => _list.isNotEmpty ? _list.last : absentValue; @override set length(int newValue) { if (newValue < _list.length) { _list.length = newValue; } else { _list.addAll(List.filled(newValue - _list.length, defaultValue)); } } }
调用:
const notFound = 'Value Not Found'; const defaultString = ''; final SafeList<String> myList = SafeList( defaultValue: defaultString, absentValue: notFound, values: ['Flutter', 'iOS', 'Android'], ); print(myList[0]); // Flutter print(myList[1]); // iOS print(myList[2]); // Android print(myList[3]); // Value Not Found myList.length = 5; print(myList[4]); // '' myList.length = 0; print(myList.first); // Value Not Found print(myList.last); // Value Not Found
获取图像宽高比
在 Flutter 开发中,经常需要获取图像的宽高比,特别是在需要设置图像宽高时。我们可以通过 Completer 和 ImageStreamListener 来处理获取图像宽高比的需求。
定义:
import 'dart:async' show Completer; import 'package:flutter/material.dart' as material show Image, ImageConfiguration, ImageStreamListener; extension GetImageAspectRatio on material.Image { Future<double> getAspectRatio() { final completer = Completer<double>(); image.resolve(const material.ImageConfiguration()).addListener( material.ImageStreamListener( (imageInfo, synchronousCall) { final aspectRatio = imageInfo.image.width / imageInfo.image.height; imageInfo.image.dispose(); completer.complete(aspectRatio); }, ), ); return completer.future; } }
调用:
class _DartTipsPageState extends State<DartTipsPage> { @override void initState() { super.initState(); _getImageAspectRatio(); // 打印结果:2.8160919540229883 } _getImageAspectRatio() async { Image wxIcon = Image.asset("images/wx_icon.png"); var aspectRatio = await wxIcon.getAspectRatio(); print(aspectRatio); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xffffffff), ); } }
自动添加间距
在 Flutter 中,当需要在 Row 或 Column 中为元素之间添加相同的间距时,通常会写出大量重复的代码。
Row( crossAxisAlignment = CrossAxisAlignment.center, mainAxisAlignment = MainAxisAlignment.center, children = [ _hasFirstSpacing ? SizedBox(width: 20,) : Container(), Text("Flutter"), SizedBox(width: 20,), Text("ReactNative"), SizedBox(width: 20,), Text("uni-app"), ], ),
我们可以创建一个自动添加间距的自定义类 RowWithSpacing 来简化代码。
class RowWithSpacing extends Row { RowWithSpacing({ super.key, double spacing = 8, // 是否需要在开头添加间距 bool existLeadingSpace = false, super.mainAxisAlignment, super.mainAxisSize, super.crossAxisAlignment, super.textDirection, super.verticalDirection, super.textBaseline, List<Widget> children = const [], }) : super( children: [ ...existLeadingSpace ? [SizedBox(width: spacing)] : <Widget>[], ...children.expand( (w) => [ w, SizedBox(width: spacing), ], ) ], ); }
调用:
RowWithSpacing( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, existLeadingSpace: true, spacing: 20, children: [ Text("Flutter"), Text("ReactNative"), Text("uniapp"), ], ),
以上就是关于前端 Dart 和 Flutter 开发小技巧,希望通过应用这些小技巧,你将能够更加高效地开发 Dart 和 Flutter 应用程序,写出优雅可维护的代码。