이번에는 Flutter를 사용하여 책 상세 정보 화면을 만드는 코드를 자세하게 분석해보겠습니다.
BookDetailScreen
클래스는 여러 화면에서 listItem container
를 클릭했을 때 전환되는 책 상세정보 화면입니다. 해당 화면에서는 책 표지를 비롯하여, 제목, 저자, 출판사, 책 소개 등의 정보를 나타내며, 해당 도서에 대한 감상평을 남길 수 있는 감상평 쓰기 버튼이 있습니다.
아래 코드에서는 Flutter
의 기본 라이브러리 외에도 책 리뷰 작성을 위한 화면인 WriteReviewWrapper
클래스와 데이터베이스에서 정보를 가져오는 함수들이 정의된 라이브러리를 임포트하고 있습니다.
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:military_bookstore/authentication/WriteReviewWrapper.dart';
import 'package:military_bookstore/database/get_aladin_database.dart';
import 'package:military_bookstore/database/get_database_Info.dart';
import 'package:military_bookstore/widget/appbar_widget.dart';
import 'package:military_bookstore/widget/drewer_widget.dart';
import 'package:military_bookstore/widget/nav_widget.dart';
import 'write_review_screen.dart';
아래 코드는 책 상세 정보를 표시하는 BookDetailScreen
클래스를 정의하고 있습니다. 이 클래스는 StatelessWidget
을 상속받아 구현되어 있으며, 책의 제목(bookTitle)을 매개변수로 받아와야 합니다.
class BookDetailScreen extends StatelessWidget {
final String bookTitle;
BookDetailScreen({super.key, required this.bookTitle});
Widget build(BuildContext context) {
// 화면 크기 및 비율 계산
double deviceWidth = MediaQuery.of(context).size.width;
double deviceHeight = MediaQuery.of(context).size.height;
double widthRatio = deviceWidth / 375;
double heightRatio = deviceHeight / 812;
return Scaffold(
appBar: appbar_widget(context),
drawer: drewer_widget(context),
body: Center(
child: Container(
height: widthRatio * 812,
clipBehavior: Clip.antiAlias,
// 배경색상 설정
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment(-0.00, -1.00),
end: Alignment(0, 1),
colors: [
Color(0xA545B0C5),
Color(0xFF4580C5),
Color(0xFF4580C5)
],
),
),
child: Column(
children: [
nav_widget(context),
// ... 생략 ...
],
)),
),
);
}
}
아래 코드는 책의 이미지와 감상평 쓰기 버튼, 제목, 저자, 출판사 등을 표시하기 위해 정보를 불러오는 함수들 입니다. 이 함수들을 통해 FutureBuilder
로 정보를 가져오고 있습니다.
Future<Image> getBookImage(String bookTitle) async {
FirebaseFirestore _firestore = FirebaseFirestore.instance;
QuerySnapshot querySnapshot = await _firestore
.collection('bookInfos')
.where('title', isEqualTo: bookTitle)
.limit(1)
.get();
Map<String, dynamic>? data = querySnapshot.docs[0].data() as Map<String, dynamic>?;
String imageUrl = data!['thumbnail'];
return getImage(imageUrl);
}
Future<Image> getImage(String imageUrl) async {
if (imageUrl.isEmpty) {
throw Exception('$imageUrl');
}
try {
http.Response response = await http.get(Uri.parse(imageUrl));
if (response.statusCode == 200) {
return Image.memory(response.bodyBytes);
} else {
throw Exception('Failed to load image - ${response.statusCode}');
}
} catch (e) {
throw Exception('Failed to load image - $e');
}
}
Future<String> getAladinDescription(String bookTitle) async {
FirebaseFirestore _firestore = FirebaseFirestore.instance;
QuerySnapshot querySnapshot = await _firestore
.collection('aladinBooks')
.where('title', isEqualTo: bookTitle)
.limit(1)
.get();
Map<String, dynamic>? data = querySnapshot.docs[0].data() as Map<String, dynamic>?;
String bookContents = data!['description'];
return bookContents;
}
Future<String> getAladinAuthors(String bookTitle) async {
FirebaseFirestore _firestore = FirebaseFirestore.instance;
QuerySnapshot querySnapshot = await _firestore
.collection('aladinBooks')
.where('title', isEqualTo: bookTitle)
.limit(1)
.get();
Map<String, dynamic>? data = querySnapshot.docs[0].data() as Map<String, dynamic>?;
String authorsString = data!['author'];
return authorsString;
}
Future<String> getAladinPublisher(String bookTitle) async {
FirebaseFirestore _firestore = FirebaseFirestore.instance;
QuerySnapshot querySnapshot = await _firestore
.collection('aladinBooks')
.where('title', isEqualTo: bookTitle)
.limit(1)
.get();
Map<String, dynamic>? data = querySnapshot.docs[0].data() as Map<String, dynamic>?;
String publisher = data!['publisher'];
return publisher;
}
감상평 쓰기 버튼은 GestureDetector
를 사용하여 터치 이벤트를 처리하고 있습니다. 이 감상평 쓰기
버튼을 클릭하면 해당 책에 대한 감상평을 작성하는 페이지로 전환됩니다. 감상평 쓰기 페이지는 다음 글에서 자세히 다루도록 하겠습니다.
Container(
width: widthRatio * 155,
height: heightRatio * 30,
alignment: Alignment.topRight,
child: GestureDetector(
child: Container(
padding: EdgeInsets.symmetric(vertical: heightRatio * 5),
width: widthRatio * 90,
decoration: ShapeDecoration(
color: Color(0xFF46B0C6),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
shadows: [
BoxShadow(
color: Color(0x3F000000),
blurRadius: 4,
offset: Offset(0, 4),
spreadRadius: 0,
)
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: widthRatio * 2),
Text(
"감상평 쓰기",
style: TextStyle(
fontSize: 12,
fontFamily: 'GowunBatang',
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(width: widthRatio * 2),
Icon(
Icons.edit,
color: Colors.white,
size: 13,
),
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WriteReviewWrapper(
bookTitle: bookTitle,
),
),
);
},
),
),