# flutter 学习笔记

# 组件的使用
* Text文字组件
  * `textAlign: TextAlign.start,` // 文本对齐方式
  * `textDirection: TextDirection.ltr` // 文本方向
  * `maxLines:1` // 最大行数
  * `textScaleFactor: 1.5,` // 文字缩放
  * `overflow: TextOverflow.ellipsis,` // 超出处理
  * `style:`
    * TextStyle组件
    ```dart
      TextStyle(
        color: Colors.blue,
        fontSize: 18.0,
        height: 1.2,  
        fontFamily: "Courier",
        background: new Paint()..color=Colors.yellow,
        decoration:TextDecoration.underline,
        decorationStyle: TextDecorationStyle.dashed
      ),
    ```
  * 文本接合,多个textSpan对文本进行修饰，然后拼合在一起
  ```dart
    Text.rich(TextSpan(
      children: [
        TextSpan(
          text: "https://flutterchina.club",
          style: TextStyle(
            color: Colors.blue
          ),  
          recognizer: _tapRecognizer
        ),
        ...
      ]
    ))
  ```
  * 字体设置[链接]('https://book.flutterchina.club/chapter3/text.html')
* 按钮
  * `RaisedButton` // 悬浮按钮
  * `FlatButton` // 扁平按钮
  * `OutlineButton` // 默认有边框
  * `IconButton` // 可点击的icon
    * `icon: Icon(Icons.thumb_up),`
  * 前三个都可以加`.icon`然后属性变成`icon`和`label`
  * 自定义
  ```dart
    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, //按钮的内容
    })
  ```
* 图片
  * pubspec.yaml配置
    ```yaml
      assets:
        - images/avatar.png
    ```
  * 加载图片
    ```dart
      Image(
        image: AssetImage("images/avatar.png"),
        width: 100.0
      );
      Image.asset("images/avatar.png",
        width: 100.0,
      )
      Image(
        image: NetworkImage(
            "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
        width: 100.0,
      )
      Image.network(
        "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
        width: 100.0,
      )
      const Image({
        ...
        this.width, //图片的宽
        this.height, //图片高度
        this.color, //图片的混合色值
        this.colorBlendMode, //混合模式
        this.fit,//缩放模式
        this.alignment = Alignment.center, //对齐方式
        this.repeat = ImageRepeat.noRepeat, //重复方式
        ...
      })
    ```
* ICON
  * `Icon(Icons.accessible,color: Colors.green,),`
  * 使用自定义字体图标[链接]('https://book.flutterchina.club/chapter3/img_and_icon.html')
* Switch开关组件
  * `value: true`
  * `onChanged`
* Checkbox多选组件
  * `value: true`
  * `onChanged` 
* Stack层叠组件 
  * 定位相对于父元素
  * `alignment: Alignment.center` // 总体控制
  * `alignment: Alignment(0,0)` // float(-1~1) 0,0居中
  * `children:  <Widget>[]`
    * Align组件
      * `alignment: Alignment.center` // 单独控制
      * `alignment: Alignment(0,0)` // float(-1~1) 0,0居中
      * `child: `  // 需要定位的子组件
    * Positioned组件
      * `left, bottom, top, right` // int 默认为0
      * `child: ` // 需要定位的子组件image
* AspectRatio组件
  * 默认横向占满父组件
  * 可以用来控制图片
  * `aspectTatio: 2.0/1.0`  // 宽高比
  * `child: ` // 子组件
* Card组件
  * `margin: EdgeInsets.all(10)` // 外边距
  * `child: ` // 子组件
* ClipOval组件
  * 可以用来裁剪原型头像
  * `child: ` // 子组件
* CircleAvatar组件
  * 感觉可以自适应头像大小
  * `backgroungImage: NetworkImage('src')`
* RaisedButton组件
  * `child:` // 子组件
  * `textColor: Theme.of(context).accentColor,` // 文字颜色
  * `textColor: Colors.red,` // 文字颜色
  * `onPressed: (){}` // 点击事件
* Warp组件
  * 相对于父组件横向占满
  * 可以自动换行
  * `spacing: 10,` // 元素和元素之间的距离
  * `runSpacing: 10` // 元素在纵轴之间的距离
  * `alignment: WarpAlignment.srart` // 水平对齐方式 
  * `runAlignment: WarpAlignment.spaceAround` // 纵向对齐方式
  * `direction: Axis.vertical` // 纵向排列
* SizedBox组件
  * `height: 30,`
  * `width:10,`
  * 空白盒子
* StatefullWidget
  * `setState((){})` 修改需要刷新的内容,类似小程序的setData
* Scaffold组件
  * appBar组件
    * `title: Text('text')` // 标题
    * `backgroundColor: Colors.red` // 背景颜色
    * `leading: IconButton(icon: Icon(Icons.menu), onPressed:(){})` // 左边加东西
    * `actions: <Widget>[]` // 右边加东西
    * `centerTitle: true` // 不论是不是ios都给居中显示
    * 菜单栏
      ```dart 
        DefaultTabController(
          length : 2, // tab的个数
          child: Scafford(
            appBar: AppBar(
              title: Text('title'),
              bottom: TabBar(
                tabs: <Widget>[
                  Tab(text:'1'),
                  Tab(text:'2'),
                  Tab(text:'3'),
                ]
              )
            ),
            body: TabBarView(
              children: <Widget>[
                Text('text1'),
                Text('text2'),
                Text('text3'),
              ]
            )
          )
        )
      ```
      * TabBar组件
        * `indicatorColor: Colors.red,`
        * `isScrollable: true` // 允许滑动
        * `tabs: <Widget>[]`
          * Tab组件
            * `text:"text"`
      * TabBarView组件
        * `children: <Widget>[]`
  * body
  * bottomNavigationBar组件
    * `currentIndex: 0,` // 当前选中的tab
    * `onTap: (int index){}` // 点击事件,默认参数是点击了第几个按钮
    * `items: <BottomNavigationBarItem>[]` // 按钮内容
      * BottomNavigationBarItem组件
        * `icon: Icon(Icons.home),` // 图标
        * `title: Text('主页')` // 文字
  * floatingActionButton浮动按钮组件
    * child:
    * onPressed: (){}
* Navigator路由跳转组件
  ```dart
    // 路由跳转
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context)=> FormPage(参数)
      )
    )
    // 返回上一界面
    Navigator.of(context).pop()
    // 替换掉当前界面
    Navigator.of(context).pushReplacementNamed('/home')
    // 重置路由
    Navigator.of(context).pushAndRemoveUntil(
      new MaterialPageRoute(
        builder: (context) => new Tabs(index: 1),
      ),
      (route) => route == null
    )
  ``` 
  * MaterialPageRoute
    * `WidgetBuilder builder` // 是一个WidgetBuilder类型的回调函数，它的作用是构建路由页面的具体内容，返回值是一个widget。我们通常要实现此回调，返回新路由的实例。
    * `RouteSettings settings` // 包含路由的配置信息，如路由名称、是否初始路由（首页）。
    * `bool maintainState = true,` // 默认情况下，当入栈一个新路由时，原来的路由仍然会被保存在内存中，如果想在路由没用的时候释放其所占用的所有资源，可以设置maintainState为false。
    * `bool fullscreenDialog = false,` // 表示新的路由页面是否是一个全屏的模态对话框，在iOS中，如果fullscreenDialog为true，新页面将会从屏幕底部滑入（而不是水平方向）。
* MaterialApp
  * `debugShowCheckedModeBanner: false` // 去除斜着的debug标识
  * routes
    ```dart
      routes: {
        '/form': (context) => FromPage(),
        '/search': (context) => SearchPage(),
      }

      Navigator.pushNamed(context, '/search')

      // 在跳转到的路由的build方法里写
      var args=ModalRoute.of(context).settings.arguments;
      // 就可以传输参数了
      Naviagtor.pushNamed(context, '/search', arguments:{"id": 123});

      // 或者是定义路由的时候进行传参，这样就可以正常的使用了
      routes: {
        "tip2": (context){
          return TipRoute(text: ModalRoute.of(context).settings.arguments);
        },
      }, 
    ```
  * `initialRoute: '/'` // 初始化加载的路由
  * 对于路由的固定写法
    ```dart
      // Route.dart
      import 'package:flutter/material.dart';
      import '../pages/Tabs.dart';
      import '../pages/Search.dart';
      import '../pages/Form.dart';

      final Map<String, Function> routes = {
        '/':(contxt,{arguments})=>Tabs(),
        '/search':(contxt,{arguments}) =>SearchPage(arguments: arguments),
        '/form': (context,{arguments}) =>FormPage(arguments: arguments),
      };
      
      // 这个东西实际上是一个路由生成钩子，只有在没有找到指定路由的时候才会被调用，当前没有设置route所有的路由都会经过这个钩子进行处理，这里也可以当成路由守卫，判断各种权限然后进行路由的导航
      var onGenerateRoute=(RouteSettings settings) {
        // 统一处理
        final String name = settings.name;   
        final Function pageContentBuilder = routes[name];        

        if (pageContentBuilder != null) {
          if (settings.arguments != null) {
            final Route route = MaterialPageRoute(
              builder: (context) =>
                pageContentBuilder(context, arguments: settings.arguments));
            return route;
          } else {
            final Route route = MaterialPageRoute(
              builder: (context) =>
                pageContentBuilder(context));
            return route;
          }
        }
      };
      // main.dart
      import 'package:flutter/material.dart';
      import 'routes/Routes.dart';
      void main() => runApp(MyApp());

      class MyApp extends StatelessWidget {  
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            // home:Tabs(),
            initialRoute: '/',      
            onGenerateRoute: onGenerateRoute
          );
        }
      }
      // 路由跳转
      Naviagtor.pushNamed(context, '/search', arguments:{"id": 123});
    ```
* 资源管理 `pubspec.yaml`
  ```yaml
  flutter:
    assets:
      - assets/my_icon.png
      - assets/background.png
  ```
  assets指定应包含在应用程序中的文件， 每个asset都通过相对于pubspec.yaml文件所在的文件系统路径来标识自身的路径。asset的声明顺序是无关紧要的，asset的实际目录可以是任意文件夹（在本示例中是assets文件夹）  
* 在Widget树中获取State对象
  * 方法一
  ```dart
    // 直接通过of静态方法来获取ScaffoldState 
    ScaffoldState _state=Scaffold.of(context); 
    _state.showSnackBar(
      SnackBar(
        content: Text("我是SnackBar"),
      ),
    );
  ```
  * 方法二
  ```dart
    //定义一个globalKey, 由于GlobalKey要保持全局唯一性，我们使用静态变量存储
    static GlobalKey<ScaffoldState> _globalKey= GlobalKey();
    ...
    Scaffold(
        key: _globalKey , //设置key
        ...  
    )
    _globalKey.currentState.openDrawer()
  ```
  GlobalKey是Flutter提供的一种在整个APP中引用element的机制。如果一个widget设置了GlobalKey，那么我们便可以通过globalKey.currentWidget获得该widget对象、globalKey.currentElement来获得widget对应的element对象，如果当前widget是StatefulWidget，则可以通过globalKey.currentState来获得该widget对应的state对象。
* 