Flutter Widget移动UI框架使用Material和密匙Key实战
黎燃 人气:0Flutter
Flutter是谷歌的移动UI框架,可以在IOS和Android上快速构建高质量的本地用户界面。Flutter可以使用现有代码。
在世界上,Flutter正被越来越多的开发人员和组织使用,Flutter是完全免费和开源的。这也是构建未来Google Fuchsia应用程序的主要方式。
import 'package:flutter/material.dart'; void main() { runApp( new Center( child: new Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
runApp函数接受给定的小部件,并使其成为小部件树的根。在本例中,小部件树由两个小部件组成:Center(及其子小部件)和Text。框架强制根小部件覆盖整个屏幕,这意味着文本“Hello,world”将位于屏幕中心。需要在text实例中指定文本显示的方向。使用MaterialApp时,将自动设置文本方向,稍后将进行演示。 编写应用程序时,通常会创建新的小部件。这些小部件是无状态无状态小部件或有状态有状态小部件。具体选择取决于小部件是否需要管理某些状态。小部件的主要工作是实现一个构建函数来构建自己。小部件通常由一些较低级别的小部件组成。Flutter框架将依次构建这些小部件,直到构建最低级别的子小部件。这些最低级别的小部件通常是RenderObject,它将计算和描述小部件的几何结构。
Material
Flutter提供了许多小部件来帮助构建遵循Material Design的应用程序。Material应用程序从MaterialApp小部件开始,它在应用程序的根位置创建一些有用的小部件,包括一个Navigator,它管理由字符串标识的小部件堆栈(即页面路由堆栈)。导航器允许应用程序在页面之间平滑过渡。是否使用MaterialApp是完全可选的,但使用它是一个很好的做法。 Scaffold是Material中主要的布局组件.
import 'package:flutter/material.dart'; void main() { runApp(new MaterialApp( title: 'Flutter Tutorial', home: new TutorialHome(), )); } class TutorialHome extends StatelessWidget { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( leading: new IconButton( icon: new Icon(Icons.menu), tooltip: 'Navigation menu', onPressed: null, ), title: new Text('Example title'), actions: <Widget>[ new IconButton( icon: new Icon(Icons.search), tooltip: 'Search', onPressed: null, ), ], ), body: new Center( child: new Text('Hello, world!'), ), floatingActionButton: new FloatingActionButton( tooltip: 'Add', // used by assistive technologies child: new Icon(Icons.add), onPressed: null, ), ); } }
更完整的示例
让我们考虑一个更完整的示例,它将上面介绍的概念结合在一起。让我们假设一个显示各种待售产品并维护购物车的购物应用程序。让我们先定义ShoppingListItem:
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小部件是无状态的。它将在构造函数中接收的值存储在最终成员变量中,然后在构建函数中使用它们。例如,inCart布尔值表示在两种视觉呈现效果之间切换:一种使用当前主题的主色,另一种使用灰色。 当用户单击列表项时,小部件不会直接修改其inCart值。相反,小部件将调用其父小部件赋予它的onCartChanged回调函数。此模式允许在小部件层次结构中存储更高的状态,从而使状态持续更长时间。在极端情况下,存储并传递给runApp应用程序的小部件的状态将持续整个生命周期。 当父项收到onCartChanged回调时,父项将更新其内部状态,这将触发父项使用新的inCart值重新生成ShoppingListItem的新实例。尽管父ShoppingListItem在重建时创建了一个新实例,但操作成本很低,因为Flutter框架会将新构建的小部件与先前构建的小组件进行比较,并且只将差异应用于底层RenderObject。
Key
可以使用该键控制在重新构建小部件时框架将匹配哪些其他小部件。默认情况下,框架根据其runtimeType和显示顺序进行匹配。当使用键时,框架要求两个小部件具有相同的键和runtimeType。 键对于构建相同类型的小部件的多个实例非常有用。例如,ShoppingList构建了足够的ShoppingListItem实例来填充其可见区域: 如果没有密钥,则当前生成中的第一个项将始终与上一个生成中的首个项同步。即使在语义上,如果列表中的第一个项目滚动到屏幕外,它在窗口中也不再可见。 通过将列表中的每个项目指定为“语义”键,无限列表可以更有效,因为框架将使项目与匹配的语义键同步,从而具有相似(或相同)的视觉外观。此外,语义同步条目意味着在有状态的子窗口小部件中,保留状态将附加到相同的语义条目,而不是附加到相同编号位置的条目。
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { Widget titleSection = new Container( padding: const EdgeInsets.all(32.0), child: new Row( children: [ new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ new Container( padding: const EdgeInsets.only(bottom: 8.0), child: new Text( 'Oeschinen Lake Campground', style: new TextStyle( fontWeight: FontWeight.bold, ), ), ), new Text( 'Kandersteg, Switzerland', style: new TextStyle( color: Colors.grey[500], ), ), ], ), ), new Icon( Icons.star, color: Colors.red[500], ), new Text('41'), ], ), ); //... }
将第一行文本放入容器,然后在底部添加8个像素。列中的第二个子项(也是文本)显示为灰色。 标题行中的最后两项是红星图标和文本“41”。将整行放在容器中,沿每条边填充32个像素
加载全部内容