双子神偷2国语高清,达尔西斯,泉州武夷花园
前言
使用flutter开发一款app是一件非常愉快的事情,其出色的性能、跨多端以及数量众多的原生组件都是我们选择flutter的理由!今天我们就来使用flutter开发一款电影类的app,先看下app的截图。
从main.dart开始
在flutter里main.dart是应用开始的地方:
import 'package:flutter/material.dart'; import 'package:movie/utils/router.dart' as router; void main() => runapp(myapp()); class myapp extends statelesswidget { // this widget is the root of your application. @override widget build(buildcontext context) { return materialapp( debugshowcheckedmodebanner: false, title: '电影', theme: themedata( primaryswatch: colors.blue, ), ongenerateroute: router.generateroute, initialroute: '/', ); } }
一般的,在flutter中管理路由有两种方式,一种是直接使用navigator.of(context).push(),这种方式比较适合非常简单的应用,随着应用的不断发展,逻辑越来越多,推荐使用具名路由来管理应用,本文也是使用的这种方式。直接将路由挂在materialapp的ongenerateroute字段上即可,具体的路由定义放在了单独的文件中进行管理utils/router.dart:
import 'package:flutter/material.dart'; import 'package:movie/screens/home.dart'; import 'package:movie/screens/detail.dart'; import 'package:movie/screens/videoplayer.dart'; route<dynamic> generateroute(routesettings settings) { switch (settings.name) { case '/': return materialpageroute(builder: (context) => home()); case 'detail': var arguments = settings.arguments; return materialpageroute( builder: (context) => moviedetail(id: arguments)); case 'video': var arguments = settings.arguments; return materialpageroute( builder: (context) => videopage(url: arguments)); default: return materialpageroute(builder: (context) => home()); } }
真是像极了前端的路由定义,先将组件import进来,然后在各自的路由中return即可。
首页
在首页中使用tabbar来展示"正在热映"和"top250":
import 'package:flutter/material.dart'; import 'package:movie/screens/hot.dart'; class home extends statefulwidget { home({key key}) : super(key: key); _homestate createstate() => _homestate(); } class _homestate extends state<home> with singletickerproviderstatemixin { tabcontroller _tabcontroller; @override void initstate() { super.initstate(); _tabcontroller = tabcontroller(vsync: this, initialindex: 0, length: 2); } @override widget build(buildcontext context) { return scaffold( appbar: appbar( title: tabbar( controller: _tabcontroller, tabs: <widget>[ tab(text: '正在热映'), tab(text: 'top250'), ], ), ), body: tabbarview( controller: _tabcontroller, children: <widget>[ hot(), hot(history: true), ], ), ); } }
两个页面的布局是一样的,只有数据是不同的,所以我们复用这个页面hot,传入history参数来代表是否为top250页面
复用的hot组件
import 'package:flutter/material.dart'; import 'package:movie/utils/api.dart' as api; import 'package:movie/widgets/movieitem.dart'; class hot extends statefulwidget { final bool history; hot({key key, this.history = false}) : super(key: key); _hotstate createstate() => _hotstate(); } class _hotstate extends state<hot> with automatickeepaliveclientmixin { list _movielist = []; int start = 0; int total = 0; scrollcontroller _scrollcontroller = scrollcontroller(); @override void initstate() { super.initstate(); _scrollcontroller.addlistener(() { if (_scrollcontroller.position.pixels == _scrollcontroller.position.maxscrollextent) { getmore(); } }); this.query(init: true); } query({bool init = false}) async { map res = await api.getmovielist( history: widget.history, start: init ? 0 : this.start); var start = res['start']; var total = res['total']; var subjects = res['subjects']; setstate(() { if (init) { this._movielist = subjects; } else { this._movielist.addall(subjects); } this.start = start + 10; this.total = total; }); } future<null> _onrefresh() async { await this.query(init: true); } getmore() { if (start < total) { query(); } } @override bool get wantkeepalive => true; @override widget build(buildcontext context) { super.build(context); return refreshindicator( onrefresh: _onrefresh, child: listview.builder( controller: _scrollcontroller, itemcount: this._movielist.length, itembuilder: (buildcontext context, int index) => movieitem(data: this._movielist[index]), ), ); } }
电影的详情页面
点击单条电影时使用navigator.pushnamed(context, 'detail', arguments: data['id']);即可跳转详情页,在详情页中通过id再请求接口获取详情:
import 'package:flutter/material.dart'; import 'package:movie/widgets/detail/detailtop.dart'; import 'package:movie/widgets/detail/rateing.dart'; import 'package:movie/widgets/detail/actors.dart'; import 'package:movie/widgets/detail/photos.dart'; import 'package:movie/widgets/detail/comments.dart'; import 'package:movie/utils/api.dart' as api; class moviedetail extends statefulwidget { final id; moviedetail({key key, this.id}) : super(key: key); _moviedetailstate createstate() => _moviedetailstate(); } class _moviedetailstate extends state<moviedetail> { var _data = {}; @override void initstate() { super.initstate(); this.init(); } init() async { var res = await api.getmoviedetail(widget.id); setstate(() { _data = res; }); } @override widget build(buildcontext context) { return scaffold( body: _data.isempty ? center(child: circularprogressindicator(),) : safearea( child: container( height: mediaquery.of(context).size.height, width: mediaquery.of(context).size.width, child: listview( scrolldirection: axis.vertical, children: <widget>[ moviedetailtop(data: _data), rate(count: _data['ratings_count'], rating: _data['rating']), container(padding: edgeinsets.all(10),child: text(_data['summary'])), actors(directors: _data['directors'], casts: _data['casts']), photos(photos: _data['photos'],), comments(comments: _data['popular_comments']), ], ), ), ), ); } }
在详情页面中,我们封装了一些组件,这样能让项目更加容易阅读和维护,组件的具体实现就不详细介绍了,都是一些常用的原生组件,这些组件分别是:
真实数据来自哪里?
应用中的数据都是从豆瓣开发者api中拉取的,分别是,正在热映in_theaters,top250top250和电影详情subject/id三个接口,请求这些接口是需要apikey的,为了大家能方便请求数据,我将apikey上传到了github上,还请大家温柔点,不要将这个apikey干爆了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对移动技术网的支持。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Android apk 项目一键打包并上传到蒲公英的实现方法
Android 自定义LineLayout实现满屏任意拖动功能的示例代码
android 限制某个操作每天只能操作指定的次数(示例代码详解)
Android 集成 google 登录并获取性别等隐私信息的实现代码
网友评论