컬럼 연습하기

송민경's avatar
Apr 09, 2024
컬럼 연습하기

1. 박스 1개 만들기

notion image
  • double.infinity는 무한대
notion image
 

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), ], ); } }
notion image
 
  • 컬럼 // 세로 : 블락, 가로 : 인라인
  • 로우 // 가로 : 블락, 세로 : 인라인
  • 자식이 큰게 들어오면 다 깨짐 → 컬럼 자체를 미리 키워놔야 함
notion image
  • 컨테이너는 끝까지 차지함
  • 자식이 없으면 블락
  • 자식이 있으면 인라인
notion image
notion image
  • ListView는 최소 값이 가로가 double.infinity라서 width가 안보임
크기를 조절하려면 부모를 만들어서 크기 조절하기
notion image
 

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), ], ); } }
notion image
 

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), ], ); } }
notion image
  • 영역이 나뉘어져 있음
  • 각 영역마다 3개의 컴포넌트로 나눠야 함
  • 컴포넌트끼리 다 독립적이지 않아서 영향을 받는 것 → 완전히 독립시켜야 함
  • 전체는 컬럼 : 위에서 아래로
내부에 컴포넌트 각각 3개로 구분
notion image
 

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), ], ); } }
notion image
  • 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), ], ); } }
notion image
notion image
notion image
  • 하나만 길이가 다른 경우
@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, ) ], ), ); }
notion image
notion image
@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로 맞추고 부모의 길이 조절하기
notion image
notion image
notion image
@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, ), ) ], ), );
notion image
@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, ), ), ), ], ) ); }
notion image
@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, ), ], ), ), ], ) ); }
notion image
 

무너지지 않는 디자인 만들기

  • 앱은 가로 사이즈가 제일 중요함
  • 세로 크기는 안에 있는 자식의 크기에 맞춘 것이기에 신경쓸 필요 없음
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 → 가로 : 인라인 → 늘려주기
높이 : 자식의 크기에 맞추기
  • 박스로 감싸는 이유는 가로 설계 때문 → 로우는 그대로 두기
notion image
notion image
@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, ), ), ], ) ); }
notion image
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), ], ); } }
notion image
notion image

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

notion image
다시 Row로 감싼다 (컨테이너에 alt + enter)
notion image
notion image
💡
근데 이렇게 하면 안 됨
 

why?

notion image
배치할 때, 독립적이지 않으니까 모두 영향을 받는다. 독립적으로 디자인해야 함! 지금 컬럼 안에 다 때려넣었잖아. 전체도 컬럼, 안에 세부(?)도 컬럼. 이 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 ]

notion image
섹션이 총 3개!
notion image
이런 식으로 디자인이 나와야 함
notion image
다 만들었으니 애를 컴포넌트로 빼자 (컴포넌트로 빼는게 맞는데 지금은 수업한다고 Method로 뺌)
notion image
 

 
notion image
컨테이너로 감싸고, 리턴 타입을 Widget (부모)로 바꿔준다.
notion image
notion image
독립됨
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

notion image
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), ], ); } }
notion image

 
notion image
height는 박스로 감싸서 크기 줄 필요 없음
 

 
💡
Column은 늘리고, Row는 그대로 둔다. Column은 왜 늘릴까? 처음에 Row가 들어갈 수 있는 경우도 있겠지
notion image
💡
center를 두든, 뭘 두든…

[ Align ]

notion image
notion image
notion image
💡
끝까지 차지하기 위해선 컬럼은 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), ], ); } }
notion image
 
💡
배치는 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

vosw1