android开发分享如何使用Flutter开发一款电影APP详解

前言 使用flutter开发一款app是一件非常愉快的事情,其出色的性能、跨多端以及数量众多的原生组件都是我们选择flutter的理由!今天我们就来使用flutter开发

前言

使用flutter开发一款app是一件非常愉快的事情,其出色的性能、跨多端以及数量众多的原生组件都是我们选择flutter的理由!今天我们就来使用flutter开发一款电影类的app,先看下app的截图。

如何使用Flutter开发一款电影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(),这种方式比较适合非常简单的应用,随着应用的不断发展,逻辑越来越多,推荐使用具名路由来管理应用,android开发分享如何使用Flutter开发一款电影APP详解也是使用的这种方式。直接将路由挂在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组件

  • 在这个组件中,通过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<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']),           ],          ),         ),        ),    );   }  }

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

  • 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开发分享如何使用Flutter开发一款电影APP详解的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对<计算机技术网(www.ctvol.com)!!>的支持。

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/900789.html

(0)
上一篇 2021年10月24日
下一篇 2021年10月24日

精彩推荐