小編給大家分享一下使用Flutter開發(fā)一款電影APP的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
雅安網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,雅安網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為雅安1000+提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請找那個售后服務(wù)好的雅安做網(wǎng)站的公司定做!
前言
使用Flutter開發(fā)一款A(yù)pp是一件非常愉快的事情,其出色的性能、跨多端以及數(shù)量眾多的原生組件都是我們選擇Flutter的理由!今天我們就來使用Flutter開發(fā)一款電影類的App,先看下App的截圖。
從main.dart開始
在Flutter里main.dart是應(yīng)用開始的地方:
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(),這種方式比較適合非常簡單的應(yīng)用,隨著應(yīng)用的不斷發(fā)展,邏輯越來越多,推薦使用具名路由來管理應(yīng)用,本文也是使用的這種方式。直接將路由掛在MaterialApp的onGenerateRoute字段上即可,具體的路由定義放在了單獨的文件中進(jìn)行管理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進(jìn)來,然后在各自的路由中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), ], ), ); } }
兩個頁面的布局是一樣的,只有數(shù)據(jù)是不同的,所以我們復(fù)用這個頁面Hot,傳入history參數(shù)來代表是否為Top250頁面
復(fù)用的Hot組件
在這個組件中,通過history字段來區(qū)分成兩個頁面。
在頁面initState的生命周期中,請求數(shù)據(jù),再進(jìn)行相應(yīng)的展示。
下拉刷新的功能是使用的RefreshIndicator組件,在其onRefresh中進(jìn)行下拉時的邏輯處理。
Flutter沒有直接提供上拉加載的組件,但是也是很容易實現(xiàn),通過ListView的controller來做判斷即可:當(dāng)前滾動的位置是否到達(dá)最大滾動位置_scrollController.position.pixels == _scrollController.position.maxScrollExtent
為了獲得良好的用戶體驗,Tab來回切換的時候,我們不希望頁面重新渲染,F(xiàn)lutter提供了混入類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']);即可跳轉(zhuǎn)詳情頁,在詳情頁中通過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']), ], ), ), ), ); } }
在詳情頁面中,我們封裝了一些組件,這樣能讓項目更加容易閱讀和維護(hù),組件的具體實現(xiàn)就不詳細(xì)介紹了,都是一些常用的原生組件,這些組件分別是:
widgets/detail/detailTop.dart 頁面頂部的電影概述
widgets/detail/rateing.dart 評分組件
widgets/detail/actors.dart 演員表
widgets/detail/photos.dart 劇照
widgets/detail/comments.dart 評論組件
真實數(shù)據(jù)來自哪里?
應(yīng)用中的數(shù)據(jù)都是從豆瓣開發(fā)者api中拉取的,分別是,正在熱映in_theaters,top250top250和電影詳情subject/id三個接口,請求這些接口是需要apikey的,為了大家能方便請求數(shù)據(jù),我將apikey上傳到了github上,還請大家溫柔點,不要將這個apikey干爆了。
以上是“使用Flutter開發(fā)一款電影APP的示例”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前文章:使用Flutter開發(fā)一款電影APP的示例
當(dāng)前路徑:http://bm7419.com/article24/gejije.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、標(biāo)簽優(yōu)化、響應(yīng)式網(wǎng)站、ChatGPT、小程序開發(fā)、虛擬主機
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)