9. 플러터 : 사진 배치

여러 장의 사진을 다뤄보자.
앞에서 Row와 Column 위젯을 배웠으니까
아래 사진처럼 출력하는 것은 어렵지 않다고 생각할 것이다.
사용한 사진은 "7. 플러터 : 사진 (1)"에 들어있다.

그런데 내가 갖고 있는 4장의 사진은 크기가 다르다.
1번과 2번 사진의 크기가 같고 3번과 4번 사진의 크기가 같다.
화면에서는 1, 3, 4, 2 순서로 출력하고 있다.
그리고 사진 주변으로 약간의 여백을 줬다.


일반적인 방법을 사용한다면
출력할 사진의 영역을 구하기만 하면 된다.
이번 코드에서는 너비와 높이를 똑같이 줬고, 수평 크기를 절반으로 나눴기 때문에 너비(width)만 알면 된다.
화면의 크기는 MediaQuery 클래스를 통해 할 수 있다.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '사진 배치',
home: Scaffold(
appBar: AppBar(title: Text('사진 배치'),),
body: MyApp(),
),
));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width ~/ 2;
return Column(
children: <Widget>[
makeRow('images/family_1.jpg', 'images/family_3.jpg', width: width.toDouble()),
makeRow('images/family_4.jpg', 'images/family_2.jpg', width: width.toDouble()),
],
);
}

Widget makeRow(String leftPath, String ritePath, {double width}) {
return Row(
children: <Widget>[
Container(
child: Image.asset(leftPath, width: width-10, height: width-10),
padding: EdgeInsets.all(5.0),
),
Container(
child: Image.asset(ritePath, width: width-10, height: width-10),
padding: EdgeInsets.all(5.0),
),
],
);
}
}


~/ 연산은 정수 나눗셈을 수행한다. width 변수의 자료형은 int가 되고
makeRow 함수에 직접 전달할 수 없기 때문에 toDouble 함수로 형변환을 한다.

makeRow 함수에서 사진 2장을 수평으로 출력한다.
이때 4방향 모두에 대해 여백을 주고 싶기 때문에 margin 또는 padding 옵션이 필요하다.
문제는 Image 클래스에는 이런 옵션이 없다는 점.
그래서 Container 클래스로 감싸서 이 부분을 처리하게 된다.

그렇다면 출력된 사진의 실제 크기는 어떻게 될까?
패딩을 줬다면 패딩만큼 줄어든 크기가 되는 것인가?
아니다.
패딩은 Container 위젯에 줬기 때문에 Image 위젯과는 상관이 없다.
Image 위젯을 생성할 때 10을 빼지 않으면 화면을 벗어나기 때문에 원하는 결과를 얻지 못한다.
꼭 직접 확인해 볼 것.


두 번째 예제를 보자.
첫 번째 예제에서는 가로와 세로 크기가 같았지만, 이번에는 가로와 세로 비율이 달라질 수 있고
중요한 것은 화면을 꽉 채우고 싶다는 것이다.


쉽게 보면, 가로와 세로 크기를 알면 된다.
가로 크기는 앞의 예제에서 구했고 세로 크기만 구하면 된다.
두 장의 사진을 비교해서 적절한 비율을 찾은 다음에 가로(너비)에 곱하면 세로(높이)를 구할 수 있다.

그러나 최신의 언어와 도구를 사용하고 있다면
계산하지 않고도 구할 수 있는 방법이 있지 않을까?
Expanded와 IntrinsicHeight 클래스의 조합으로 그와 같은 일을 할 수 있다.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '사진 배치',
home: Scaffold(
appBar: AppBar(title: Text('사진 배치'),),
body: MyApp(),
),
));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
makeRow('images/family_1.jpg', 'images/family_3.jpg'),
makeRow('images/family_4.jpg', 'images/family_2.jpg'),
],
);
}

Widget makeRow(String leftPath, String rightPath) {
return IntrinsicHeight(
child: Row(
children: <Widget>[
makeExpandedImage(leftPath),
makeExpandedImage(rightPath),
],
crossAxisAlignment: CrossAxisAlignment.stretch,
),
);
}

Widget makeExpandedImage(String imagePath) {
return Expanded(
child: Container(
child: Image.asset(imagePath, fit: BoxFit.cover),
margin: EdgeInsets.all(5.0),
),
);
}
}


수평에 들어가는 모든 사진은 같은 너비를 가져야 한다.
사진 각각에 대해 Expanded 위젯으로 감싼 다음에 Row 또는 Column 위젯에 전달하면 된다.
이때 Image 객체의 크기를 여백(padding 또는 margin)만큼 줄여주지 않아도 된다.
수평에 들어가는 위젯의 대상이 Container이기 때문이고 사진은 Container 크기에서 margin만큼 뺀 크기로 자동 설정된다.

다만 이렇게 하면 Image 객체의 너비만 같고 높이는 같지 않게 된다.
CrossAxisAlignment 클래스(enum)의 stretch 옵션으로 수직으로 늘려주면 높이도 같아진다.
그러나, 어느 정도로 늘려줘야 하는지에 대한 기준이 없기 때문에 결과가 분명하게 나오지 않는다.
IntrinsicHeight 클래스는 자식 위젯이 갖고 있는 원래 크기에 맞게 자식 위젯의 크기를 설정한다.
이 말은 하위 자식 위젯들에 대해 Row 위젯과 같은 높이가 되도록 설정하는 것을 말한다.
역시 IntrinsicHeight 객체로 감싸지 않은 상태에서의 결과도 확인해 봐야 할 것이다.

'플러터' 카테고리의 다른 글

11. 플러터 : 버튼  (0) 2019.02.07
10. 플러터 : 사진 옵션(BoxFit)  (0) 2019.02.03
8. 플러터 : 사진 (2)  (0) 2019.02.02
7. 플러터 : 사진 (1)  (0) 2019.02.02
6. 플러터 : 텍스트 집합(Row + Column)  (0) 2019.02.02