在home資料夾下新增「movie_detail_page.dart」
首先先設定建構子,傳入要顯示的電影資訊,並初始化YoutubeRepository和YoutubeBloc(要記得引入youtube.dart)。
class MovieDetailPage extends StatefulWidget {
final posterPath;
final overview;
final releaseDate;
final title;
final voteAverage;
final movieId;
MovieDetailPage(
{Key key,
this.posterPath,
this.overview,
this.releaseDate,
this.title,
this.voteAverage,
this.movieId})
: super(key: key);
@override
_MovieDetailPageState createState() => _MovieDetailPageState();
}
class _MovieDetailPageState extends State<MovieDetailPage> {
String get posterPath => widget.posterPath;
String get overview => widget.overview;
String get releaseDate => widget.releaseDate;
String get title => widget.title;
String get voteAverage => widget.voteAverage.toString();
String get movieId => widget.movieId.toString();
bool isOverviewSelected = false;
YoutubeBloc _youtubeBloc;
YoutubeRepository _youtubeRepository;
@override
void initState() {
_youtubeRepository = YoutubeRepository();
_youtubeBloc = YoutubeBloc(youtubeRepository: _youtubeRepository);
_youtubeBloc.dispatch(SearchYoutubeEvent("$title 預告片"));
super.initState();
}
}
接下來是UI的程式碼
做到了以下幾個功能:
SliverAppBar
讓AppBar在向下滑動的時候會被隱藏起來SliverList
包覆起來GestureDetector
讓使用者可以縮放大綱文字BlocBuilder
監聽YoutubeBloc狀態,顯示搜尋到的預告片 @override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: false,
bottom: false,
child: CustomScrollView(slivers: <Widget>[
SliverAppBar(
expandedHeight: 200.0,
floating: false,
pinned: false,
elevation: 0.0,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://image.tmdb.org/t/p/w500${posterPath}",
fit: BoxFit.cover,
)),
),
SliverList(
delegate: SliverChildListDelegate(
[
Container(margin: EdgeInsets.only(top: 5.0)),
Text(
title,
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Row(
children: <Widget>[
Icon(
Icons.favorite,
color: Colors.red,
),
Container(
margin: EdgeInsets.only(left: 1.0, right: 1.0),
),
Text(
voteAverage,
style: TextStyle(
fontSize: 18.0,
),
),
Container(
margin: EdgeInsets.only(left: 10.0, right: 50.0),
),
Text(
"上映日期:${releaseDate}",
style: TextStyle(
fontSize: 16.0,
),
),
],
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
isOverviewSelected
? GestureDetector(
onTap: () => setState(() {
isOverviewSelected = !isOverviewSelected;
}),
child: Text(overview),
)
: GestureDetector(
onTap: () => setState(() {
isOverviewSelected = !isOverviewSelected;
}),
child: Column(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200),
child: Text(
overview,
softWrap: true,
overflow: TextOverflow.visible,
maxLines: 2,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.arrow_drop_down),
Text('閱讀全文'),
],
)
],
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Text(
"Trailer",
style: TextStyle(
fontSize: 28.0,
fontWeight: FontWeight.bold,
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
BlocBuilder(
bloc: _youtubeBloc,
builder: (context, state) {
if (state is YoutubeSuccessState) {
return trailerWidget(state.ytResult);
}
return Center(child: CircularProgressIndicator(),);
},
),
],
),
)
])),
);
}
}
稍微介紹一下SliverList
和SliverAppBar
A sliver is a portion of a scrollable area. You can use slivers to achieve custom scrolling effects.
以上是Flutter官方對Sliver的解釋,非常清楚Sliver代表可以「滑動」的區域。
平常使用的ListView或是GridView也是由Sliver所實做出來的。
使用Sliver的好處是可以創造出更豐富的滑動效果,或是我們這邊要的——讓AppBar能自動隱藏。
想知道如何使用或是更多實際的效果可以看這篇medium
在home資料夾下新增「trailer_widget.dart」
創造一個能把YoutubeBloc回傳的影片資訊顯示出來的GridView。
程式碼:
import 'package:flutter/material.dart';
import 'package:youtube_api/youtube_api.dart';
import '../youtube/youtube_player_dialog.dart';
Widget trailerWidget(List<YT_API> videos) {
if (videos.length > 0) {
return GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: videos.length > 4 ? 4 : videos.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context, index) {
return Column(
children: <Widget>[
GestureDetector(
child: Image.network(videos[index].thumbnail['default']['url']),
onTap: () => showDialog(
context: context,
builder: (context) => YoutubePlayerDialog(
videoUrl: videos[index].id,
)),
),
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 130),
child: Text(
videos[index].title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
)
],
);
},
);
} else {
return Center(
child: Text(
'找尋不到影片...',
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w900),
),
);
}
}
shrinkWrap
一定要設定為true,不然GridView會被無限拉大。itemCount
可以依照你的需求調整要顯示的影片數量。
在youtube資料夾新增「youtube_player_dialog.dart」,當使用者點擊影片縮圖就彈出一個Youtube的影片撥放器播放預告片。
程式碼很簡單,使用上次載好的Youtube_Player套件給它影片的id就可以了。
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import 'package:flutter/material.dart';
class YoutubePlayerDialog extends StatefulWidget {
final String _videoUrl;
YoutubePlayerDialog({Key key, String videoUrl})
: _videoUrl = videoUrl,
super(key: key);
@override
_YoutubePlayerDialogState createState() => _YoutubePlayerDialogState();
}
class _YoutubePlayerDialogState extends State<YoutubePlayerDialog> {
String get videoUrl => widget._videoUrl;
@override
Widget build(BuildContext context) {
return Dialog(
child: YoutubePlayer(
context: context,
videoId: videoUrl,
flags: YoutubePlayerFlags(
autoPlay: true,
showVideoProgressIndicator: true,
),
),
);
}
}
在Android跳轉頁面是用Intent
而在Flutter是使用Navigator.push
。
開啟show_movie_widget.dart增加點擊跳轉頁面的程式碼。
GestureDetector(
onTap: () =>Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MovieDetailPage(
posterPath: movieList
.results[currentPage.round()].backdropPath,
overview:
movieList.results[currentPage.round()].overview,
title: movieList.results[currentPage.round()].title,
releaseDate: movieList
.results[currentPage.round()].releaseDate,
voteAverage: movieList
.results[currentPage.round()].voteAverage,
movieId: movieList.results[currentPage.round()].id,
))),
child: Padding(padding: EdgeInsets.only(top: 10.0),
child: Text(
'點擊看更多細節與預告片',
style: TextStyle(
color: Colors.amberAccent,
fontSize: 14.0,
fontWeight: FontWeight.bold),
),)
),
今天把電影細節頁面的排版完成、也把播放預告片的功能做完了。比較可惜的是影片只有單純地用關鍵字在Youtube搜尋,可能會找到同名的影片甚至完全無關的,這部分可能就要額外處理了。
我想明天就多增加一個留言功能讓大家能夠討論電影心得,為了能快速開發就使用Firebase提供的Cloud Firestore作為我們的資料庫吧。
完整程式碼在這裡-> FlutTube Github