Flutter 위젯
Views
View 컨테이너
React Native 에서는 View 가 컨테이너이고 Flexbox를 이용한 레이아웃, 스타일, 터치 핸들링, 접근성제어를 지원
Flutter에서는 Container나, Column, Row, Center같은 위젯 라이브러리의 핵심 레이아웃 위젯을 사용할 수 있음.
FlatList, SectionList
- ListView : 목록의 수가 적은 경우에 가장 적합함.
- 무거운 목록이거나 무한 스크롤 목록일때는 ListView.builder 를 사용
- 자식들을 필요할 때만 빌드하고, 화면에 나타나야할 자식들만 빌드함
1
2
3
4
5
6
7
8
9
10
// Flutter
var data = [ ... ];
ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
return Text(
data[index],
);
},
)
Canvas
- ReactNative에서는 직접적으로 지원하는 컴포넌트가 없음
- Flutter에서는 CustomPaint, CustomPainter 클래스를 사용하여 캔버스를 그릴 수 있다.
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
// Flutter
class MyCanvasPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint();
paint.color = Colors.amber;
canvas.drawCircle(Offset(100.0, 200.0), 40.0, paint);
Paint paintRect = Paint();
paintRect.color = Colors.lightBlue;
Rect rect = Rect.fromPoints(Offset(150.0, 300.0), Offset(300.0, 400.0));
canvas.drawRect(rect, paintRect);
}
bool shouldRepaint(MyCanvasPainter oldDelegate) => false;
bool shouldRebuildSemantics(MyCanvasPainter oldDelegate) => false;
}
class _MyCanvasState extends State<MyCanvas> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomPaint(
painter: MyCanvasPainter(),
),
);
}
}
레이아웃
레이아웃 속성 정의
React native에서는 style props를 이용해 flexbox 속성을정의함.
1 2 3 4
// React Native <View style= >
flutter에서는 컨트롤 위젯 및 스타일 속성을 결합하여 설계된 위젯을 통해 레이아웃을 정의한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
// Flutter Center( child: Column( children: <Widget>[ Container( color: Colors.red, width: 100.0, height: 100.0, ), Container( color: Colors.blue, width: 100.0, height: 100.0, ), Container( color: Colors.green, width: 100.0, height: 100.0, ), ], ), )
위젯을 겹쳐 쌓아올리는 방법
- React Native에서는 absolute 을 사용
- flutter에서는 Stack을 사용함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Flutter
Stack(
alignment: const Alignment(0.6, 0.6),
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(
'https://avatars3.githubusercontent.com/u/14101776?v=4'),
),
Container(
decoration: BoxDecoration(
color: Colors.black45,
),
child: Text('Flutter'),
),
],
)
스타일링
컴포넌트 꾸미기
- react native 에서는 인라인 스타일링과 stylesheets.create를 이용한 스타일링 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<View style={styles.container}>
<Text style=>
This is a sample text
</Text>
</View>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
- flutter에서는 Text 위젯은 style 속성에 TextStyle클래스를 사용할 수 있음.
- 여러 곳에서 같은 스타일을 사용하고 싶으면 따로 빼서 적용가능
- 다른 위젯에서도 비슷한 방식인가?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var textStyle = TextStyle(fontSize: 32.0, color: Colors.cyan, fontWeight:
FontWeight.w600);
...
Center(
child: Column(
children: <Widget>[
Text(
'Sample text',
style: textStyle,
),
Padding(
padding: EdgeInsets.all(20.0),
child: Icon(Icons.lightbulb_outline,
size: 48.0, color: Colors.redAccent)
),
],
),
)
Icons와 Colors를 사용하는 방법은?
- flutter에서는 material 라이브러리를 import하면 다양한 material icon과 컬러를 가져옴
1
Icon(Icons.lightbulb_outline, color: Colors.redAccent)
- Icons 클래스를 사용할떄는 pubspec.yaml 파일에 uses-material-design : true 를 꼭 설정해줘야함
1
2
name: my_awesome_application
flutter: uses-material-design: true
- 쿠퍼티노 아이콘 사용
1
2
3
name: my_awesome_application
dependencies:
cupertino_icons: ^0.1.0
- 컴포넌트 전체적인 색과 스타일을 지정하고 싶으면 ThemeData 클래스를 사용
- MaterialApp 에서 theme 속성에 ThemeData 객체를 설정한다.
- Colors 클래스는 material 디자인의 color paletter에 해당하는 색상을 제공
1
2
3
4
5
6
7
8
9
10
11
12
13
class SampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
textSelectionColor: Colors.red
),
home: SampleAppPage(),
);
}
}
스타일 테마 추가
- React Native에서는 컴포넌트 공통 테마는 stylesheets에 정의한 후 컴포넌트에 사용함
- Flutter에서는 ThemeData 클래스에 스타일을 정의하고, MaterialApp 위젯의 테마 속성에 전달함으로써 거의 모든 곳에 균일한 스타일을 적용할 수 있음.
1
2
3
4
5
6
7
8
9
10
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.cyan,
brightness: Brightness.dark,
),
home: StylingPage(),
);
}
- Theme는 MaterialApp 위젯을 사용하지 않아도 적용가능.
- data 매개변수에서 ThemeData를 가져와 모든 자식 위젯에 ThemeData를 적용함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@override
Widget build(BuildContext context) {
return Theme(
data: ThemeData(
primaryColor: Colors.cyan,
brightness: brightness,
),
child: Scaffold(
backgroundColor: Theme.of(context).primaryColor,
...
...
),
);
}
상태관리
- State 클래스
- StatefulWidget
- 상태 관리 방법
StatelessWidget
- 상태 변화가 필요없는 위젯.
객체의 자체적인 구성정보나 위젯의 BuildContext 이외의 것에 의존하지 않을때 유용함
- 상태가 없는 위젯의 build 메서드는 보통 3가지 상황에서만 호출됨
- 위젯이 트리에 추가될 때
- 위젯의 부모가 설정이 변경됐을때
- 사용하고 있는 InheritedWidget이 변경될 때
StatefulWidget
setState를 호출하여 Flutter 프레임워크에게 상태가 변경됐음을 알려줌.
- 이후 앱이 build 메서드를 다시 실행하여 변경사항을 반영함
아래는 createState() 메서드를 필요로하는 StatefulWidget을 선언하는 예시
- 위젯의 상태를 관리하는 상태객체 _MyStatefulWidgetState를 생성함
1 2 3 4 5 6 7
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget({Key key, this.title}) : super(key: key); final String title; @override _MyStatefulWidgetState createState() => _MyStatefulWidgetState(); }
아래는 _MyStatefulWidgetState 라는 상태 클래스.
- 상태가 바뀌면 setState가 새로운 toggle 값과 함께 호출됨.
- 이후 프레임워크가 UI위젯을 다시 빌드함.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
class _MyStatefulWidgetState extends State<MyStatefulWidget> { bool showtext=true; bool toggleState=true; Timer t2; void toggleBlinkState(){ setState((){ toggleState=!toggleState; }); var twenty = const Duration(milliseconds: 1000); if(toggleState==false) { t2 = Timer.periodic(twenty, (Timer t) { toggleShowText(); }); } else { t2.cancel(); } } void toggleShowText(){ setState((){ showtext=!showtext; }); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( children: <Widget>[ (showtext ?(Text('This execution will be done before you can blink.')) :(Container()) ), Padding( padding: EdgeInsets.only(top: 70.0), child: RaisedButton( onPressed: toggleBlinkState, child: (toggleState ?( Text('Blink')) :(Text('Stop Blinking')) ) ) ) ], ), ), ); } }
StatefulWidget 과 StatelessWidget의 모범사례
위젯을 설계할때의 고려사항
위젯이 StatefulWidget인지 StatelessWidget인지 결정하라
- 위젯이 변화하면 Stateful 사용
- 위젯이 final이거나 immutable이면, Stateless를 사용
어떤 객체가 위젯의 상태를 관리하는지 결정하라
- Flutter에서 상태를 관리하는 3가지 방법
- 위젯이 자신의 상태를 관리
- 부모위젯이 상태를 관리
- 혼합하여 관리
- 원칙
- 해당 상태가 사용자 입력이라면, 상위위젯에서 관리하는 것이 가장 좋음
- ex : 슬라이더 위치 혹은 체크박스의 선택과 취소
- 해당 상태가 UI와 연관이 깊으면, 해당 위젯에서 관리
- ex : 애니메이션
- 잘모르겠을때는 부모 위젯이 관리하도록 함
- 해당 상태가 사용자 입력이라면, 상위위젯에서 관리하는 것이 가장 좋음
- Flutter에서 상태를 관리하는 3가지 방법
StatefulWidget의 하위 클래스 및 State
- 아래 예시는 자신이 직접 상태를 관리하는 것
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class MyStatefulWidget extends StatefulWidget { MyStatefulWidget({Key key, this.title}) : super(key: key); final String title; @override _MyStatefulWidgetState createState() => _MyStatefulWidgetState(); } class _MyStatefulWidgetState extends State<MyStatefulWidget> { @override Widget build(BuildContext context) { ... } }
StatefulWidget을 위젯트리에 추가하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class MyStatelessWidget extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyStatefulWidget(title: 'State Change Demo'), ); } }
- 위와같이 Stateless 위젯 안에 Stateful 위젯을 추가하는 방식도 통함