Layouts in Flutter

ashe·2020년 1월 12일
0

잿더미의 Flutter

목록 보기
7/8

Layouts in Flutter

원문과 함께하는 것을 권장합니다.

중점으로 알아야하는 것

  • 위젯은 UI를 빌드하는 데 사용되는 클래스이다.
  • 위젯은 레이아웃과 UI 요소 모두에 사용된다.
  • 간단한 위젯을 작성하고 조합하여 복잡한 위젯을 작성한다.

Flutter 의 레이아웃 매커니즘의 핵심은 위젯이다. Flutter에서 거의 모든 것이 위젯이며 레이아웃도 위젯이다. Flutter 앱에 표시되는 이미지, 아이콘 및 텍스트는 모두 위젯이다. 보이지 않는 Column, Row, Alignment 등도 위젯이다.

복잡한 위젯을 작성하기 위해 위젯을 조합하여 레이아웃을 작성한다. 원문 아래에 레이아웃을 구성하는 예를 보여준다.

두 번째 스크린 샷은 시각적 레이아웃을 표시하고있고 각 열에는 아이콘과 레이블이 포함된 세개의 열이 존재한다.

이 학습서의 대부분의 스크린샷은 debugPaintSizeEnabled 가 true로 설정되어 표시되므로 시각적 레이아웃 구성을 볼 수 있다.

위에서 보여준 UI 의 위젯트리를 아래 사진에서 보여준다.

앞 튜토리얼을 했으면 예상할 수 있는 구조이다. 하지만 Container 에 대해 궁금할 수 있다. (분홍색으로 표시된 노드) Container는 하위 위젯을 사용자 정의할 수 있는 위젯 클래스이다. padding, margin, border, background 를 추가 할 때 컨테이너를 사용하여 설정할 수 있다.

이 예에서는 각 텍스트 위젯은 Container 에 안에 배치되어 위 margin(예제 사진에서 파란색으로 칠해진 부분) 을 가진다. ??

이 예제의 나머지는 속성에 의해 제어된다. 색상 속성을 사용하여 아이콘의 색상을 설정하고, Text.style 속성을 사용하여 글꼴, 색, 굵기를 설정한다. Row, Column 에너는 자식이 수직 또는 수평으로 정렬되는 방식과 자식의 공간을 지정할 수 있는 속성이 있다.

Layout a widget

Flutter 에서 단일 위젯을 어떻게 표현할까? 이 섹션에서는 간단한 위젯을 작성하고 표시하는 방법을 보여준다. 간단한 Hello World 앱의 전체 코드도 보여준다. Flutter 에서는 텍스트, 아이콘 또는 이미지를 화면에 표시하는 데 몇 단계만 거치면 된다.

1. layout Widget 을 선택한다.

표시해야할 위젯의 속성(정렬, 제한)에 따라 다양한 레이아웃 중 하나를 선택한다. 이러한 특성을 위젯으로 전달하기 때문이다.

이 예는 내용을 가로 및 세로 가운데 맞추는 Center 를 사용한다.

2. 위젯을 생성한다.

Text('Hello World'),
Image.asset(
  'images/lake.jpg',
  fit: BoxFit.cover,
),
Icon(
  Icons.star,
  color: Colors.red[500],
),

3. 위젯에 layout 위젯을 추가한다.

모든 레이아웃은 다음 중 하나가 있다.

  • Child 속성: 하나의 자식을 받는 것 (Container, Center)
  • Children 속성: 위젯 목록을 받는 것 (Row, Column, ListView, Stack)
Cetner(
	child: Text('Hello World'),
),

4. 페이지에 layout 위젯 추가하기

Flutter 앱 자체는 위젯이고 대부분의 위젯에는 build 메서드가 존재한다. build 메서드에 위젯을 인스턴스화하고 반환하면 위젯이 보여지게 된다.

Material apps

Material 앱의 경우 Scaffold 위젯을 사용할 수 있다. 기본 배너, 배경 색을 제공하며 Drawers, Snack bars, Bottom Sheet 를 추가할 수 있는 API 를 제공한다. 그런 다음 home 의 body 속성에 Center 위젯을 직접 전달한다.

class MyApp extends StatelessWidget {
	
	Widget build(BuildContext context) {
		return MaterialApp(
			title: 'Flutter layout demo',
			home: Scaffold(
				appBar: AppBar(
					title: Text('Flutter layout demo'),
				),
				body: Center(
					child: Text('Hello World'),
				)
			)
		)
	}
}

Non-Material apps

Material 앱이 아닌 경우 build 메서드에 Center 위젯을 바로 배치한다.

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(color: Colors.white),
      child: Center(
        child: Text(
          'Hello World',
          textDirection: TextDirection.ltr,
          style: TextStyle(
            fontSize: 32,
            color: Colors.black87,
          ),
        ),
      ),
    );
  }
}

기본적으로 non-Material 앱에는 AppBar, 제목, 배경 색이 포함되지 않는다. Non-Material 앱에서는 이러한 기능을 사용하려면 직접 작성해야한다. 이 앱은 Material 앱을 모방하기 위해 배경을 흰 색으로, 텍스트를 진한 회색으로 바꾼다.

위젯들을 수평, 수직으로배치하는 레이아웃

가장 일반적 패턴 중하나는 위젯을 수직 또는 수평으로 배치하는 것이다. Row 위젯을 사용하여 수평으로 배치하고 Column 위젯을 사용하여 수직으로 배치한다.

중점으로 알아야하는것

  • Row 와 Column은 레이아웃 패턴 중 가장 일반적으로 사용된다.
  • Row 와 Column은 여러 위젯을 자식으로 갖는다.
  • 자식 위젯은 Row, Column 혹은 복잡한 위젯을 가질 수 있다.
  • Row 와 Column이 정렬 방법을 지정할 수 있다.
  • 하위 위젯의 크기를 늘리거나 조절할 수 있다.
  • 하위 위젯이 행 또는 열의 사용 가능한 공간을 사용하는 방법을 지정할 수 있다.

Flutter에서 행 또는 열을 만들려면 하위 위젯 목록을 추가해야한다. children 속성에 들어간 위젯은 행 또는 열에 배치된다. 다음 예제는 Row, Column을 중첩하여 사용하는 방법을 보여준다.

이 레이아웃은 Row로 구성되고, Row에는 두개의 하위 요소가 있다.

왼쪽 Column의 위젯 트리는 Row, Column의 중첩 트리를 가지고있다.

이 예제의 일부를 아래 Nesting rows and column에서 구현한다.

Row 와 Column은 수평 및 수직 배치를 위한 기본 위젯이며, 이러한 낮은 수준의 위젯은 최대로 커스터마이징하게 사용할 수 있다. Flutter는 필요에 따른 전문화되고 더 높은 수준의 위젯을 제공한다. 예를 들어, Row 대신 선행 아이콘과 후행 아이콘에 대한 속성이 포함되어 목록에 사용하기 쉬운 ListTile 을 구현해놨다. Row 대신 사용가능한 공간에 맞추기 위해 내용이 너무 길면 자동으로 스크롤되는 레이아웃인 ListView도 구현되어있다.

정렬 위젯

mainAxisAlignment 그리고 crossAxisAlignment 속성을 사용하여 Row 또는 Column이 하위 정렬되는 방법을 제어한다. Row의 경우 주 축은 가로, Column의 경우 주 축은 세로가 된다.

MainAxisAlignment 및 CrossAxisAlignment 클래스는 정렬을 제어하기 위한 다양한 상수를 제공한다.

이 예에서 이미지의 각 너비는 100 픽셀이다. 렌더 박스(이 경우 화면 전체)의 너비는 300 픽셀 이상이므로 주축 정렬을 spaceEvenly로 설정하면 빈 수평공간이 각 이미지 사이, 전 후에 균일하게 할당된다.

Row(
	mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Image.asset('image/pic1.jpg'),
    Image.asset('image/pic2.jpg'),
    Image.asset('image/pic3.jpg'),
  ]
)

Column은 Row 와 같은 방식으로 작동한다.

Column(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Image.asset('images/pic1.jpg'),
    Image.asset('images/pic2.jpg'),
    Image.asset('images/pic3.jpg'),
  ],
);

Sizing Widgets

레이아웃이 너무 커 장치에 맞지 않으면 영향을 받는 가장자리를 따라 노랜색과 검은 색 줄무늬가 나타난다.

Expanded 위젯을 사용하여 Row 또는 Column의 크기에 맞도록 위젯 크기를 조절할 수 있다.

Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Expanded(
      child: Image.asset('images/pic1.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic2.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic3.jpg'),
    ),
  ],
);

만약 이중 하나의 사진이 더 많은 크기를 차지하게 하고싶다면 flex 속성을 사용한다. Exapanded flex 속성의 기본값은 1이다. 이 값의 비율에 따라 크기를 다르게 가질 수 있다.

Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Expanded(
      child: Image.asset('images/pic1.jpg'),
    ),
    Expanded(
      flex: 2,
      child: Image.asset('images/pic2.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic3.jpg'),
    ),
  ],
);

Packing widgets

기본적으로 Column Row는 기본 축을 다라 가능한 많은 공간을 차지하지만 자식을 밀접하게 묶으려면 mainAxisSize를 MainAxisSize.min 으로 설정한다. 다음 예는 이 속성을 사용하여 별표 아이콘을 밀접하게 묶는다.

Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.black),
    Icon(Icons.star, color: Colors.black),
  ],
)

Nesting rows and column

레이아웃 프레임워크를 사용하면 원하는만큼 Row와 Column을 중첩할 수 있다. 레이아웃 개요 섹션에 대한 코드의 일부를 작성한다.

위에서 붉은색 부분의 위젯트리는 다음과 같다.

ratings 변수는 5개의 작은 별표 아이콘과 텍스트가 포함된 행을 만든다.

var stars = Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.black),
    Icon(Icons.star, color: Colors.black),
  ],
);

final ratings = Container(
  padding: EdgeInsets.all(20),
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      stars,
      Text(
        '170 Reviews',
        style: TextStyle(
          color: Colors.black,
          fontWeight: FontWeight.w800,
          fontFamily: 'Roboto',
          letterSpacing: 0.5,
          fontSize: 20,
        ),
      ),
    ],
  ),
);

많이 중첩된 레이아웃 코드로 인해 발생할 수 있는 시각적 혼란을 최소화하려면 변수 및 함수에서 구현 후 조합한다.

위젯트리에서 rating 아래에는 각 열에는 아이콘과 두 줄의 텍스트가있다.

final descTextStyle = TextStyle(
  color: Colors.black,
  fontWeight: FontWeight.w800,
  fontFamily: 'Roboto',
  letterSpacing: 0.5,
  fontSize: 18,
  height: 2,
);

// ??
final iconList = DefaultTextStyle.merge(
  style: descTextStyle,
  child: Container(
    padding: EdgeInsets.all(20),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        Column(
          children: [
            Icon(Icons.kitchen, color: Colors.green[500]),
            Text('PREP:'),
            Text('25 min'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.timer, color: Colors.green[500]),
            Text('COOK:'),
            Text('1 hr'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.restaurant, color: Colors.green[500]),
            Text('FEEDS:'),
            Text('4-6'),
          ],
        ),
      ],
    ),
  ),
);

각 UI 트리를 정의한 것을 leftColumn 에서 합친다.

final leftColumn = Container(
  padding: EdgeInsets.fromLTRB(20, 30, 20, 20),
  child: Column(
    children: [
      titleText,
      subTitle,
      ratings,
      iconList,
    ],
  ),
)

왼쪽 Column은 너비를 제한하기 위해 컨테이너에 배치한다. 마지막으로 UI 는 카드로 구성한다.

body: Center(
  child: Container(
    margin: EdgeInsets.fromLTRB(0, 40, 0, 30),
    height: 600,
    child: Card(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: 440,
            child: leftColumn,
          ),
          mainImage,
        ],
      ),
    ),
  ),
),

Common layout widgets

Flutter의 위젯 라이브러리에는 다양하게 존재한다. 가장 일반적으로 사용되는게 몇 있는데, 이를 사용하여 가장 빠르게 시작할 수 있다. 사용가능한 다른 위젯 정보는 다른 것을 참조한다.

위젯은 표준 위젯과 Material 위젯의 두가지 범주로 분류된다. 모든 앱은 위젯 라이브러리를 사용할 수 있지만 Material 컴포넌트는 Material 앱에서만 사용할 수 있다.

표준 위젯

  • Container: padding, margin, border, background 등의 속성을 위젯에 추가한다.
  • GridView: 위젯을 스크롤 가능한 그리드로 배치한다.
  • ListView: 위젯을 스크롤 가능한 목록으로 배치한다.
  • Stack: 위젯을 다른 위젯 위에 겹칞다.

Material 위젯

  • Card: 모서리와 그림자가 있는 상자로 UI 를 구성한다.
  • ListTile: 최대 3줄의 텍스트와 선, 후행의 아이콘 행의 UI 를 구성한다.

위 위젯들이 어떻게표시되는지는 원문을 보자. 어떤 UI가 존재하는지 알면 된다.

profile
Qué será, será

0개의 댓글