본문 바로가기
플러터/플러터 개념

[Day5] UI Layouts in Flutte 2 - Flutter for SwiftUI Developers 번역

by 인생여희 2023. 11. 9.

[Day5] UI Layouts in Flutte 2 - Flutter for SwiftUI Developers 번역

 

Lay out multiple widgets vertically and horizontally

가장 일반적인 레이아웃 패턴 중 하나는 위젯을 세로 또는 가로로 배열하는 것입니다. Row 위젯을 사용하여 위젯을 가로로 정렬하고 Column 위젯을 사용하여 위젯을 세로로 정렬할 수 있습니다.

[요점]
- Row과 Column은 가장 일반적으로 사용되는 두 가지 레이아웃 패턴입니다.
- Row과 Column은 각각 자식 위젯의 리스트(List)를 받습니다.
- 자식 위젯(List)은 그 자체로 Row, Column 또는 기타 복잡한 위젯이 될 수 있습니다.
- Row과 Column이 자식 위젯을 세로 및 가로로 정렬하는 방법을 지정할 수 있습니다.
- 특정 자식 위젯을 늘리거나 제한할 수 있습니다.
- 자식 위젯이 Row 또는 Column의 사용 가능한 공간을 사용하는 방법을 지정할 수 있습니다.


Flutter에서 Row 또는 Column을 만들려면 Row 또는 Column 위젯에 자식 위젯 List를 추가합니다.
차례로 각 자식 위젯은 그 자체로 Row나 Column이 될 수 있습니다.
다음 예제는 Row 또는 Column 안에 또다른 Row 또는 Column을 중첩하는 방법을 보여줍니다.


이 레이아웃은 Row으로 구성됩니다. Row에는 왼쪽에 Column이 있고 오른쪽에 이미지가 있는 두 개의 자식이 있습니다:




왼쪽 Row의 위젯 트리에는 Row와 Column이 중첩되어 있습니다.



Row와 Column 중첩에 파블로바의 레이아웃 코드 일부를 구현합니다.


참고: Row와 Column은 가로 및 세로 레이아웃을 위한 아주 기초적인 기본 위젯으로, 이러한 낮은 수준(low level)의 위젯을 사용하면 최대한의 커스터마이징이 가능합니다.

Flutter는 필요에 따라 더 높은 수준의 위젯도 제공합니다.

예를 들어, Row 대신에 선행 및 후행 아이콘과 최대 3줄의 텍스트에 대한 속성이 있는 사용하기 쉬운 위젯인 ListTile을 사용할 수 있습니다.

Column 대신 콘텐츠가 너무 길어 사용 가능한 공간에 맞지 않을 경우 자동으로 스크롤되는 Column과 같은 레이아웃인  ListView를 선호할 수 있습니다.

자세한 내용은 일반적인 레이아웃 위젯을 참조하세요.


 

Aligning widgets(위젯 정렬)

mainAxisAlignment 및 crossAxisAlignment 속성을 사용하여 Row 또는 Column의 자식 정렬 방식을 제어할 수 있습니다.
Row의 경우 주축(mainAxisAlignment)은 가로로, 교차 축(crossAxisAlignment)은 세로로 정렬됩니다.
Column의 경우 주축(mainAxisAlignment)은 세로로, 교차 축(crossAxisAlignment)은 가로로 정렬됩니다.


MainAxisAlignmentCrossAxisAlignment 열거형은 정렬을 제어하기 위한 다양한 상수를 제공합니다.


다음 예시에서는 3개의 이미지 각각 너비가 100픽셀입니다.


렌더링 상자(이 경우 전체 화면)의 너비가 300픽셀을 초과하므로 main axis alignment(주축 정렬)을 spaceEvenly(공간균등)으로 설정하면 각 이미지의 앞과 뒤, 사이의 가로 크기가 균등하게 나뉩니다.

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



Column은 Row과 동일한 방식으로 작동합니다.

 


다음 예는 각각 100픽셀 높이의 이미지 3개로 구성된 Column을 보여줍니다. 렌더링 상자의 높이(이 경우 전체 화면)가 300픽셀을 초과하므로 main axis alignment(주축 정렬)을 spaceEvenly(공간균등)으로 설정하면 각 이미지의 위, 가운데, 아래에  여유가 있는 공간이 균등하게 부여됩니다.

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



Sizing widgets(위젯 크기 조정)

레이아웃이 너무 커서 장치에 맞지 않으면 영향을 받는 가장자리를 따라 노란색과 검은색 줄무늬 패턴이 나타납니다. 다음은 너무 넓은 Row의 예입니다:

 


Expanded 위젯을 사용하여 Row 또는 Column에 맞게 위젯의 크기를 조정할 수 있습니다. 이미지 Row가 렌더링 상자에 비해 너무 넓었던 이전 예제를 수정하려면 각 이미지를 Expanded 위젯으로 감싸면 됩니다.

 

 

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 계수를 결정하는 정수인 Expanded 위젯 flex 속성을 사용하면 됩니다. 기본 flex 계수는 1입니다.
다음 코드는 가운데 이미지의 flex 계수를 2로 설정합니다:

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


기본적으로 row 또는 column은 주축(main axis)을 따라 가능한 한 많은 공간을 차지하지만, 자식들을 서로 가깝게 패킹하려면 mainAxisSizeMainAxisSize.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]),
    const Icon(Icons.star, color: Colors.black),
    const Icon(Icons.star, color: Colors.black),
  ],
)



Nesting rows and columns

layout framework를 사용하면 row과 column을 또 다른 row과 column 안에 원하는 만큼 깊게 중첩할 수 있습니다. 다음 레이아웃의 개요 섹션에 대한 코드를 살펴봅시다:


위의 그림에서 빨간색 윤곽선 부분은 두 개의 Row로 구현됩니다. 평점 Row에는 별 5개와 리뷰 수가 포함됩니다. 아이콘 Row에는 아이콘과 텍스트의 세 Column이 포함됩니다.

평점 Row의 위젯 tree입니다:



ratings 변수는 별 5개 아이콘의 작은 Row와 텍스트를 포함하는 Row을 생성합니다:

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]),
    const Icon(Icons.star, color: Colors.black),
    const Icon(Icons.star, color: Colors.black),
  ],
);

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


Tip :  중첩된 레이아웃 코드로 인해 발생할 수 있는 시각적 혼란을 최소화하려면 UI의 일부를 변수와 함수로 구현하세요.

평점 행 아래의 아이콘 Row에는 3개의 Column이 있으며, 위젯 tree에서 볼 수 있듯이 각 Column에는 아이콘과 두 줄의 Text가 포함되어 있습니다:




iconList 변수는 아이콘 Row를 정의합니다:

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

// DefaultTextStyle.merge()를 사용하면 자식에게 상속되는 기본 텍스트
// 스타일을 생성할 수 있으며, 이 스타일은 자식 및 모든 후속 자식에 상속됩니다.
final iconList = DefaultTextStyle.merge(
  style: descTextStyle,
  child: Container(
    padding: const EdgeInsets.all(20),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        Column(
          children: [
            Icon(Icons.kitchen, color: Colors.green[500]),
            const Text('PREP:'),
            const Text('25 min'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.timer, color: Colors.green[500]),
            const Text('COOK:'),
            const Text('1 hr'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.restaurant, color: Colors.green[500]),
            const Text('FEEDS:'),
            const Text('4-6'),
          ],
        ),
      ],
    ),
  ),
);



leftColumn 변수에는 평점과 아이콘 행은 물론 파블로바를 설명하는 제목과 텍스트가 포함되어 있습니다:

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



왼쪽 열(left column)은 너비(width)를 제한하기 위해 SizedBox에 배치됩니다. 마지막으로, UI는 Card 안에 전체 행(왼쪽 열과 이미지 포함)으로 구성됩니다.

파블로바 이미지는 Pixabay에서 가져온 것입니다.

Image.network()를 사용하여 인터넷에서 이미지를 다운로드할 수 있지만, 이 예제에서는 프로젝트의 이미지 디렉터리에 이미지를 저장하고 pubspec 파일에 추가한 다음 Images.asset()을 사용하여 액세스합니다.

자세한 내용은 에셋 및 이미지 추가하기를 참조하세요.
에셋 및 이미지 추가하기 : https://docs.flutter.dev/ui/assets/assets-and-images

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



: 파블로바 예제는 태블릿과 같은 넓은 기기에서 가로로 실행하는 것이 가장 좋습니다.
iOS 시뮬레이터에서 이 예제를 실행하는 경우 하드웨어 > 장치 메뉴를 사용하여 다른 장치를 선택할 수 있습니다.
이 예제에서는 iPad Pro를 권장합니다. 하드웨어 > 회전을 사용하여 방향을 가로 모드로 변경할 수 있습니다. 창 > 크기 조정을 사용하여 시뮬레이터 창의 크기를 변경할 수도 있습니다(논리적 픽셀 수는 변경하지 않음).

 
출처

https://docs.flutter.dev/ui/layout#lay-out-multiple-widgets-vertically-and-horizontally