Hi,大家好,我是承香墨影!上周 Google 发布了 Flutter 的 Beta 版本,我想将会带起来一波程序员来研究它。今天分享的文章,就是一个基于 Flutter 的入门文章,作者还是一个学生,在阅读 Flutter 之后,简单的创建了自己的第一个 Flutter App。虽然很简单,但是依然说明 Flutter 的简洁和快速开发的能力,看看作者是这么做到的吧! — 承香墨影 作者 | Norbert 翻译 | 承香墨影 授权 承香墨影 翻译并发布 概要 这是一个偶然的事件,我正在浏览我的 Youtube 的订阅内容,看到了很多关于 Flutter 的相关视频,这引起了我的兴趣。我很兴奋的开始阅读它的文档。 我喜欢的学习方式,是边动手边学习。阅读完几页文档并研究如何创建一个新的项目,我对自己尝试新东西,倍感信心。 App 正如你在 Gif 中看到的那样,这是一个非常基本的应用程序,但它仍然有一些让我觉得有趣的地方。 它使用 Google Book Api 从数据库中读取书籍数据。 在数据展示前,显示一个加载指示器。 将书名和图像,都加载显示出来。 在传统的 Android App 中,这将需要几个类和不少代码。 而使用 Flutter,这个 App 有一个类和 129 行代码。包括一些引入语句和布局。 这一切,是不是听起来很棒?让我们开始吧! 开始 在我开始之前,我并不会详细的介绍这个 App 的所有细节,请务必查看示例代码以及文档,进行参考。 另外,整个 App 的代码(所有 129 行代码),都在 Github 上开源,我推荐你看看。 在这个例子中,我们需要 3 个变量。 一个书本的列表,其中一般被定义成长这样: 一个 Public Subject,它是 RxDart 的一部分,而 RxDart 又是 Rx 的一个实现,我这里主要用它来监听 textChanged 事件。 还有一个变量,表示我们目前是否在等待服务端响应。 此外,用户界面包含三个主要元素。 列表 加载器。 文本输入框。 我们将他们放在一起。 关于这个地方的一个有趣的部分是 onChanged,在这里我们传递了一个 Lambda,它讲当前输入的文本添加到 subject 上,这使得我们可以在其他地方监听回调。 如果当前出于加载状态,则显示进度条,否则显示一个空的容器。 该列表是一个基于索引的 ListView。而在其内部,我们布局了一个用于显示网络图片的 逻辑代码 在这个 所有的逻辑都在这里了。 首先说几点,如果 另外,如果我们获取到 Text 的内容,我们将开始加载并清除列表。 之后,我们向 Google Api 发出请求 当结果返回的时候: 获得返回的内容。 解析 JSON 数据,饭后返回一个 Map。 "items" 包含大量的书籍信息。 循环迭代之后,使用 这些 "items" 就是我们需要的标题和书籍封面图。 小结 到这里,该 App 是一个完整的小应用。 这是第一步,接下来将使用一个数据库来存储数据。 我读过这本书吗? 关于这本书的一些笔记内容。 期待你的持续关注。 在头条号私信我。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、虚拟机、Linux、Kotlin、Python、爬虫、Web项目源码。List<Book> _items = new List();final subject = new PublishSubject<String>();bool _isLoading = false;
class Book { String title,url; Book(this.title,this.url); }
new TextField( decoration: new InputDecoration( hintText: 'Choose a book', ), onChanged: (string) => (subject.add(string)),),
_isLoading? new CircularProgressIndicator(): new Container(),
new Expanded( child: new ListView.builder( padding: new EdgeInsets.all(8.0), itemCount: _items.length, itemBuilder: (BuildContext context, int index) { return new Card( child: new Padding( padding: new EdgeInsets.all(8.0), child: new Row( children: <Widget>[ _items[index].url != null? new Image.network(_items[index].url): new Container(), new Flexible( child: new Text(_items[index].title, maxLines: 10), ), ], ) ) ); }, ),),
Image
以及一个用于显示书籍描述的 Text
。 @override void initState() { super.initState(); subject.stream.debounce(new Duration(milliseconds: 600)).listen(_textChanged); }
initState
方法中,我们使用流式编码来处理它的事件并消费它们。这样做是为了每次点键入文本的时候,不会立即向 Api 服务器发送请求,而是会在最后一次键入文本之后,等待 600ms,再将输入的字符串发送到 _textChange()
方法,这也是我们使用 Rx 的唯一原因。 void _textChanged(String text) { if(text.isEmpty) { setState((){_isLoading = false;}); _clearList(); return; } setState((){_isLoading = true;}); _clearList(); http.get("https://www.xxx.com/books/v1/volumes?q=$text") .then((response) => response.body) .then(JSON.decode) .then((map) => map["items"]) .then((list) {list.forEach(_addBook);}) .catchError(_onError) .then((e){setState((){_isLoading = false;});}); } void _onError(dynamic d) { setState(() { _isLoading = false; }); } void _clearList() { setState(() { _items.clear(); }); }
Text
是空的,我们不再加载并消除列表。volumes?q=$text
,其中 text
包含当前输入的字符串。_addBook()
方法添加到 "items" 中。 void _addBook(dynamic book) { setState(() { _items.add(new Book(book["volumeInfo"]["title"], book["volumeInfo"]["imageLinks"]["smallThumbnail"])); }); }