A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 小江哥 黑马粉丝团   /  2019-7-24 19:24  /  1056 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

给IDE安装插件
我使用vsCode,安装Futter和Dart两个插件,你也可以使用Android Studio IDE或者IntelliJ,也需要安装插件。
创建一个基于模版的Flutter app
在你的项目文件夹下打开终端,输入 flutter create 你的app名称。比如 cd Desktop/www && flutter create firstapp。
用IDE打开项目,你主要编辑的是 lib/main.dart 文件。
Hello World
按照惯例,我们写一个 Hello World。
首先删除 lib/main.dart 内的内容,然后输入

import 'package:flutter/material.dart';

void main() => runApp(new Center(
    child: new Text('Hello World', textDirection: TextDirection.ltr),
));

终端运行 flutter run,效果如下图
1. 代码中使用了runApp函数,runApp函数接受指定的控件(Widget),并使其作为控件树(widget tree)的根控件。控件(Widget)定义一个元素(Element)的配置,在Flutter框架的层次结构中处于核心层。本实例中,控件树(widget tree)包含两个控件,Center控件使其子控件处于中间位置,Text控件打印文本内容。runApp函数强制将根控件覆盖屏幕,这意味着文本将显示在屏幕中心。
2. main函数使用了(=>)符号, 这是Dart中单行函数或方法的简写。
3. import 'package:flutter/material.dart',引入Flutter提供的一套丰富的Material widgets。
创建一个书单列表应用
1. 定义一个展示类 Book.dart
import 'package:flutter/material.dart';

// 声明一个 Book 类
class Book {
    // 声明一个常量构造函数
    const Book({this.name});
    final String name;
}
// 重命名一个具有两个参数的来自父控件的回调函数CartChangedCallback,两参数分别为自定义的Book类和布尔型,
typedef void CartChangedCallback(Book book, bool inCart);

// 定义一个扩展自Flutter无状态组件的类 BookItem
class BookItem extends StatelessWidget {
    // 声明构造函数,并调用超类为每一个book实例增加一个key
    BookItem({Book book, this.inCart, this.onCartChanged})
        : book = book,
          super(key: new ObjectKey(book));
    final Book book;
    final bool inCart;
    final CartChangedCallback onCartChanged;

    // 定义一个颜色方法
    Color _getColor(BuildContext context) {
        return inCart ? Colors.black54 : Theme.of(context).primaryColor;
    }

    // 定义一个文本样式方法
    TextStyle _getTextStyle(BuildContext context) {
        if (!inCart) return null;
        return new TextStyle(
            color: Colors.black54,
            decoration: TextDecoration.lineThrough,
        );
    }

    // 重写一个 Widget
    @override
    Widget build(BuildContext context) {
        return new ListTile(
            onTap: () => onCartChanged(book, !inCart),
            leading: new CircleAvatar(
                backgroundColor: _getColor(context),
                child: new Text(book.name[0]),
            ),
            title: new Text(book.name, style: _getTextStyle(context)),
        );
    }
}

BookItem控件遵循无状态控件的通用模式,将在构造函数中接收到的值存储在final成员变量中,然后在build函数执行时使用。
当用户点击列表项时,控件不会直接修改inCart的值,但是控件从父控件接收onCartChanged函数。此模式允许你在控件较高的层次结构中存储状态,这样使状态的持续时间更长。在极端情况下,存储在runApp的控件状态在应用程序的生命周期内保持不变。
当父控件接收到onCartChanged回调,父控件会更新其内部状态,这将触发父控件重建并使用新的inCart值创建BookItem的新实例。尽管父控件在重建时创建了BookItem的新实例,但该操作很节省,因为框架会将新构建的控件与之前构建的控件时进行比较,并将有差异的部分应用于底层渲染对象。
2. 编写父控件 mian.dart
import 'package:flutter/material.dart';
// 引入Book.dart
import 'Book.dart';

// 定义一个扩展自有状态控件的 BookList 类
class BookList extends StatefulWidget {
    BookList({Key key, this.books})
        : super(key: key);
    final List<Book> books;
    @override
    _BookListState createState() => new _BookListState();
}
class _BookListState extends State<BookList> {
    Set<Book> _bookCart = new Set<Book>();
    void _handleCartChanged(Book book, bool inCart) {
        setState(
            () {
            if (inCart)
                _bookCart.add(book);
            else
                _bookCart.remove(book);
        });
    }
    @override
    Widget build(BuildContext context) {
        return new Scaffold(
            appBar: new AppBar(
                title: new Text('书单列表'),
            ),
            body: new ListView(
                children: widget.books.map(
                    (Book book) {
                        return new BookItem(
                            book: book,
                            inCart: _bookCart.contains(book),
                            onCartChanged: _handleCartChanged,
                        );
                    }
                ).toList(),
            ),
        );
    }
}
final List<Book> _kBooks = <Book>[
    new Book(name: '你倾城一笑惊绝了多少年华'),
    new Book(name: '她被你一笑绝经了多少年头'),
    new Book(name: '我看你俩是昏厥了多少岁月'),
    new Book(name: '他看着我们懵逼了多少时光'),
    new Book(name: '所有人梦里花落了多少年少'),
];

void main() => runApp(new MaterialApp(
    title: '我的应用',
    home: new BookList(books: _kBooks),
));

类BookList继承了StatefulWidget,这意味着这个控件存储可变状态,当BookList首次插入到树中,框架调用createState函数在树中相关联的位置创建一个新的_BookListState实例。当该控件的父控件重建时,父控件会创建一个新的BookList实例,但框架将重用已经在树上的_BookListState实例,而不会再次调用createState函数。
要访问当前BookList的属性,_BookListState可以使用其config属性。如果父控件重建并创建一个新的BookList,_BookListState也将使用新的config值重建。如果想要在config属性更改时收到通知,可以覆盖didUpdateConfig函数,它通过oldConfig将旧配置与当前config进行比较。
当处理onCartChanged回调时,_BookListState通过从_bookCart中添加或删除一个产品来改变其内部状态。为了向框架通知它改变了内部状态,它在setState中封装这些调用。调用setState将控件标记为dirty,并安排它在应用程序下次需要更新屏幕时重建。如果在修改控件内部状态时忘记调用setState,框架不会知道控件是dirty的,可能不会调用控件的build函数,这意味着用户界面不会更新以反映更改的状态。
通过这种方式管理动态,不再需要单独编写代码来创建和更新子控件。相反,只需要实现构建函数,即可处理这两种情况。
以下是最终效果图


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马