지난 포스트에서 우주 사진/비디오 리스트 뷰를 완성 했다. 이제 리스트 아이템을 클릭 했을 때 보여질 상세 뷰를 만들어 보자.
Flutter 앱 개발 11 : 우주 사진/비디오 리스트뷰
지난 포스트에서 BLoC 패턴을 활용한 서버 연동 부분을 구현해 보았다. 이제 리스트 뷰 UI 를 연동해 보자. Flutter 앱 개발 10 : 우주 사진/비디오 데이터 가져오기 (BLoC) 이번 포스트에서는 BLoC 패턴
drogrammer.tistory.com
1. 필요 패키지 의존성 추가 (youtube_player_flutter)
이번 포스트에서 사용할 패키지는 loading_animation, extended_image, youtube_player_flutter 이다. 앞의 두가지는 이미 지난 포스트에서 의존성을 추가해 두었으므로, 추가하지 않았던 youtube_player_flutter 를 pubspec.yaml 에 추가해 주자.
...
dependencies:
loading_animations: 2.1.0 # 지난 포스트에서 이미 추가함
extended_image: ^1.5.0 # 지난 포스트에서 이미 추가함
youtube_player_flutter: ^7.0.0+7 # Youtube 패키지
...
Youtube 패키지를 사용하려면, 안드로이드의 경우 minSdkVersion 을 17이상으로 변경해야 한다.
android > app > build.gradle 파일을 아래와 같이 변경한다.
...
android {
...
defaultConfig {
...
minSdkVersion 17 // minSdkVersion 을 17로 변경
...
}
...
}
2. 우주 사진/비디오 설명 위젯 추가 (ApodDescription)
우주 사진/비디오 상세 뷰에서 활용할 설명 위젯을 추가하자. lib/widget/apod_description.dart 파일을 추가한다.
사진/비디오의 제목, 설명, 날짜, 저작권 정보를 받아서 표시하는 위젯으로 아래와 같은 레이아웃을 가진다.

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class ApodDescription extends StatelessWidget {
final String title; // 사진/비디오 제목
final String contents; // 사진/비디오 설명
final DateTime date; // 날짜
final String copyright; // 저작권 정보
ApodDescription({this.title, this.contents, this.date, this.copyright});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
DateFormat('yyyy MM dd').format(date),
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontFamily: 'NexonLv2GothicMedium',
),
),
),
Text(
title,
style: TextStyle(
fontSize: 24,
color: Colors.white,
),
),
// 저작권 정보가 있으면 표시, 없으면 빈 Container 추가
copyright != null
? Padding(
padding: EdgeInsets.only(top: 6),
child: Text(
"Image Credit & Copyright: $copyright",
style: TextStyle(
fontSize: 13,
color: Colors.white,
),
),
)
: Container(),
Padding(
padding: EdgeInsets.only(top: 25),
child: Text(
contents,
style: TextStyle(
fontSize: 16,
color: Colors.white,
height: 1.5,
),
),
),
],
);
}
}
3. 우주 사진/비디오 상세 뷰 추가 (ApodDetail)
우주 사진/비디오 상세 뷰를 추가하자. lib/view/apod_detail.dart 파일을 추가하자.
코드 중 핵심적인 부분을 설명하면,
- 컨텐츠와 부가 설명을 리스트뷰에 넣어서 보여준다.
- 컨텐츠가 비디오일 경우 유튜브 플레이어를 활용하여 동영상을 자동 재생한다.
- 이미지의 경우 네트워크로부터 사진을 받아서 보여주며, 로딩 과정에는 로딩 애니메이션을 보여준다.
- 사진/비디오 리스트 뷰로부터 상세 뷰로 전환 시, 이미지의 경우에만 히어로 애니메이션을 사용한다.
- 제목 문자열은 다국어를 지원한다. (다국어 지원 포스트 참고)
아래 레이아웃 및 코드를 참고하기 바란다.

import 'package:apod/data/apod.dart';
import 'package:apod/widget/apod_description.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:loading_animations/loading_animations.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import 'package:easy_localization/easy_localization.dart';
class ApodDetail extends StatelessWidget {
final Apod apod; // 선택된 사진/비디오의 상세 정보 (data/apod.dart)
final String tagId; // Hero 애니메이션을 위한 ID
ApodDetail({this.apod, this.tagId});
@override
Widget build(BuildContext context) {
YoutubePlayerController controller;
if (apod.isVideo) {
// 컨텐츠가 비디오면 유튜브 플레이어 컨트롤러 초기화
controller = YoutubePlayerController(
// 비디오 URL 등록
initialVideoId: YoutubePlayer.convertUrlToId(apod.hdUrl),
// 자동 시작 활성화
flags: YoutubePlayerFlags(
autoPlay: true,
),
);
}
// 전체 화면 뷰 이므로 Scaffold 위젯 추가
return Scaffold(
// AppBar 를 추가하고 다국어 처리 되어 있는 제목 텍스트 추가
appBar: AppBar(
title: Text('title'.tr()),
),
// 컨텐츠가 길어질 수 있으므로 스크롤가능한 리스트뷰 추가
body: ListView(
children: [
apod.isVideo == true
// 비디오면 유튜브 플레이어를 추가함.
? YoutubePlayer(
controller: controller,
bottomActions: [
// 플레이어 아래에 재생 위치, 재생 컨트롤 바, 남은 시간 표시
CurrentPosition(),
ProgressBar(isExpanded: true),
RemainingDuration(),
],
)
// Hero 애니메이션을 위한 위젯. (이미지만 Hero 애니메이션 사용)
: Hero(
tag: tagId,
// 네트워크로 부터 이미지 다운로드 후 화면에 보여주는 위젯
child: ExtendedImage.network(
apod.url,
cache: true,
fit: BoxFit.cover,
loadStateChanged: (state) {
switch (state.extendedImageLoadState) {
// 이미지 로딩 중일 경우 로딩 애니메이션 표시
case LoadState.loading:
return LoadingFadingLine.circle(
backgroundColor: Colors.white,
);
break;
case LoadState.completed:
break;
case LoadState.failed:
break;
}
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
// 사진/비디오 상세 설명 텍스트 위젯
child: ApodDescription(
title: apod.title,
contents: apod.description,
date: apod.date,
copyright: apod.copyright,
),
),
],
),
);
}
}
4. 우주 사진/비디오 리스트와 연결
지금까지 만든 우주 사진/비디오 상세 뷰 (ApodDetail) 를 우주 사진/비디오 리스트와 연결해 보자. 이전포스트에서 만든 리스트 타일 위젯의 onTap 콜백에서 ApodDetail을 띄워주면 끝이다.
lib/widget/apod_tile.dart 를 아래와 같이 수정하자.
...
import 'package:apod/view/apod_detail.dart';
...
class ApodTile extends StatelessWidget {
...
@override
Widget build(BuildContext context) {
...
return InkWell(
onTap: () => {
// ApodDetail 뷰로 전환한다.
Navigator.of(context).push(
MaterialPageRoute(
builder: (ctx) => ApodDetail(apod: apod, tagId: id),
),
)
},
...
);
}
}
5. 결과
아래와 같이 리스트 아이템 (타일) 을 선택하면 사진/비디오 상세뷰로 전환되는 것을 확인 할 수 있다.

댓글