【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】使用Flutter開(kāi)發(fā)一款電影APP的示例_第1頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】使用Flutter開(kāi)發(fā)一款電影APP的示例_第2頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】使用Flutter開(kāi)發(fā)一款電影APP的示例_第3頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】使用Flutter開(kāi)發(fā)一款電影APP的示例_第4頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】使用Flutter開(kāi)發(fā)一款電影APP的示例_第5頁(yè)
已閱讀5頁(yè),還剩4頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】使用Flutter開(kāi)發(fā)一款電影APP的示例

在下給大家分享一下使用Flutter開(kāi)發(fā)一款電影APP的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!前言使用Flutter開(kāi)發(fā)一款A(yù)pp是一件非常愉快的事情,其出色的性能、跨多端以及數(shù)量眾多的原生組件都是我們選擇Flutter的理由!今天我們就來(lái)使用Flutter開(kāi)發(fā)一款電影類的App,先看下App的截圖。從main.dart開(kāi)始在Flutter里main.dart是應(yīng)用開(kāi)始的地方: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(),這種方式比較適合非常簡(jiǎn)單的應(yīng)用,隨著應(yīng)用的不斷發(fā)展,邏輯越來(lái)越多,推薦使用具名路由來(lái)管理應(yīng)用,本文也是使用的這種方式。直接將路由掛在MaterialApp的onGenerateRoute字段上即可,具體的路由定義放在了單獨(dú)的文件中進(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

()

{

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)來(lái),然后在各自的路由中return即可。首頁(yè)在首頁(yè)中使用TabBar來(lái)展示"正在熱映"和"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),

],

),

);

}

}兩個(gè)頁(yè)面的布局是一樣的,只有數(shù)據(jù)是不同的,所以我們復(fù)用這個(gè)頁(yè)面Hot,傳入history參數(shù)來(lái)代表是否為T(mén)op250頁(yè)面復(fù)用的Hot組件在這個(gè)組件中,通過(guò)history字段來(lái)區(qū)分成兩個(gè)頁(yè)面。在頁(yè)面initState的生命周期中,請(qǐng)求數(shù)據(jù),再進(jìn)行相應(yīng)的展示。下拉刷新的功能是使用的RefreshIndicator組件,在其onRefresh中進(jìn)行下拉時(shí)的邏輯處理。Flutter沒(méi)有直接提供上拉加載的組件,但是也是很容易實(shí)現(xiàn),通過(guò)ListView的controller來(lái)做判斷即可:當(dāng)前滾動(dòng)的位置是否到達(dá)最大滾動(dòng)位置_scrollController.position.pixels==_scrollController.position.maxScrollExtent為了獲得良好的用戶體驗(yàn),Tab來(lái)回切換的時(shí)候,我們不希望頁(yè)面重新渲染,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]),

),

);

}

}電影的詳情頁(yè)面點(diǎn)擊單條電影時(shí)使用Navigator.pushNamed(context,'detail',arguments:data['id']);即可跳轉(zhuǎn)詳情頁(yè),在詳情頁(yè)中通過(guò)id再請(qǐng)求接口獲取詳情: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:

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論