Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Flutter基础—应用实例

$
0
0

总结之前学习的概念,编写一个完整的应用实例。假设我们使用一个网络购物的应用程序,它展示出售的各种商品和存放准备购买商品的购物车。首先定义一个展示类ShoppingListItem.dart:

import 'package:flutter/material.dart';
class Product {
  const Product({this.name});
  final String name;
}
typedef void CartChangedCallback(Product product, bool inCart);
class ShoppingListItem extends StatelessWidget {
  ShoppingListItem({Product product, this.inCart, this.onCartChanged})
    : product = product,
      super(key: new ObjectKey(product));
  final Product product;
  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,
    );
  }
  @override
  Widget build(BuildContext context) {
    return new ListItem(
      onTap: () {
        onCartChanged(product, !inCart);
      },
      leading: new CircleAvatar(
        backgroundColor: _getColor(context),
        child: new Text(product.name[0]),
      ),
      title: new Text(product.name, style: _getTextStyle(context)),
    );
  }
}

ShoppingListItem控件遵循无状态控件的通用模式,将在构造函数中接收到的值存储在final成员变量中,然后在build函数执行时使用。例如布尔值inCart在两个视觉效果之间切换:一个使用当前主题的颜色,另一个使用灰色。

当用户点击列表项时,控件不会直接修改inCart的值,但是控件从父控件接收onCartChanged函数。此模式允许你在控件较高的层次结构中存储状态,这样使状态的持续时间更长。在极端情况下,存储在runApp的控件状态在应用程序的生命周期内保持不变。

当父控件接收到onCartChanged回调,父控件会更新其内部状态,这将触发父控件重建并使用新的inCart值创建ShoppingListItem的新实例。尽管父控件在重建时创建了ShoppingListItem的新实例,但该操作很节省,因为框架会将新构建的控件与之前构建的控件时进行比较,并将有差异的部分应用于底层渲染对象。

下面编写存储可变状态的父控件:

import 'package:flutter/material.dart';
import 'ShoppingListItem.dart';
class ShoppingList extends StatefulWidget {
  ShoppingList({Key key, this.products}) : super(key: key);
  final List<Product> products;
  @override
  _ShoppingListState createState() => new _ShoppingListState();
}
class _ShoppingListState extends State<ShoppingList> {
  Set<Product> _shoppingCart = new Set<Product>();
  void _handleCartChanged(Product product, bool inCart) {
    setState(
      () {
        if (inCart)
          _shoppingCart.add(product);
        else
          _shoppingCart.remove(product);
      }
    );
  }
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('购物清单'),
      ),
      body: new MaterialList(
        type: MaterialListType.oneLineWithAvatar,
        children: config.products.map(
          (Product product) {
            return new ShoppingListItem(
              product: product,
              inCart: _shoppingCart.contains(product),
              onCartChanged: _handleCartChanged,
            );
          }
        ),
      ),
    );
  }
}
final List<Product> _kProducts = <Product>[
  new Product(name: '鸡蛋'),
  new Product(name: '面粉'),
  new Product(name: '巧克力脆片'),
];
void main() {
  runApp(
    new MaterialApp(
      title: 'Flutter教程',
      home: new ShoppingList(products: _kProducts),
    ),
  );
}

类ShoppingList继承了StatefulWidget,这意味着这个控件存储可变状态,当ShoppingList首次插入到树中,框架调用createState函数在树中相关联的位置创建一个新的_ShoppingListState实例(注意:通常命名中带有下划线的State子类,说明它们是私有类)。当该控件的父控件重建时,父控件会创建一个新的ShoppingList实例,但框架将重用已经在树上的_ShoppingListState实例,而不会再次调用createState函数。

要访问当前ShoppingList的属性,_ShoppingListState可以使用其config属性。如果父控件重建并创建一个新的ShoppingList,_ShoppingListState也将使用新的config值重建。如果想要在config属性更改时收到通知,可以覆盖didUpdateConfig函数,它通过oldConfig将旧配置与当前config进行比较。

当处理onCartChanged回调时,_ShoppingListState通过从_shoppingCart中添加或删除一个产品来改变其内部状态。为了向框架通知它改变了内部状态,它在setState中封装这些调用。调用setState将控件标记为dirty,并安排它在应用程序下次需要更新屏幕时重建。如果在修改控件内部状态时忘记调用setState,框架不会知道控件是dirty的,可能不会调用控件的build函数,这意味着用户界面不会更新以反映更改的状态。

通过这种方式管理动态,不再需要单独编写代码来创建和更新子控件。相反,只需要实现构建函数,即可处理这两种情况。

这里写图片描述

作者:hekaiyou 发表于2016/11/8 21:41:34 原文链接
阅读:0 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>