티스토리 뷰

반응형

위젯은 화면에 표시되는 것이라고 생각하면 됩니다.

모든 화면 표시와 사용자 상호작용에 위젯을 사용하기 때문입니다.

 

위젯은 크게 Stateless 위젯과 Stateful 위젯으로 구별합니다.

 

Stateless 위젯

 

화면 표시용 위젯입니다.

위젯이 로딩되어 화면에 표시된 이후에는 사용자 이벤트나 동작이 있어도 내용을 변경할 수 없습니다.

 

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  title: 'Stateless Widget',
  home: Scaffold(
    appBar: AppBar(title: Text('Stateless 위젯')),
    body: _FirstStatelessWidget(),
  ),
));

class _FirstStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Stateless');
  }
}

 

  1. Scaffold 위젯의 body 속성에 _FirstStatelessWidget 위젯을 생성했습니다.
  2. _FirstStatelessWidget 클래스는 StatelessWidget 클래스를 상속받고 있습니다.
  3. build 함수에서는 Text 위젯을 반환합니다.

 

Stateless 위젯을 만들기 위해서는 StatelessWidget 클래스를 상속하고 build 함수에서 원하는 위젯을 반환하면 됩니다.

 

 

Stateless 위젯 -> Stateful 위젯

 

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  title: 'Stateless -> Stateful',
  home: Scaffold(
    appBar: AppBar(title: Text('Stateless -> Stateful')),
    body: _FirstStatefulWidget(),
  ),
));

class _FirstStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _FirstStatefulWidgetState();
}

class _FirstStatefulWidgetState extends State<_FirstStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return Text('Stateful');
  }
}

 

  1. Stateful 위젯을 body 속성에 배치하였습니다.
  2. Stateful 위젯은 State를 가지기 때문에 _FirstStatefulWidget 클래스는 build 대신에 createState를 구현합니다.
  3. _FirstStatefulWidgetState 클래스는 State<_FirstStatefulWidget>를 상속하고 build를 구현합니다.

 

Stateless 위젯은 처음 화면에 표시한 내용을 변경할 수 없습니다. 하지만 Stateful 위젯은 변경된 내용을 화면에 표시할 수 있습니다. 

플러터는 고정부와 변동부를 구별하도록 설계되어 있습니다. 위에서 고정부는 _FirstStatefulWidget 클래스이고 변동부는 _FirstStatefulWidgetState입니다.

 

 

 

Stateful 위젯 생명주기

화면 갱신은 내부적으로 상태 변화와 생명주기를 활용합니다.

 

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  title: 'Stateless -> Stateful',
  home: Scaffold(
    appBar: AppBar(title: Text('Stateless -> Stateful')),
    body: _MyStatefulWidget(),
  ),
));

class _MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<_MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return Text('Stateful');
  }
}

 

 

먼저 _MyStatefulWidgetState 안에서 ctrl + o를 눌러 override 가능한 함수들을 확인합니다.

 

위의 함수들을 override 해줍니다.

 

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  title: 'Stateless -> Stateful',
  home: Scaffold(
    appBar: AppBar(title: Text('Stateless -> Stateful')),
    body: _MyStatefulWidget(),
  ),
));

class _MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<_MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return Text('Stateful');
  }

  @override
  void didChangeDependencies() {

  }

  @override
  void dispose() {

  }

  @override
  void deactivate() {

  }

  @override
  void setState(VoidCallback fn) {

  }

  @override
  void reassemble() {

  }

  @override
  void didUpdateWidget(_MyStatefulWidget oldWidget) {

  }

  @override
  void initState() {

  }
}

그러면 위와 같이 override가 됩니다.

 

initState은 위젯이 생성될 때 한 번만 호출됩니다. 변수를 초기화할 때 필요합니다.

build는 위젯의 내용을 반환합니다. 계산이 오래 걸리는 동작에 필요합니다.

setState는 화면을 갱신할 때 호출합니다.

 

 

생명주기 확인해보기

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
  title: 'Stateless -> Stateful',
  home: Scaffold(
    appBar: AppBar(title: Text('Stateless -> Stateful')),
    body: _MyStatefulWidget(),
  ),
));

class _MyStatefulWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<_MyStatefulWidget> {

  var _buttonState;

  @override
  void initState() {
    super.initState();
    print('initState: 기본 값 설정');
    _buttonState = 'OFF';
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies 호출');
  }

  @override
  Widget build(BuildContext context) {
    print('build 호출');
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text('버튼을 누르세요.'),
          onPressed: _onClick,
        ),
        Row(
          children: <Widget>[
            Text('버튼 상태: '),
            Text(_buttonState)
          ],
        )
      ],
    );
  }

  void _onClick() {
    print('onClick 호출');
    setState((){
      print('setState 호출');
      if(_buttonState == 'OFF') {
        _buttonState = 'ON';
      } else {
        _buttonState = 'OFF';
      }
    });
  }

  @override
  void didUpdateWidget(_MyStatefulWidget oldWidget) {
    print('didUpdateWidget');
  }

  @override
  void deactivate() {
    print('deactivate');
  }

  @override
  void dispose() {
    print('dispose');
  }
}

간단하게 생명주기를 확인하는 코드를 작성했습니다.

 

버튼을 클릭해서 ON/OFF를 하는 코드입니다.

 

 

  1. initState 함수에서 _buttonState 변수에 OFF 문자열을 초기화해주었습니다. 로그에서는 initState, didChangeDependencies, build 순으로 호출되고 화면에 표시됩니다.
  2. 버튼을 누르면 _onClick 메서드가 호출됩니다.
  3. _onClick에서는 setState 함수가 호출됩니다.

 

플러터는 선언적 프로그래밍으로서 변수의 값만 변경해도 화면이 자동으로 갱신됩니다. 따라서 개발자는 UI가 아닌 로직에만 집중할 수 있습니다.

 

 

 

생명주기의 로그를 확인하면 아래와 같습니다.

I/flutter ( 6970): initState: 기본 값 설정
I/flutter ( 6970): didChangeDependencies 호출
I/flutter ( 6970): build 호출
I/flutter ( 6970): onClick 호출
I/flutter ( 6970): setState 호출
I/flutter ( 6970): onClick 호출
I/flutter ( 6970): setState 호출
I/flutter ( 6970): build 호출
I/flutter ( 6970): onClick 호출
I/flutter ( 6970): setState 호출
I/flutter ( 6970): build 호출

 

반응형
댓글