Flutter에서 자주 사용하는 위젯들 (Container, Row, Colums, SafeArea, Etc)

Posted by , July 09, 2023
Flutter
Series ofFlutter

thumbnail

최근 플러터를 개발하면서...

나는 따로 강의를 수강한 적은 없고, 노마드코더쪽 무료 강의만 들었다.
먼저 따라하면서 어떤지 맛보기에는 좋았다.

하지만 실제 프로덕트(라고 하지만 개인 서비스)를 올리려 했는데 막히는 부분이 좀 있었다.
위젯을 다른 위젯으로 래핑한다거나, 공간이 벗어났을 때 처리 등등...

더 나아가선 상태관리까지...
그래서 도서관에서 책을 빌려 공부하면서 자주 쓰는 위젯에 대해 정리를 해볼까 한다.
여기 포스팅에 소개한 위젯 말고도 더 많겠지만, 나름 자주 쓰는 것에 대해 정리를 해본다.

Container

이름과 같이 뭔가를 적재하는 위젯이다.
그래서 나 같은 경우 Scaffold위젯에서 child속성에 이 컨테이너 위젯을 넣는다.

Scaffold가 뼈대 역할을 하는데 그 시작점을 Container로 잡고 한다.
가로(Width)와 세로(Height)의 길이를 정할 수 있고, 컨테이너 위젯의 배경색 등을 넣을 수 있다.

예를들어 가로는 화면에 꽉 채우고 세로는 300에 배경은 초록색으로 하는 박스 형태 컨테이너가 필요하면 아래와 같이 작성할 수 있다.

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
            top: true,
            child: Container(
              width: double.infinity,
              height: 300,
              decoration: const BoxDecoration(color: Colors.green),
            )));
  }
}

그럼 아래와 같은 형태로 결과가 나올 것이다.

img01

여기서 보면 컨테이너 위에 SafeArea라는 위젯이 래핑되어 있는데, 이는 뒤에서 소개하겠다.

그리고 컨테이너는 하나의 자식(child)를 가지는데 보통 단독으로 사용하는 위젯,
또는 Row, Colums와 같이 여러 자식을 소우하는 위젯을 둘 수 있다.

아래는 샘플이다.


  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        top: true,
        child: Container(
          width: double.infinity,
          height: 300,
          decoration: const BoxDecoration(color: Colors.green),
          child: const Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              Text(
                "View01",
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                    fontWeight: FontWeight.w800),
              ),
              Text(
                "View02",
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                    fontWeight: FontWeight.w800),
              ),
              Text(
                "View03",
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                    fontWeight: FontWeight.w800),
              ),
            ],
          ),
        ),
      ),
    );
  }

img02

코드 샘플이 빈약하지만 이 정도면 컨테이너 위젯의 기본에 대해서는 알 수 있을 것이다.

Row

Row위젯은 위에서 본 바와 같이 가로로 위젯을 배치하는데 사용한다.
그리고 다수의 위젯을 배열 형태로 받는다.
위의 샘플 예제에서 보면 mainAxisAlignment라는 속성이 있다.

이건 주축 정렬에 대한 속성을 제공한다.
이것과 반대로 되는 것은 crossAxisAlignment라는 속성이 있다.

말로 하니까 좀 복잡한데 다음과 같이 쉽게 정의할 수 있다.

img03


MainAxisAlignment

주측 정렬(MainAxisAlignment)에 대한 속성은 다음과 같다.

  • start
    • 시작에 정렬한다
  • center
    • 중앙에 정렬한다.
  • end
    • 끝에 정렬
  • SpaceBetween
    • 각 자식 위젯간의 간격을 균등하게 정렬한다.
  • spaceAround
    • 각 자식 위젯간의 간격을 균등하게 정렬하고, 맨처음과 맨끝 간격을 자식 위젯 사이의 반만큼 배정해 정렬한다.
  • spaceEvenly
    • 각 자식 위젯간의 간격을 균등하게 정렬하고, 맨처음과 맨끝 간격도 균등하게 정렬한다.

start center end
img04 img05 img06

SpaceBetween spaceAround spaceEvenly
img07 img08 img09

CrossAxisAlignment

이번엔 반대측 정렬(CrossAxisAlignment)에 대한 속성은 다음과 같다.

  • start
    • 시작에 정렬
  • center
    • 중앙에 정렬
  • end
    • 끝에 정렬
  • stretch
    • 반대축 최대한으로 늘려서 정렬

start center
img10 img11

end stretch
img12 img13

Colum

컬럼은 Row랑 반대 성향의 위젯이다.
Colum은 세로로 위젯을 배치하는데 사용한다.
그리고 다수의 위젯을 배열 형태로 받는다.

샘플 코드는 아래와 같다.


  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        top: true,
        child: Container(
          width: double.infinity,
          height: 300,
          decoration: const BoxDecoration(color: Colors.green),
          child: Column(
            children: [
              Container(
                width: 100,
                height: 100,
                decoration: const BoxDecoration(color: Colors.blue),
                child: const Center(
                  child: Text(
                    "View01",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 20,
                        fontWeight: FontWeight.w800),
                  ),
                ),
              ),
              Container(
                width: 100,
                height: 100,
                decoration: const BoxDecoration(color: Colors.indigo),
                child: const Center(
                  child: Text(
                    "View02",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 20,
                        fontWeight: FontWeight.w800),
                  ),
                ),
              ),
              Container(
                width: 100,
                height: 100,
                decoration: const BoxDecoration(color: Colors.blueGrey),
                child: const Center(
                  child: Text(
                    "View03",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 20,
                        fontWeight: FontWeight.w800),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

중요한 것은 여기도 주축정렬과 반대정렬이 있는데, Row와 반대 성향을 가진다.


img14


주측 정렬(MainAxisAlignment)에 대한 속성은 다음과 같다.

  • start
    • 시작에 정렬한다
  • center
    • 중앙에 정렬한다.
  • end
    • 끝에 정렬
  • SpaceBetween
    • 각 자식 위젯간의 간격을 균등하게 정렬한다.
  • spaceAround
    • 각 자식 위젯간의 간격을 균등하게 정렬하고, 맨처음과 맨끝 간격을 자식 위젯 사이의 반만큼 배정해 정렬한다.
  • spaceEvenly
    • 각 자식 위젯간의 간격을 균등하게 정렬하고, 맨처음과 맨끝 간격도 균등하게 정렬한다.

start center end
img15 img16 img17

SpaceBetween spaceAround spaceEvenly
img18 img19 img20

CrossAxisAlignment

이번엔 반대측 정렬(CrossAxisAlignment)에 대한 속성은 다음과 같다.

  • start
    • 시작에 정렬
  • center
    • 중앙에 정렬
  • end
    • 끝에 정렬
  • stretch
    • 반대축 최대한으로 늘려서 정렬

start center
img21 img22

end stretch
img23 img24

SafeArea

이름에서처럼 안전한 영역을 제공해주는 위젯이다.
이게 뭔말이냐 하면...

아이폰의 경우 하드웨어 특성상 노치가 있다.
그래서 아래와 같은 코드가 있다고 해보자.


  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: double.infinity,
        height: 300,
        decoration: const BoxDecoration(color: Colors.green),
      ),
    );
  }

이 코드의 결과는 아래와 같이 출력된다.

img25

근데 저 SafeArea위젯을 사용하면 아래와 같이 노치를 벗어나서 랜더링 된다.

img26

코드는 다음과 같다.

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        top: true,
        child: Container(
          width: double.infinity,
          height: 300,
          decoration: const BoxDecoration(color: Colors.green),
        ),
      ),
    );
  }

속성에는 top, bottom, left, rigth가 있고 bool 값을 받는데, 기본으로 전부 true를 가진다.
물론 미적용하고 싶다면 각 속성에 false를 걸어주면 된다.

SizedBox

Flexible

Expanded