五个你所不知道的Flutter开发细节

6,382 阅读3分钟

一、利用IDE高效组合Widget

在Flutter中,UI的构建是通过Widget的层层嵌套实现的,开发过程中不可避免地需要频繁修改Widget树,从中插入或者移除一些Widget。

除了手动写代码和剪切粘贴去修改Widget树之外,在Android Studio和Visual Studio Code中,你还有更高效的方法可以使用:

  • 在Android Studio中

Android Studio

  • 在Visual Studio Code中

Visual Studio Code

二、理解下划线开头命名的含义

Flutter所使用的Dart语言,没有类似Java的publice protect private,以_开头的变量、函数和类,意味着它仅在库中是可视的

Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore (_) are visible only inside the library.出处

观察以下几个例子,加深理解:

  • 变量

name变量以_开头后,虽然都是继承于Fruit,但是由于Apple不在同一库中,因此它无法访问父类的name属性。

  • 函数

getName方法以_开头后,虽然都是继承于Fruit,但是由于Apple不在同一库中,因此它无法访问父类的getName方法,也无须实现它。

Banana类可以访问在同一个库中的_Fruit类,但是由于Apple不在同一库中,因此它无法访问_Fruit类。

三、区别final与const

在Dart中,当你不需要去改变一个变量的时候,应该使用final或者const,而不是使用var去声明一个变量。

一个final变量只允许被赋值一次,必须在定义时或者构造函数参数表中将其初始化。

const所修饰的是编译时常量,我们在编译时就已经知道了它的值,它的值是不可改变的。

它们的区别就在于,const比final更加严格,看以下几个例子:

final List<String> list = [];
list.add('1'); // 正确

const List<String> list = [];
list.add('1'); // 错误,运行时报错:Cannot add to an unmodifiable list
final timestamp = new DateTime.now().millisecondsSinceEpoch; // 正确

const timestamp = new DateTime.now().millisecondsSinceEpoch; 
// 错误,编译前报错:Const variables must be initialized with a constant value

官方文档

四、使用Debug Painting调试界面

Flutter提供的Debug Painting可以很方便地协助我们观察界面的布局,调试界面的开发

在Android Studio和Visual Studio Code中都有提供开关去显示或隐藏Debug Painting(前提是App处于调试运行状态):

  • 在Android Studio中

Android Studio

  • 在Visual Studio Code中

Visual Studio Code

五、使用FocusScope转移焦点,隐藏输入法

我们在开发App的时候,会经常遇到当点击空白区域时将输入法隐藏的需求。一想到输入法,大家可能都会想通过Method Channle,让原生实现隐藏输入法的办法来解决。其实我们可以通过FocusScope来转移焦点,同样能够达到隐藏输入法的目的。

Container(
        height: 500.0,
        child: new GestureDetector(
          onTap: () {
            // 通过GestureDetector捕获点击事件,再通过FocusScope将焦点转移至空焦点——new FocusNode()
            FocusScope.of(context).requestFocus(FocusNode());
          },
          child: Container(
              margin: EdgeInsets.all(30.0),
              child: ListView(children: <Widget>[
                TextField(
                  decoration: InputDecoration(labelText: 'Username'),
                ),
                TextField(
                  decoration: InputDecoration(labelText: 'Password'),
                )
              ])),
        ),
      ),

开发过程中还发现了Flutter一个bug,这里传递给FocusScope的context不能在MaterialApp下面,即你需要将这部分代码放到独立的一个Widget里面。 具体参考这个issue最后一个评论。