Flutter基础(二)

Flutter基础知识

Posted by Ted on February 25, 2018

1、初始化

void main() => runApp(new FirstWidget());

class FirstWidget extends StatelessWidget {
  Widget first = new MaterialApp(
                theme: new ThemeData(
                  primarySwatch: Colors.green,
                ),
                home: Scaffold(
        			    appBar: AppBar(title: Center(child: Text('我是标题'))),
        				drawer: Text('这是抽屉栏'),
        				body: Text('你好,这是一个简单的页面'),
                ),
          );

  @override
  Widget build(BuildContext context) => first;
}

=> expr 胖箭头语法是 { return expr; } 形式的缩写。

所以初始化函数实际上是

void main(){
    return runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
  return   new MaterialApp(
                theme: new ThemeData(
                  primarySwatch: Colors.green,
                ),
                home: Scaffold(
        			    appBar: AppBar(title: Center(child: Text('我是标题'))),
        				drawer: Text('这是抽屉栏'),
        				body: Text('你好,这是一个简单的页面'),
                ),
          );
  }
}

在编写应用程序时,通常会创建新的widget,这些widget是无状态的StatelessWidget或者是有状态的StatefulWidget, 具体的选择取决于您的widget是否需要管理一些状态。widget的主要工作是实现一个build函数,用以构建自身。一个widget通常由一些较低级别widget组成。Flutter框架将依次构建这些widget,直到构建到最底层的子widget时,这些最低层的widget通常为RenderObject,它会计算并描述widget的几何形状。

StatefulWidget 拥有 StatelessWidget 的所有功能,也就是说 StatelessWidget 是他的子集,每个StateFulWidget 维护一个 State 对象,当我们对 相关数据更新后 并且 调用了** setState(() {})** 方法,这样就吧 该 Widget 标记为 dirty ,因此会触发控件的更新、替换、删除 等。

上面的runApp函数接受给定的Widget并使其成为widget树的根,框架强制根widget覆盖整个屏幕。所以官方不推荐把Widget层的控件来作为根控件,而是以MaterialApp或者WidgetApp作为父节点,上面的MyApp使用build函数构建了一个MaterialApp,将一个Scaffold脚手架包裹在里面,Scaffold显示的才是整个页面

img

2、MaterialApp/WidgetApp

class MaterialApp extends StatefulWidget

MaterialApp的主要作用是定义一些整体的风格,设置一些整体属性。构建一个material design风格的App。

  • MaterialApp 引入了 Material Design,还是相当漂亮的,开发者几乎不需要做额外的布局、样式 编码就能达到产品级视觉效果, 当然可以根据需求进行微调。
  • MaterialApp 提供了大量的美观、功能丰富的控件,放弃MaterialApp等于放弃了一整片森林。

MaterialApp 主要属性如下:

  • title : 在任务管理窗口中所显示的应用名字
  • theme : 应用各种 UI 所使用的主题颜色
  • color : 应用的主要颜色值(primary color),也就是安卓任务管理窗口中所显示的应用颜色
  • home : 应用默认所显示的界面 Widget
  • routes : 应用的顶级导航表格,这个是多页面应用用来控制页面跳转的,类似于网页的网址
  • initialRoute :第一个显示的路由名字,默认值为 Window.defaultRouteName
  • onGenerateRoute : 生成路由的回调函数,当导航的命名路由的时候,会使用这个来生成界面
  • onLocaleChanged : 当系统修改语言的时候,会触发这个回调
  • navigatorObservers : 应用 Navigator 的监听器
  • debugShowMaterialGrid : 是否显示 纸墨设计 基础布局网格,用来调试 UI 的工具
  • showPerformanceOverlay : 显示性能标签,https://flutter.io/debugging/#performanceoverlay
  • checkerboardRasterCacheImages 、showSemanticsDebugger、debugShowCheckedModeBanner 各种调试开关

3、Scaffold

class Scaffold extends StatefulWidget 

Scaffold中文名脚手架,如果说MaterialApp是定义整个App主体、主题之类的角色,Scaffold就是针对当前页面的一个架构了,其中的提供了一些组件属性

appBar:顶部标题栏

body:用来展示 APP 的主体部分。主体部分大部分是通过组合 ContainerColumnRowStack来实现的

floatingActionButton:悬浮按钮

bottomNavigationBar:底部类Tab导航栏

drawer:左边侧边栏控件

endDrawer:右边侧滑栏

backgroundColor: 内容的背景颜色,默认使用的是 ThemeData.scaffoldBackgroundColor 的值

4、布局/Flex

在main函数中开启网格调试布局

debugPaintSizeEnabled=true;

flutter采用Flex布局。

child可承载单个子控件,children可承载多个子控

一些常用的布局Widget:

  • Container:如果要添加填充,边距,边框或背景色,请使用Container来设置,只有Container有这些属性
  • Row:child在水平(左右)方向上进行布局
  • Colomn:child在竖直(上下)方向上进行布局
  • Expanded:填充剩余空间,必须放置于Row, Column或Flex内,
  • Stack+Positoned:Stack与Row和Clomn类似,只不过适用于子Wight没那么规则化的布局,可以允许其子widget简单的堆叠在一起

5、添加本地资源

在根目录下新建文件夹,命名为images,将lake.png图片放入

在pubspec.yam中添加

flutter:
  assets:
    - images/lake.png
    - images/background.png

如果要,包含images文件夹下的所有文件,可以简化为

flutter:
  assets:
    - images/

在代码中访问,比如:

new Image.asset(
    'images/lake.jpg',        //图片的路径
    width: 600.0,             //图片控件的宽度
    height: 240.0,            //图片控件的高度
    fit: BoxFit.cover,        //告诉引用图片的控件,图像应尽可能小,但覆盖整个控件。
 ),

有一些系统的Icons可以直接访问

Icons.call  // 电话图标

6、定位/Alignment

在Widget内设置alignment属性,是为了给child/children定位,

alignment: Alignment.center,

7、Stack

Stack可用于一些位置没有那么比例化的Row以及Cloumn

  child: Stack(
      children: <Widget>[
        Positioned(
          right: 10.0,
          top: 24.0,
          width: 20,
          height: 20,
          child: new Container(
            color: Colors.blue,
          ),
        )],

img

这种情况还有一个方法是用Row来布局,Row内先加一个Expand来拓张,然后接一个所需要的控件,再接一个控件用来与边界的距离

img

8、Tabbar使用

_tabController = new TabController(vsync: this, length: 3); 

Widget actionCountBar() => new Container(
    height: 50,
    child: new TabBar(
      controller: _tabController,
      tabs: <Widget>[
        new Tab(
          text: '转发0',
        ),
        new Tab(
          text: '评论5',
        ),
        new Tab(
          text: '点赞1',
        ),
      ],
    ),
  );

  Widget actionTabView()=> new Container(
    height: 500,
    child: new TabBarView( // 这是不同的页面
      controller: _tabController,
      children: <Widget>[
        new Center(child: new Text('转发')),
        new Center(child: new Text('评论')),
        new Center(child: new Text('点赞')),
      ],
    ),
  );

需要注意的是,controller要预先生成

9、NestedScrollView嵌套ScrollView

NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverToBoxAdapter(
                child: listHeaderView(),
              ),
            ];
          },
          body: Column(
            children: <Widget>[
              actionCountBar(),
              actionTabView(items),
            ],
          )),

headerSliverBuilder:头部,相当于UITableView的HeadView

SliverToBoxAdapter:新建普通的

body:放置ScrollView