91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Flutter開發一款電影APP的示例

發布時間:2021-02-04 10:12:24 來源:億速云 閱讀:302 作者:小新 欄目:移動開發

小編給大家分享一下使用Flutter開發一款電影APP的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

前言

使用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(),這種方式比較適合非常簡單的應用,隨著應用的不斷發展,邏輯越來越多,推薦使用具名路由來管理應用,本文也是使用的這種方式。直接將路由掛在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干爆了。

以上是“使用Flutter開發一款電影APP的示例”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

葫芦岛市| 大同县| 鄂伦春自治旗| 天祝| 射洪县| 新昌县| 武安市| 增城市| 灵武市| 大厂| 浦东新区| 修水县| 上思县| 驻马店市| 富阳市| 潞城市| 都昌县| 福贡县| 岫岩| 云林县| 遂川县| 望城县| 芦山县| 宁陕县| 乐至县| 富民县| 绵阳市| 灵武市| 台山市| 浪卡子县| 团风县| 普安县| 靖西县| 江油市| 象州县| 伊春市| 金寨县| 竹北市| 江北区| 凤庆县| 明溪县|