3.Flutter Widget框架

1.介绍

中心思想就是用widget构建UI

2.Hello World

一个最简单的Flutter应用程序,只需一个widget即可

import 'package:flutter/material.dart';
void main() {
  runApp(
    new Center(
      child: new Text(
        'Hello World!',
        textDirection: TextDirection.ltr,
      ),
    )
  );
}

  • runApp接受给定的widget,并将它作为widget树的根,在上面的代码中,widget由Center和Text组成。框架强制根widget占满整个屏幕,文本居中显示,文本显示的方向需要在Text实例中用textDirection指定,当使用MaterialApp时,文本的方向将自动设定。
  • 在编写应用程序的时候通常要创建新widget,这些widget是无状态的StatelessWidget或者是有状态的StatefulWidget,具体的选择取决于你的widget是否需要管理一些状态
  • widget的主要工作是实现一个build函数,用以构建自身
  • 一个widget通常由一些较低级别widget组成。Flutter框架将依次构建这些widget,直到构建到最底层的子widget时。这些最低层的widget通常为RenderObject,它会计算并描述widget的几何形状。

3.基础 Widget

Flutter有一套丰富、强大的基础widget,其中以下是很常用的widget :

  • Text:可创建一个带格式的文本。
  • Row、 Column: 可在水平(Row)和垂直(Column)方向上创建灵活的布局。其设计是基于web开发中的Flexbox布局模型。
  • Stack: 取代线性布局 (和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于Stack的上下左右四条边的位置。Stacks是基于Web开发中的绝度定位(absolute positioning )布局模型设计的。
  • Container: 可创建矩形视觉元素。container 可以装饰为一个BoxDecoration, 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container可以使用矩阵在三维空间中对其进行变换。

下面创建一个 Container

//创建一个标题栏
class MyAppBar extends StatelessWidget{
  MyAppBar({this.title});

  // Widget子类中的字段往往都会定义为"final"
  final Widget title;
  
  @override
  Widget build(BuildContext context) {
    return new Container( // 这里是圆括号
      height: 64.0, //单位是逻辑上的像素(包括手机顶部的导航栏)
      padding: const EdgeInsets.symmetric(horizontal: 8.0), //左右都有8个像素的填充
      decoration: new BoxDecoration(color: Colors.blue[500]), //填充背景,后面的数字表示深浅
      // Row 是水平方向的线性布局(linear layout),使用Row 布局来排列其子项
      child: new Row(
        //列表项的类型是 <Widget>
        children: <Widget>[
          new IconButton(
              icon: new Icon(Icons.menu),
              tooltip: '导航栏',
              onPressed: null),  // null 会禁用 button
          // 中间的title widget被标记为Expanded, ,这意味着它会填充尚未被其他子项占用的的剩余可用空间,
          // Expanded可以拥有多个children,然后使用flex参数来确定他们占用剩余空间的比例
          new Expanded(
              child: title
          ),
          new IconButton(
              icon: new Icon(Icons.search), 
              tooltip: '搜索',
              onPressed: null),
        ],
      ),
    );
  }
}

class MyScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Material 是UI呈现的“一张纸”
    return new Material(
      child: new Column(
        children: <Widget>[
          // 在Column的顶部,放置了一个MyAppBar实例,将一个Text widget作为其标题传递给应用程序栏
          new MyAppBar(
            title: new Text(
              'Example title',
              style: Theme.of(context).primaryTextTheme.title,
            ),
          ),
          new Expanded(
              child: new Center(
                child: new Text('Hello World'),
              ) 
          ),
        ],
      ),
    );
  }

void main() {
  runApp(new MaterialApp(
    title: 'Container Test',
    home: new MyScaffold()
  )
  );
}

在这里插入图片描述

4.使用 Material 组件

  • Material应用程序以MaterialApp widget开始, 该widget在应用程序的根部创建了一些有用的widget,其中包括一个Navigator, 它管理由字符串标识的Widget栈(即页面路由栈)。Navigator可以让您的应用程序在页面之间的平滑的过渡。
//创建Material样式
class TutorialHome  extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    //Scaffold是Material中主要的布局组件.
    return new Scaffold(
      appBar: new AppBar(
        leading: new IconButton(icon: new Icon(Icons.menu),tooltip: '导航栏', onPressed: null),
        title: new Text('搜索'),
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.search),tooltip: '搜索', onPressed: null)
        ],
      ),
      body: new Center(
        child: new Text('Hello World'),
      ),
      floatingActionButton: new FloatingActionButton(
          tooltip:'Add',
          child: new Icon(Icons.add),
          onPressed: null
      ),
    );
  }


void main() {
  runApp(new MaterialApp(
    title: 'Flutter  Test',
    home: new TutorialHome(),
  )
  );
}
  • 请注意,我们再次将widget作为参数传递给其他widget。该 Scaffold widget 需要许多不同的widget的作为命名参数,其中的每一个被放置在Scaffold布局中相应的位置。 同样,AppBar 中,我们给参数leading、actions、title分别传一个widget。 这种模式在整个框架中会经常出现,这也可能是您在设计自己的widget时会考虑到一点。
    在这里插入图片描述

5.处理手势

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: () {
        print('MyButton was tapped');
      },

      child: new Container(
        height: 36.0,
        padding: const EdgeInsets.all(8.0),
        margin: const EdgeInsets.symmetric(horizontal: 8.0),
        decoration: new BoxDecoration(
          borderRadius: new BorderRadius.circular(5.0),
          color: Colors.lightGreen[500],
        ),
        child: new Center(
          child: new Text('Engage'),
        ),
      ),
    );
  }
}

void main() {
  runApp(new MaterialApp(
    title: 'ButtonTap  Test',
    home: new MyButton(),
  )
  );
}

在这里插入图片描述

  • GestureDetector widget并不具有显示效果,而是检测由用户做出的手势。 当用户点击Container时, GestureDetector会调用它的onTap回调, 在回调中,将消息打印到控制台。您可以使用GestureDetector来检测各种输入手势,包括点击、拖动和缩放。

  • 许多widget都会使用一个GestureDetector为其他widget提供可选的回调。 例如,IconButton、 RaisedButton、 和FloatingActionButton ,它们都有一个onPressed回调,它会在用户点击该widget时被触发。

6.根据用户输入改变widget

//计数
class Counter extends StatefulWidget{
  @override
  _CounterState createState() => new _CounterState();
}

class _CounterState  extends State<Counter>{
  int _counter = 0;

  void _increment() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new RaisedButton(
          onPressed: _increment,
          child: new Text('Increment'),
        ),
        new Text('Count : $_counter'),
      ],
    );
  }
}


void main() {
  runApp(new MaterialApp(
    title: 'ButtonTap  Test',
    home: new Counter(),
  )
  );
}

在这里插入图片描述

  • 无状态widget从它们的父widget接收参数, 它们被存储在final型的成员变量中。 当一个widget被要求构建时,它使用这些存储的值作为参数来构建widget。
  • StatefulWidgets是特殊的widget,它知道如何生成State对象,然后用它来保持状态

为什么StatefulWidget和State是单独的对象?

在Flutter中,这两种类型的对象具有不同的生命周期: Widget是临时对象,用于构建当前状态下的应用程序,而State对象在多次调用build()之间保持不变,允许它们记住信息(状态)。
class CounterDisplay extends StatelessWidget {
  // 注意:圆括号里面有一个大括号
  CounterDisplay({this.count});

  final int count;

  @override
  Widget build(BuildContext context) {
    return new Text('Count :$count');
  }
}

class CounterIncrementor extends StatelessWidget{
  CounterIncrementor({this.onPressed});

  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    return new RaisedButton(
      onPressed: onPressed,
      child: new Text('Increment'),
    );
  }
}

class CounterUpdate extends StatefulWidget{
  @override
  _CounterStateUpdate createState() => new _CounterStateUpdate();
}

class _CounterStateUpdate  extends State<CounterUpdate>{
  int _counter = 0;

  void _increment() {
    setState(() {
      ++_counter;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new CounterDisplay(count:_counter),
        new CounterIncrementor(onPressed: _increment),
      ],
    );
  }
}

void main() {
  runApp(new MaterialApp(
    title: 'ButtonTap  Test',
    home: new CounterUpdate(),
  )
  );
}

说明:

  1. Widget子类中的字段往往都会定义为"final"
  2. 在Flutter中,事件流是“向上”传递的,而状态流是“向下”传递的(译者语:这类似于React/Vue中父子组件通信的方式:子widget到父widget是通过事件通信,而父到子是通过状态),重定向这一流程的共同父元素是State
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值