Flutter基础—应用实例

119 篇文章 9 订阅
82 篇文章 1416 订阅

总结之前学习的概念,编写一个完整的应用实例。假设我们使用一个网络购物的应用程序,它展示出售的各种商品和存放准备购买商品的购物车。首先定义一个展示类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 ListTile(
      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 ListView(
        children: widget.products.map(
          (Product product) {
            return new ShoppingListItem(
              product: product,
              inCart: _shoppingCart.contains(product),
              onCartChanged: _handleCartChanged,
            );
          }
        ).toList(),
      ),
    );
  }
}
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函数,这意味着用户界面不会更新以反映更改的状态。

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

这里写图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何小有

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值