
1. 박스 1개 만들기

- double.infinity는 무한대

2. 박스 3개 만들기
- 컬럼은 세로 정렬
- 로우는 가로 정렬
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:recipe_app2/components/recipe_menu_item.dart'; import '../components/recipe_body.dart'; import '../components/recipe_menu.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ), // 새로 방향 레이아웃 -> 자식이 없을때 크기 : 0, 0, 0, 0 ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), //시그니처 매개변수 키 값이 없다, 그 위젯의 핵심은 시그니처로 키 값을 넣지 않는다. SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }

- 컬럼 // 세로 : 블락, 가로 : 인라인
- 로우 // 가로 : 블락, 세로 : 인라인
- 자식이 큰게 들어오면 다 깨짐 → 컬럼 자체를 미리 키워놔야 함

- 컨테이너는 끝까지 차지함
- 자식이 없으면 블락
- 자식이 있으면 인라인


- ListView는 최소 값이 가로가 double.infinity라서 width가 안보임
크기를 조절하려면 부모를 만들어서 크기 조절하기

3. 외워야함!!
ㅤ | 인라인 | 블락 | 스타트 | 센터 |
Colum | 가로 | 세로 | 세로 | 가로 |
Row | 세로 | 가로 | 가로 | 세로 |
Container | 자식O | 자식 X | ㅤ | ㅤ |
ListView | 세로 | 세로 | ㅤ | ㅤ |
4. 서로에게 영향 안받도록 배치하기
- 로우는 가로 정렬
crossAxisAlignment: CrossAxisAlignment.start // 왼쪽에서 시작
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), Row( children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), ], ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }

5. 각각 독립된 영역으로 구분하기
- 서로 영향을 주고 받지 않도록 해야 디자인이 깨지지 않음
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), Row( children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), ], ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.yellow, width: 50, height: 50, ), ], ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }

- 영역이 나뉘어져 있음
- 각 영역마다 3개의 컴포넌트로 나눠야 함
- 컴포넌트끼리 다 독립적이지 않아서 영향을 받는 것 → 완전히 독립시켜야 함
- 전체는 컬럼 : 위에서 아래로
내부에 컴포넌트 각각 3개로 구분

6. 디자인이 안 무너지게 설계하기
- 컴포넌트로 뺀 후 타입을 변경한 경우 부모의 타입으로 바꿔줘야 오류가 나지 않음
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), Row( children: [ Container( color: Colors.red, width: 50, ) ], ) ], ), ); } Widget _top() { // 부모 타입으로 변경하기 return Container( width: double.infinity, child: Column( children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }

- top 디자인하기
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), Row( children: [ Container( color: Colors.red, width: 50, ) ], ) ], ), ); } Widget _top() { // 부모 타입으로 변경하기 return Container( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }



- 하나만 길이가 다른 경우
@override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), Row( children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 100, ) ], ) ], ), ); } Widget _top() { // 부모 타입으로 변경하기 return Container( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ), ); }


@override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), Container( height: 100, // 자식의 크기에 맞추려면 자식 각각에 높이를 주면 됨 child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: double.infinity, ), Container( color: Colors.green, width: 50, height: double.infinity, ), Container( color: Colors.yellow, width: 50, height: double.infinity, ) ], ), ) ], ), );
- 자식의 높이는 infinity로 맞추고 부모의 길이 조절하기



@override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), _center(), Container( width: 50, height: 50, child: Container( color: Colors.red, ), ) ], ), );

@override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), _center(), Center( child: Container( width: 50, height: 50, child: Container( color: Colors.red, ), ), ), ], ) ); }

@override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), _center(), Container( width: double.infinity, height: 50, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.red, width: 50, height: 50, ), ], ), ), ], ) ); }

무너지지 않는 디자인 만들기
- 앱은 가로 사이즈가 제일 중요함
- 세로 크기는 안에 있는 자식의 크기에 맞춘 것이기에 신경쓸 필요 없음
Widget _top() { // 부모 타입으로 변경하기 return SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ), ); }
- top은 colum → 가로 : 인라인 → 늘려주기
높이 : 자식의 크기에 맞추기
- 박스로 감싸는 이유는 가로 설계 때문 → 로우는 그대로 두기


@override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( crossAxisAlignment: CrossAxisAlignment.center, // 전체 디자인 // 총 3개의 섹션 children: [ _top(), // 새로로 내려감 _center(), Align( alignment: Alignment.centerRight, child: Container( color: Colors.red, width: 50, height: 50, ), ), ], ) ); }

import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( // 전체 디자인 // 총 3개의 섹션 children: [ _top(), _center(), _bottom(), ], ) ); } Widget _bottom() { return Align( alignment: Alignment.center, child: Container( color: Colors.red, width: 50, height: 50, ), ); } Widget _center() { return Row( // 부모로 감싸는 이유는 가로 설계 때문 crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ); } Widget _top() { // 부모 타입으로 변경하기 return SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ) ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }


[ 노란색을 가운데 두고 싶다 ]

다시 Row로 감싼다 (컨테이너에 alt + enter)


근데 이렇게 하면 안 됨
why?

배치할 때, 독립적이지 않으니까 모두 영향을 받는다. 독립적으로 디자인해야 함! 지금 컬럼 안에 다 때려넣었잖아. 전체도 컬럼, 안에 세부(?)도 컬럼. 이 3개가 컬럼 안에 묶여야지 컴포넌트화 시킬 수 있음
[ 전체 코드 ] - 다음에 연습
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:recipe_app/components/recipe_body.dart'; import 'package:recipe_app/components/recipe_menu.dart'; import 'package:recipe_app/components/recipe_menu_item.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), Row( children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.blue, width: 50, height: 50, ), ], ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.yellow, width: 50, height: 50, ), ], ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }
이건 컴포넌트화 불가능. 독립되어 있지 않음.
따로 박스 설계를 하지 않으면 디자인이 무너질 것
[ 제대로 설계 Column ]

섹션이 총 3개!

이런 식으로 디자인이 나와야 함

다 만들었으니 애를 컴포넌트로 빼자 (컴포넌트로 빼는게 맞는데 지금은 수업한다고 Method로 뺌)


컨테이너로 감싸고, 리턴 타입을 Widget (부모)로 바꿔준다.


독립됨
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:recipe_app/components/recipe_body.dart'; import 'package:recipe_app/components/recipe_menu.dart'; import 'package:recipe_app/components/recipe_menu_item.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( children: [ _top(), Row(), ], ), ); } Widget _top() { return Container( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }
Row

import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( children: [ _top(), Container( height: 200, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: double.infinity, ), Container( color: Colors.green, width: 50, height: double.infinity, ), Container( color: Colors.yellow, width: 50, height: double.infinity, ), ], ), ), ], ), ); } Widget _top() { return Container( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }
어휴 ssi bv
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( children: [ _top(), _center(), Container( width: double.infinity, height: 50, child: Container( color: Colors.red, width: 50, height: double.infinity, ), ), ], ), ); } Container _center() { return Container( height: 200, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: double.infinity, ), Container( color: Colors.green, width: 50, height: double.infinity, ), Container( color: Colors.yellow, width: 50, height: double.infinity, ), ], ), ); } Widget _top() { return Container( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }


height는 박스로 감싸서 크기 줄 필요 없음
Column은 늘리고, Row는 그대로 둔다.
Column은 왜 늘릴까? 처음에 Row가 들어갈 수 있는 경우도 있겠지

center를 두든, 뭘 두든…
[ Align ]



끝까지 차지하기 위해선 컬럼은 SizedBox 사용
return 타입은 전부 위젯
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Column( children: [ _top(), _center(), _bottom(), ], ), ); } Align _bottom() { return Align( alignment: Alignment.centerRight, child: Container( color: Colors.red, width: 50, height: 50, ), ); } Widget _center() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 50, ), ], ); } Widget _top() { return SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( color: Colors.red, width: 50, height: 50, ), Container( color: Colors.green, width: 50, height: 50, ), Container( color: Colors.yellow, width: 50, height: 80, ), ], ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }

배치는 Block을 만든다.
세로를 Block으로
- 컨테이너는 제약조건을 줄 수 있음
부모가 자식에게 제약 조건을 검 → 부모의 제약 조건을 알아야하기에 동적임
- 제약 조건을 모든 위젯이 들고 있는 것은 아님
sizesBox는 없음
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:recipe_app/components/recipe_body.dart'; import 'package:recipe_app/components/recipe_menu.dart'; import 'package:recipe_app/components/recipe_menu_item.dart'; import '../components/recipe_title.dart'; class RecipePage extends StatelessWidget { const RecipePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: _appbar(), body: Container( constraints: BoxConstraints( minWidth: 100, minHeight: 100, maxWidth: 150, maxHeight: 300, ), child: Container( alignment: Alignment.center, color: Colors.red, width: 1000, height: 1000, ), ), ); } AppBar _appbar() { return AppBar( actions: [ Icon(CupertinoIcons.search), SizedBox(width: 15), Icon( CupertinoIcons.heart, color: Colors.redAccent, ), SizedBox(width: 15), ], ); } }
Share article