반응형

플러터 앱에서 위젯 Key를 왜 사용하는지, 또 어디에서 쓰이는지, Key의 종류는 어떤 것이 있는지 알아보도록 하겠습니다.


Key 란

key는 무엇일까요? 키는 위젯 트리에서 위젯이 움직일 때마다 현재 상태를 보존하는 역할을 합니다. key는 주로 Element가 Widget을 식별하는 데 사용합니다.

*Widget 트리와 Element 트리에 관한 설명은 아래 포스트를 참고해 주세요.

[flutter] 플러터 Widget 트리, Element 트리, RenderObject 트리

트리와의 관계를 간단히 짚어보겠습니다. Widget 트리가 빌드되면 그 뒤에 Element트리가 생성됩니다. Widget 트리가 재구성되면 Widget 자체는 폐기 및 재구성되며 Element는 기본적으로 재사용됩니다. 그리고 Element가 재사용될 때 새로 재구성된 Widget를 참조하게 됩니다.


위젯에 Key가 필요한 경우

대부분의 경우는 key를 신경 쓸 필요가 없지만 상태를 유지하고 있는 같은 종류의 위젯을 컬렉션에 더하거나, 제거하거나, 정렬할 때 key가 필요합니다. 코드에서 실제 예를 알아보겠습니다.

 

Key 사용하기

아래 두 개의 상자를 보여주는 앱이 있습니다.

전체 코드는 아래와 같습니다.

import 'package:flutter/material.dart';
import 'package:helloworld/screens/statefulTile.dart';

class KeyScreen extends StatefulWidget {
  const KeyScreen({ Key? key }) : super(key: key);

  @override
  State<KeyScreen> createState() => _KeyScreenState();
}

class _KeyScreenState extends State<KeyScreen> {
  late List<Widget> tiles;

  @override
  void initState() {
    super.initState();
    tiles = [
      StatefulTile(key: UniqueKey()),
      StatefulTile(key: UniqueKey()),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Key Test'),
      ),
      body: Row(children: tiles),
      floatingActionButton: FloatingActionButton(
        onPressed: changeTiles,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }

  void changeTiles() {
    setState(() {
      tiles.insert(1, tiles.removeAt(0));
    });
  }
}

화면은 Scaffold로 구성된 앱에 body에 tiles를 설정해 주고 있습니다.

initState에서 초기화하고 있는 tiles에는 StatefulTile 위젯이 두 개 들어가 있고 이 위젯은 단순히 랜덤 컬러로 색칠된 Tile를 표현한 위젯입니다.

우측 하단의 floatingActionButton을 클릭했을 때 호출되는 메소드에서 배열의 순서를 교환해 주고 있습니다.

이제 floatingActionButton을 눌렀을 때 tiles안에 들어있는 위젯의 순서가 바뀌었으니 화면에서 위젯이 바뀌는 걸 기대해 볼 수 있습니다.

바뀌지 않는 위젯

하지만 화면상에서 위젯이 바뀌지 않고 그대로 인걸 볼 수 있습니다. 

 

위젯이 화면에서 바뀌지 않는 이유

위젯이 바뀌지 않은 이유는 예제와 같이 같은 타입의 key를 설정하지 않은 StatefulWidget이 바뀌면 type과 비교를 해서 type이 같기 때문에 갱신할 필요가 없다고 판단하기 때문입니다. 따라서 화면이 다시 draw 되지 않습니다.

정리하면 위젯 트리가 변경되었는지 여부는 다음과 같은 순서로 판단합니다.

  1. 위젯이 동일한 타입인지 비교하고 다를 경우 갱신한다.
  2. 같은 key인지 비교해 다르면 갱신한다. 만약 key를 설정하지 않은 경우는 null로 설정되어 있다.

위의 예제에서는 key가 null 이였기 때문에 같은 타입으로 판단하여 갱신하지 않은 것입니다. 이제 key를 아래와 같이 설정해 보겠습니다.

위젯에 UniqueKey를 설정

위젯을 생성할 때 key에 UniqueKey를 넣어주었습니다.

 

이제 화면에서 버튼을 클릭하면 위젯이 잘 바뀌어 보입니다.

 

key를 설정해 Widget과 Element의 연결이 바뀌었을 때 원래의 key를 같은 계층 내에서 어디로 옮겨졌는지를 찾아 가능한 한 재이용하게 됩니다. 예제의 경우는 Row아래로 교환한 2개의 Widget이 있기 때문에 재사용하게 됩니다. 그러나 교환하려는 위젯 사이에 Padding 등이 있으면 Padding 아래에 교환하는 두 개의 Widget이 없기 때문에  말단의 Widget에 Key를 붙이면 동작하지 않습니다. 이러한 경우에는 Padding에 key를 붙이면 교환이 잘 이루어집니다.


key 유형

Key에는 LocalKey와 GlobalKey의 두 종류가 있습니다.

1. LocalKey (부모 Widget 이하에서 유니크한 키)

  • ValueKey : 하나의 정보에서 생성되는 키, 숫자, 문자열 등
  • ObjectKey : 객체에서 생성하는 키, 같은 타입이라도 객체의 내용이 다르면 다른 키가 된다.
  • UniqueKey : 특정 Widget 내에서 고유 한 키
  • PageStorageKey: 페이지 스크롤 위치가 있는 키

2.GlobalKey(앱 내에서 고유한 키)

 

주의할 점은 uniquekey는  자동으로 키를 만들어 주기 때문에 편리하지만 key를 사용해 액세스 할 때는 그 값을 기억할 필요가 있습니다.


여기까지 읽어주셔서 감사합니다.

 

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기