본 문서는 Fluter Example의 내용을 원저작자의 동의하에 번역한것 입니다.
원 저작자 Eric Windmill에게 감사를 전합니다.
이해하는데 불필요한 문장은 과감하게 버렸습니다. 오 번역에 대해서 의견 주시면 적극 반영 하겠습니다.

Flutter Widgets

어떤걸 다루나?

What’s a Widget

플러터에선 모든게 위젯이다.

만약 여러분이 이전에 React나 Vue로 작업을 해봤다면 이것은 매우 쉬울 것이다. 플러터에서 모든것들이 Widget 이다. 재사용 가능한 작은 컴포넌트로 작업하는 것은 JS프레임워크와 매우 유사하다. 그리고 위젯은 플러터 클래스를 확장하는 다트 클래스에 지나지 않는다.

모든 플러터 위젯은 다음과 같다:

1
2
3
class ImageWidget extends StatelessWidget {
// class stuff
}

위젯 클래스들은 오직 하나의 요구사항만 있다: 그것은 반드시 다른 위젯을 리턴하는 build 메소드를 가지고 있어야 한다는 것이다. 이 규칙의 유일한 예외는 기본타입(primitive types) (대개 Strings 또는 numbers)을 반환하는 Text와 같은 낮은 수준의 위젯이다.

1
2
3
4
5
class BigText extends StatelessWidget {
Widget build(context) {
return new Text('text');
}
}

그외 위젯은 일반적인 다트 클래스 일뿐이다. 여러분은 위젯에 메소드와 속성 등을 추가 할 수있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BigText extends StatelessWidget {
// a property on this class
final String text;

// a constructor for this class
BigText(this.text);

Widget build(context) {
// Pass the text down to another widget
return new Text(
text,
// Even changing font-style is done through a Dart class.
textStyle: new TextStyle(fontSize: 20.0),
);
}
}

그런 다음 앱의 다른 곳에서 위젯을 다음과 같이 사용하면 된다:

1
2
3
4
// ...
// This is how we'd use the BigText within another widget.
child: new BigText('This string would render and be big'),
// ...

Stateless and StatefulWidgets

플러터 위젯은 플러터 라이브러리에서 몇 가지 클래스를 확장 해야 한다. 여러분이 사용할 둘은 거의 항상 StatelessWidgetStatefulWidget이다.

둘간 차이점은 위젯 내에 상태(state)개념이 있고 그 중 일부가 변경되면 플러터에 다시 렌더링(re-rendering)을 지시하는 메소드가 내장 되어 있다는 것이다. 이것은 플러터의 핵심 개념이다.
Stateful 위젯은 조금 달라 보인다. 사실 두 가지 클래스인 state객체와 위젯 이다. (역자주: Stateless위젯은 StatelessWidget 클래스만 상속 받으면 되지만 Stateful위젯은 StatefulWidget를 상속한 위젯 클래스와 위젯 생성시 내부적으로 사용되는 state객체를 생성하기 위한 State클래스를 상속받은 클래스 이렇게 두개가 필요함을 말한다.)

다음과 같이 작성하면 된다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Counter extends StatefulWidget {
Counter({Key key, this.title}) : super(key: key);

// Stateful Widgets don't have build methods.
// They have createState() methods.
// Create State returns a class that extends Flutters State class.
@override
_MyHomePageState createState() => new _MyHomePageState();

// Stateful Widgets are rarely more complicated than this.
}

class _MyHomePageState extends State<MyHomePage> {
int counter = 0;

void increaseCount() {
// setState is a special method that tells Flutter to repaint
// the view because state has been updated!
setState(() {
this.counter++;
}
}

// gotta have that build method!
Widget build(context) {
return new RaisedButton(
onPressed: increaseCount,
child: new Text('Tap to Increase'),
);
}
}

Material and Cupertino Widgets

플러터 SDK가 특별히 좋은점은 AndroidiOS 스타일의 위젯을 내장하고 있다는 것이다.
감정을 분출해서 미안하지만(역자주: 글쓴이가 플러터에서 기본 제공하는 머터리얼과 쿠퍼티노 위젯 제공에 대해 너무 좋아함을 말하는듯함) 플러터가 상자에서 꺼내준것은 꽤 놀랍다. 여러분이 별도의 디자인 능력 없이도 꽤 보기 좋고 접근하기 쉬운 모바일 앱을 만들 수 있다.

만약 여러분이 새로운 React, Vue, React Native 등의 프로젝트를 시작했다고 상상해 보자. 그러면 디자인 표준을 염두에 둔 수백가지(수많은)의 구성 요소들이 필요할 것이다.
이것이 Material과 Cupertino 위젯의 역할이다. Android앱처럼 보여주게 디자인된 Material과 iOS처럼 보여주게 디자인된 Cupertino.(역자주: 새로운 프로젝트를 위해서 수 많은 UI컴포넌트들이 필요한데 이런 작업들을 편리하도록 플러터는 Android와 iOS UI스타일에 맞게 디자인된 Material과 Cupertino 위젯음 기본 제공하므로 굉장히 편리하다.)

위젯에 내장된 이러한 기능과 완전한 사용자 정의 위젯을 만드는 능력은 당신에게 많은 힘(도움)을 준다. low-level custom 위젯으로 완전한 custom앱을 만들거나 MVP(역자주 : Minimum Value Product - 최소 기능 제품)에 도달하기 위해 주어진 기능을 사용하여 만들 수도 있다.

Most Common Widgets

다음은 즉시 사용할 준비가 된 위젯이다. 다음과 같은 위젯에 매우 익숙해 져야 한다.

  • Text : 단순히 화면에 텍스트를 표시하는 위젯.
  • Image : 이미지를 표시.
  • Icon : 플러터의 내장된 Material과 Cupertino 아이콘을 표시.
  • Container : 플러터 UI에서 div 같은거라 보면 됌. 패딩, 정렬, 위젯의 크기 조절, 다른 것들의 boatloads(역자주: 앞서 설명한 요소들을 담을 수 있는것) 를 추가 할 수 있는 편리한 위젯. 비어 있을땐 0px 공간을 차지함.
  • TextInput : 사용자 의견을 처리.(역자주: 사용자 입력 폼)
  • Row, Column : 수평 또는 수직 방향으로 child(자식) 목록을 표시. 레이아웃을 위한 flex-box 규칙을 따른다.
  • Stack : 스택은 하나 이상의 다른 자식을 목록에 표시한다. 이 기능은 CSS의 position 속성과 매우 유사하다.
  • Scaffold : 앱의 기본 레이아웃 구조를 제공하는 앱내 모든 페이지의 root이다. bottom navigations(하단 메뉴), appBar(상단 타이틀 bar), back buttons (이전 버튼) 등을 쉽게 구현 할 수 있다.

플러터의 위젯 문서는 굉장히 훌륭하다. 목록을 확인해 봐라.

1
주의: 여러분이 React같은 컴포넌트 기반 프레임워크에 익숙하다면 내용을 읽지 않아도 된다. 위젯은 단지 컴포넌트 일 뿐이다.

Thinking in Widgets

플러터에서 모든것이 위젯이다(역자주: 몇번에 걸쳐 말하는거 보니 엄청 중요하겠죠? ㅋ)
위젯은 완벽한 앱을 만들기 위해 결합 할수 있는 아주 작은 UI덩어리 입니다. 플러터로 앱을 만드는 것은 레고 블록을 하나씩 조립해서 만드는것과 같다.
위젯은 앱을 만들기 위해 내부에 서로 중첩된다. 여러분의 앱의 root 또한 위젯이며 모든 위제들은 하위로 쭉 내려간다.

플러터는 UI의 모든 측면(aspect)이 위젯으로 처리된다는 점에서 독특합니다.

위젯은 무언가를 표시하거나, 디자인을 정의하거나, 레이아웃 처리를 하거나, 상호 작용을 처리 할 수 있다. 다시 한번 강조하지만 플러터의 모든것은 Widget 이다.

  • 텍스트를 표시하는 간단한 위젯 : const Text('Hello World')
  • 사용자 상호작용을 처리하는 간단한 위젯 : const Button(onTaps: ...callback...)
  • 배경색상을 추가 하는 간단한 위젯 : const BoxDecoration(background: Colors.blue)

기본적으로 여러분의 CSS, HTML 및 자바스크립트가 모두 위젯에서 처리된다고 상상해 보자. 마크업이 없고, CSS도 없다. 오직 위젯이다.

Widget Hierarchy

아래 그림에서 윤곽선으로 보이는 모든 것이 위젯이다.
outlined widget

이 그림은 FlutterByExample의 튜토리얼 앱 중 하나에서 가져온 것으로, 강아지(dog) 정보에 대한 세부 페이지 정보 이다.

녹색 윤곽선은 page를 나타낸다. 그리고 페이지는 플러터의 위젯이다. 파란색 윤곽선은 논리적으로 그룹화된 UI 조각을 나타낸다. 나머지는 흰색으로 윤곽이 그려져 있고, 이는 단순히 내용과는 상관없는 아둔한 컴포넌트(dump component)일 뿐이고, 이것들은 단지 그들이 전달받는 것을 보여줄 뿐이다.

다음은 이 페이지의 위젯 계층도 이다.

  • PageWidget
    • DogProfileWidget
    • CircleImage
    • Text
    • Text
    • Text
    • Container
      • Icon
      • Text
  • RateDogWidget
  • Slider
  • Text
  • SubmitButton

주의 위 계층은 아주 정확하진 않다. 여기엔 columnpadding과 같은 위젯도 있다.

Design for Re-usability

플러터 위젯을 효과적으로 사용하는 가장 중요한 부분은 재사용 할 수 있도록 가장 저수준의 위젯을(lowest level) 디자인 하는 것이다.

예를들어 위 위젯계층 구조에서 CircleImage 위젯은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CircleImage extends StatelessWidget {
final String renderUrl;

CircleImage(this.renderUrl);

@override
Widget build(BuildContext context) {
return new Container(
width: 100.0,
height: 100.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.cover,
image: new NetworkImage(renderUrl ?? ''),
),
),
);
}
}

그런 다음 앱의 어느 곳에서나 이 위젯을 다시 사용할 수 있다. 이렇게요 ( new CircleImage(https...) ) 이 컴포넌트는 재사용성을 고려 하여 설계 되었으므로 여러분은 특정 크기의 둥근이미지를 원하는 앱의 어느 곳에서든 url만 전달하면 사용할 수 있다. 그러므로, 굳이 이 위젯을 반복해서 다시 만들 필요는 없다.

추가적으로 이 원 이미지는(역자주: CircleImage 컴포넌트) 어떤 이미지를 나타내야 하는지 전혀 신경쓰지 않고 있다. 이것은 단지 컴포넌트의 스타일을 강제할 뿐이다.

다음 그림은 테스트앱에서 위 컴포넌트가 사용되어진 카드(card)중 하나이다.
dogs_of_cards

예제소스