前言

使用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 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 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: [

Tab(text: '正在热映'),

Tab(text: 'TOP250'),

],

),

),

body: TabBarView(

controller: _tabController,

children: [

Hot(),

Hot(history: true),

],

),

);

}

}

两个页面的布局是一样的,只有数据是不同的,所以我们复用这个页面Hot,传入history参数来代表是否为Top250页面

复用的Hot组件

在这个组件中,通过history字段来区分成两个页面。

在页面initState的生命周期中,请求数据,再进行相应的展示。

下拉刷新的功能是使用的RefreshIndicator组件,在其onRefresh中进行下拉时的逻辑处理。

Flutter没有直接提供上拉加载的组件,但是也是很容易实现,通过ListView的controller来做判断即可:当前滚动的位置是否到达最大滚动位置_scrollController.position.pixels == _scrollController.position.maxScrollExtent

为了获得良好的用户体验,Tab来回切换的时候,我们不希望页面重新渲染,Flutter提供了混入类AutomaticKeepAliveClientMixin,重载wantKeepAlive即可,下面是完整的代码:

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 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 _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 {

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: [

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']),

],

),

),

),

);

}

}

在详情页面中,我们封装了一些组件,这样能让项目更加容易阅读和维护,组件的具体实现就不详细介绍了,都是一些常用的原生组件,这些组件分别是:

widgets/detail/detailTop.dart 页面顶部的电影概述

widgets/detail/rateing.dart 评分组件

widgets/detail/actors.dart 演员表

widgets/detail/photos.dart 剧照

widgets/detail/comments.dart 评论组件

真实数据来自哪里?

应用中的数据都是从豆瓣开发者api中拉取的,分别是,正在热映in_theaters,top250top250和电影详情subject/id三个接口,请求这些接口是需要apikey的,为了大家能方便请求数据,我将apikey上传到了github上,还请大家温柔点,不要将这个apikey干爆了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

android电影app开发,如何使用Flutter开发一款电影APP详解相关推荐

  1. 什么是移动端开发【重点学习系列---干货十足--一万字详解】

    引言 这一篇文章主要对移动端开发相关的基础知识点,进行总结.从移动端开发的一些概念.专有名词.缩放.viewport移动端事件.适配问题以及一些工作中沟通经常会用到这些方面来说一下移动端 文章目录 引 ...

  2. 四.卡尔曼滤波器(EKF)开发实践之四: ROS系统位姿估计包robot_pose_ekf详解

    本系列文章主要介绍如何在工程实践中使用卡尔曼滤波器,分七个小节介绍: 一.卡尔曼滤波器开发实践之一: 五大公式 二.卡尔曼滤波器开发实践之二:  一个简单的位置估计卡尔曼滤波器 三.卡尔曼滤波器(EK ...

  3. IOS开发环境更换后重新制作Provisioning Profile证书详解

    IOS开发环境更换后重新制作Provisioning Profile证书详解 新换了台Macbook,又折腾了一遍Provisioning Profile证书,苹果的证书繁锁复杂,每次制作都相当麻烦, ...

  4. 【Android语音合成TTS】百度语音接入方法,和使用技巧详解

    请尊重他人的劳动成果,转载请注明出处:[Android语音合成TTS]百度语音接入方法,和使用技巧详解 Ps. 依托于百度开放云,百度语音为合作伙伴提供了业界领先.永久免费的语音技术服务,目前已上线的 ...

  5. Flutter中Scaffold布局的使用详解及实例代码

    Flutter中Scaffold布局的使用详解及实例代码 Scaffold实现了基本的Material布局.只要是在Material中定义了的单个界面显示的布局控件元素,都可以使用Scaffold来绘 ...

  6. Flutter(Dart)基础——函数详解

    Flutter(Dart)基础--函数详解 在Dart中,函数(或方法)也是对象,它的类型是 Function. 这意味着,函数可以赋值给变量,也可以当做其他函数的参数. 函数的声明 基本上与Java ...

  7. Android基础入门教程——8.3.1 三个绘图工具类详解

    Android基础入门教程--8.3.1 三个绘图工具类详解 标签(空格分隔): Android基础入门教程 本节引言: 上两小节我们学习了Drawable以及Bitmap,都是加载好图片的,而本节我 ...

  8. android 6.0 存储卡,Android 6.0区别U盘和SD卡设备的方法详解

    如下所示: public static boolean isSdcardExists(Context context) { StorageManager storageManager = Storag ...

  9. Flutter开发之搭建Flutter开发环境(三)

    回首demo.之前的工程突然,无法iOS上运行了.重装了最新的Xcode.然后VS Code 终端运行 flutter packages get 再打开Xcode 设置开发证书.再在iOS真机或者模拟 ...

最新文章

  1. 如何构建优质的推荐系统服务?| 技术头条
  2. Spark基础知识解答
  3. 桌面支持--ZWMECH软件卸载工具
  4. Python-EEG工具库MNE-Python详细安装与使用
  5. netfilter与iptables表规则建立
  6. 正确认识使用UML中的类图——辨析类图的两种存在形式
  7. 代码UITableView点击cell跳转
  8. sqlserver中删除重复行的方法
  9. c语言中 printf(quot;nquot;),关于C语言 printf(quot;%d\nquot;,printf(quot;%dquot;,printf(quot;%dquot;...
  10. 信用逾期3年是不是一定会坐牢?
  11. 论文学习2-Incorporating Graph Attention Mechanism into Knowledge Graph Reasoning Based on Deep Reinforce
  12. mysql 模糊查询 s_MySql反向模糊查询
  13. Hadoop——HDFS(2)
  14. 【PowerShell】逐行处理文本示例
  15. linux usb bulk传输,2.1.1.2. USB MSC Bulk-Only (BBB) Transport
  16. 梁宁——产品的场景(阅读总结)
  17. SubsamplingScaleImageView + Glide显示网络超大图片
  18. 【数据结构—图】拓扑Topo排序
  19. 【Debug】安装labelme过程中出现的问题
  20. C语言基础知识:*p++与*++p;(*p)++  与 ++(*p)的理解

热门文章

  1. 自动化测试框架 splinter安装
  2. chrome浏览器数据消失_使用Chrome的数据保护器节省带宽
  3. 大数据技术基础笔记1 大数据概述
  4. mysql出现10061错误
  5. 扫地机器人排行 2017最新扫地机器人排行榜曝光
  6. 和我一起学 Three.js 【初级篇】:2. 掌握几何体
  7. Route-Map个人理解及实验解析
  8. 数论四大定理之欧拉定理
  9. Android Studio 解决错误 Could not find method android() for arguments
  10. C++类(Class)的定义与实现