위젯 시스템
개요
Flitter의 위젯(Widget)은 UI를 구성하는 기본 단위입니다. Flutter와 동일한 개념으로, 화면에 표시되는 모든 요소는 위젯으로 구성됩니다. 버튼, 텍스트, 레이아웃, 심지어 앱 자체도 위젯입니다.
왜 중요한가?
위젯 시스템을 이해하면:
- 재사용 가능한 컴포넌트: 한 번 만든 위젯을 어디서든 재사용
- 조합 가능한 구조: 작은 위젯들을 조합해 복잡한 UI 구성
- 명확한 상태 관리: StatelessWidget과 StatefulWidget으로 상태 관리 패턴 구분
- 예측 가능한 동작: 위젯 라이프사이클을 통한 체계적인 개발
핵심 개념
위젯의 종류
Flitter에는 세 가지 주요 위젯 타입이 있습니다:
- StatelessWidget: 상태가 없는 정적 위젯
- StatefulWidget: 상태를 가지는 동적 위젯
- RenderObjectWidget: 직접 렌더링을 담당하는 저수준 위젯
StatelessWidget
상태가 없고 한 번 생성되면 변하지 않는 위젯입니다:
import { StatelessWidget, Text, Container, EdgeInsets, Colors, type BuildContext, type Widget } from '@meursyphus/flitter';
class Greeting extends StatelessWidget {
constructor(private props: { name: string }) {
super();
}
build(context: BuildContext): Widget {
return Container({
padding: EdgeInsets.all(16),
color: Colors.blue.shade100,
child: Text(`안녕하세요, ${this.props.name}님!`)
});
}
}
// Factory function으로 export
export default function GreetingWidget(props: { name: string }): Widget {
return new Greeting(props);
}
StatefulWidget
상태를 가지고 있으며, 상태가 변경되면 UI가 자동으로 업데이트되는 위젯입니다:
import {
StatefulWidget,
State,
Container,
Column,
Text,
GestureDetector,
EdgeInsets,
Colors,
TextStyle,
type BuildContext,
type Widget
} from '@meursyphus/flitter';
class Counter extends StatefulWidget {
createState(): State<Counter> {
return new CounterState();
}
}
class CounterState extends State<Counter> {
count = 0;
build(context: BuildContext): Widget {
return Column({
children: [
Text(`카운트: ${this.count}`, {
style: TextStyle({ fontSize: 24 })
}),
GestureDetector({
onClick: () => {
this.setState(() => {
this.count++;
});
},
child: Container({
margin: EdgeInsets.only({ top: 16 }),
padding: EdgeInsets.symmetric({ horizontal: 24, vertical: 12 }),
color: Colors.blue,
child: Text("증가", {
style: TextStyle({ color: Colors.white })
})
})
})
]
});
}
}
// Factory function으로 export
export default function CounterWidget(): Widget {
return new Counter();
}
StatelessWidget vs StatefulWidget
상태가 없는 위젯과 상태가 있는 위젯의 차이를 확인해보세요.
StatelessWidget
class GreetingCard extends StatelessWidget {
constructor(private props: { name: string; message: string }) {
super();
}
build(context: BuildContext): Widget {
return Container({
padding: EdgeInsets.all(20),
child: Column({
children: [
Text(`안녕하세요, ${this.props.name}님!`),
Text(this.props.message)
]
})
});
}
}
StatefulWidget
class InteractiveCard extends StatefulWidget {
createState(): State<InteractiveCard> {
return new InteractiveCardState();
}
}
class InteractiveCardState extends State<InteractiveCard> {
clickCount = 0;
build(context: BuildContext): Widget {
return GestureDetector({
onClick: () => {
this.setState(() => {
this.clickCount++;
});
},
child: Text(`클릭 횟수: ${this.clickCount}`)
});
}
}