## 1 简介

Flutter中⼏乎所有的对象都是⼀个 **Widget**。

Widget：描述⼀个UI元素的配置数据。

- Widget 实际上就是 Element 的配置数据，Widget 树实际上是⼀个配置树，⽽真正的 UI 渲染树是由 Element构成；
- ⼀个 Widget 对象可以对应多个 Element 对象。这很好理解，根据同⼀份配置（Widget），可以创建多个实例 （Element）。 

```dart
@immutable 
abstract class Widget extends DiagnosticableTree {//诊断树，提供调试信息。
    const Widget({ this.key }); 
    final Key key;//是否在下⼀次 build 时复⽤旧的widget,条件在 canUpdate()
    
    @protected
    Element createElement(); //隐式调⽤ 
    
    @override 
    String toStringShort() { 
        return key == null ? '$runtimeType' : '$runtimeType-$key'; 
    }
    
    @override 
    void debugFillProperties(DiagnosticPropertiesBuilder properties) { //诊断树的⼀些特性
        super.debugFillProperties(properties); 
        properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense; 
    }
    //⽤于在Widget树重新 build 时复⽤旧的widget
    static bool canUpdate(Widget oldWidget, Widget newWidget) { 
        return oldWidget.runtimeType == newWidget.runtimeType 
            && oldWidget.key == newWidget.key; 
    } 
}
```

## 2 Stateless Widget

继承⾃ Widget ，重写 createElement() ⽅法。

```dart
@override 
StatelessElement createElement() => new StatelessElement(this);
```

例子

```dart
class Echo extends StatelessWidget { 
    const Echo({ 
        Key key, 
        @required this.text, 
        this.backgroundColor:Colors.grey, 
       }):super(key:key); 
    
    final String text; 
    final Color backgroundColor;
    @override 
    Widget build(BuildContext context) { 
        return Center( 
            child: Container( 
                color: backgroundColor, 
                child: Text(text),
            ), 
        );
    } 
  }
```

## 3 Stateful Widget

继承⾃ widget 类，并重写了 createElement() ⽅法，添加了⼀个新的接⼝ createState() 。

```dart
abstract class StatefulWidget extends Widget { 
    const StatefulWidget({ Key key }) : super(key: key); 
    
    @override
    StatefulElement createElement() => new StatefulElement(this); 
    
    @protected 
    State createState(); 
}
```

## 4 State

⼀个 StatefulWidget 类会对应⼀个State类，State 表示与其对应的 StatefulWidget 要维护的状态。

- 在 widget build 时可以被同步读取。 
- 当 State 被改变时，⼿动调⽤其 setState() ，重新调⽤其 build ⽅法重新构建widget树，更新 UI 的目的。

## 5 State 生命周期

- initState：当Widget第⼀次插⼊到Widget树时会被调⽤，在 build（） ⽅法或 didChangeDependencies() 中 

  调⽤它。

- didChangeDependencies()：当 State 对象的依赖发⽣变化时会被调用。

- build()：

  - 在调⽤ initState() 之后。 
  - 在调⽤ didUpdateWidget() 之后。
  - 在调⽤ setState() 之后。
  - 在调⽤ didChangeDependencies() 之后。
  - 在State对象从树中⼀个位置移除后（会调⽤deactivate）⼜重新插⼊到树的其它位置之后。

- reassemble()：专⻔为了开发调试⽽提供的。

- didUpdateWidget() ：在widget重新构建时，如果 Widget.canUpdate 返回 true 则会调⽤。

- deactivate()：当State对象从树中被移除时，会调⽤此回调。

- dispose() ：当State对象从树中被永久移除时调⽤，通常在此回调中释放资源。

## 6 状态管理

- Widget管理自己的state。 
- 父widget管理子widget状态。 
- 混合管理（父widget和子widget都管理状态）。

原则：

- 用户数据，如复选框的选中状态、滑块的位置，则该状态最好由⽗widget管理。 

- 有关界⾯外观效果的，例如颜⾊、动画，那么状态最好由 widget 本身来管理。 

- 某⼀个状态是不同widget共享的则最好由它们共同的⽗widget管理。

## 7 全局状态管理

例如语言变化。

- 实现⼀个全局的事件总线。
- 使⽤ **redux** 全局状态包。

## 8 Flutter widget 库介绍

- Text：带格式的文本
- Row、Column：在⽔平（Row）和垂直（Column）⽅向上创建灵活的 布局
- Stack：允许⼦ widget 堆叠， 你可以使⽤ Positioned 来定位他们相对于 Stack 的上下左右四条边的位置。
- Container：矩形视觉元素，可以装饰⼀个 BoxDecoration , 如 background、⼀ 个边框、或者⼀个阴影。 Container 也可以具有边距（margins）、填充(padding)和应⽤于其⼤⼩的约束 (constraints)。

## 9 文本及样式

### 9.1 Text

```dart
Text("Hello world", 
    textAlign: TextAlign.center,//⽂本的对⻬⽅式
);

Text("Hello world! I'm Jack. "*4, //文本重复次数
    maxLines: 1, //指定⽂本显示的最⼤⾏数
    overflow: TextOverflow.ellipsis, //指定截断⽅式，默认是直接截断
);

Text("Hello world", 
    textScaleFactor: 1.5, //相对于当前字体⼤⼩的缩放因⼦ 系统字体改变
);

```

### 9.2 TextStyle

指定⽂本显示的样式如颜⾊、字体、粗细、背景等

```dart
Text("Hello world", 
     style: TextStyle( 
         color: Colors.blue, 
         fontSize: 18.0, 
         height: 1.2, //指定⾏⾼
         fontFamily: "Courier", //字体集
         background: new Paint()..color=Colors.yellow,  
         decoration:TextDecoration.underline,
         decorationStyle: TextDecorationStyle.dashed ), );
```

### 9.3 TextSpan

代表⽂本的⼀个“⽚段”，设置不同文本样式。

```dart
Text.rich(TextSpan( 
    children: [ 
        TextSpan( text: "Home: " ),
        TextSpan(
            text: "https://flutterchina.club", 
            style: TextStyle( color: Colors.blue ),
            recognizer: _tapRecognizer 
        ), 
    ] 
))
```

### 9.4 DefaultTextStyle 

在widget树中，文本的样式默认是可以被继承的，DefaultTextStyle  设置默认样式。

```dart
DefaultTextStyle( //1.设置⽂本默认样式 
    style: TextStyle( 
        color:Colors.red, 
        fontSize: 20.0, ),
    textAlign: TextAlign.start, 
    child: Column(
        crossAxisAlignment: CrossAxisAlignment.start, 
        children: <Widget>[ 
            Text("hello world"), 
            Text("I am Jack"), 
            Text("I am Jack", 
                 style: TextStyle(
                     inherit: false, //2. inherit:false 不继承默认样式 
                     color: Colors.grey 
                 ), 
                ), 
        ], 
    ), 
);
```

### 9.5 使用字体

```dart
#1.在asset中声明
flutter:
   fonts: 
    family: Raleway
     fonts: 
        asset: assets/fonts/Raleway-Regular.ttf
    
#2.使用
            
// 声明⽂本样式 
const textStyle = const TextStyle( 
            fontFamily: 'Raleway', );// 使⽤⽂本样式 

var buttonText = const Text( 
    "Use the font for this text", 
    style: textStyle, 
);


```

## 10 按钮

```dart
//RaisedButton 漂浮 按钮，它默认带有阴影和灰⾊背景。按下后，阴影会变⼤
RaisedButton( 
    child: Text("normal"), 
    onPressed: () => {}, 
);

//FlatButton 即扁平按钮，默认背景透明并不带阴影。按下后，会有背景⾊：
FlatButton( 
    child: Text("normal"), 
    onPressed: () => {}, 
);

//OutlineButton 默认有⼀个边框，不带阴影且背景透明。按下后，边框颜⾊会变亮、同时出现背景和阴影(较弱)
OutlineButton( 
    child: Text("normal"),
    onPressed: () => {}, 
);

//IconButton 是⼀个可点击的Icon，不包括⽂字，默认没有背景，点击后会出现背景
IconButton( 
    icon: Icon(Icons.thumb_up), 
    onPressed: () => {}, 
)

//⾃定义按钮外观
const FlatButton({ 
     ... 
    @required this.onPressed, //按钮点击回调 
    this.textColor, //按钮⽂字颜⾊ 
    this.disabledTextColor, //按钮禁⽤时的⽂字颜⾊ 
    this.color, //按钮背景颜⾊ 
    this.disabledColor,//按钮禁⽤时的背景颜⾊ 
    this.highlightColor, //按钮按下时的背景颜⾊ 
    this.splashColor, //点击时，⽔波动画中⽔波的颜⾊ 
    this.colorBrightness,//按钮主题，默认是浅⾊主题 
    this.padding, //按钮的填充 
    this.shape, //外形 
    @required this.child, //按钮的内容
})    

```

## 11 图片及ICON

ImageProvider：抽象类

* AssetImage（Image.asset） ：从asset中加载图片
* NeworkImage（Image.network）：从网络获取图片

```dart
const Image({ 
    ... 
    this.width, //图⽚的宽 
    this.height, //图⽚⾼度 
    this.color, //图⽚的混合⾊值 
    this.colorBlendMode, //混合模式
    this.fit,//缩放模式 
    this.alignment = Alignment.center, //对⻬⽅式 
    this.repeat = ImageRepeat.noRepeat, //重复⽅式 ...
})
```

## 12 单选框和复选框

* 单选：Switch
* 复选：Checkbox

本身不会保存当前的状态，选中状态都是由**父组件**来管理的。

## 13 输入框及表单

* 输入框组件 TextField
* 表单组件 Form:子孙元素必须是 FormField 类型

```dart
Column(
        children: <Widget>[
          TextField(
            autofocus: true,//是否自动获取焦点
            decoration: InputDecoration(
                labelText: "用户名",
                hintText: "用户名或邮箱",
                prefixIcon: Icon(Icons.person)
            ),
          ),
          TextField(
            decoration: InputDecoration(
                labelText: "密码",
                hintText: "您的登录密码",
                prefixIcon: Icon(Icons.lock)
            ),
            obscureText: true,
          ),
        ],
);
```

## 14 进度指示器

* LinearProgressIndicator：是一个线性、条状的进度条。
* CircularProgressIndicator：是一个圆形进度条。

[flutter_spinkit](https://pub.flutter-io.cn/packages/flutter_spinkit) ：包提供了多种风格的模糊进度指示器