key.currentState

샤워실의 바보·2024년 2월 11일
0
post-thumbnail
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/sizes.dart';

class ChatsScreen extends StatefulWidget {
  const ChatsScreen({super.key});

  
  State<ChatsScreen> createState() => _ChatsScreenState();
}

class _ChatsScreenState extends State<ChatsScreen> {
  final GlobalKey<AnimatedListState> _key = GlobalKey<AnimatedListState>();

  final List<int> _items = [];

  void _addItem() {
    if (_key.currentState != null) {
      _key.currentState!.insertItem(
        _items.length,
        duration: const Duration(milliseconds: 500),
      );
      _items.add(_items.length);
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 1,
        title: const Text('Direct messages'),
        actions: [
          IconButton(
            onPressed: _addItem,
            icon: const FaIcon(FontAwesomeIcons.plus),
          ),
        ],
      ),
      body: AnimatedList(
        key: _key,
        padding: const EdgeInsets.symmetric(
          vertical: Sizes.size10,
        ),
        itemBuilder: (context, index, animation) {
          return FadeTransition(
            key: UniqueKey(),
            opacity: animation,
            child: SizeTransition(
              sizeFactor: animation,
              child: ListTile(
                leading: const CircleAvatar(
                  radius: 30,
                  foregroundImage: NetworkImage(
                    "https://avatars.githubusercontent.com/u/3612017",
                  ),
                  child: Text('니꼬'),
                ),
                title: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    Text(
                      "Lynn ($index)",
                      style: const TextStyle(fontWeight: FontWeight.w600),
                    ),
                    Text(
                      "2:16 PM",
                      style: TextStyle(
                        color: Colors.grey.shade500,
                        fontSize: Sizes.size12,
                      ),
                    ),
                  ],
                ),
                subtitle: const Text("Don't forget to make video"),
              ),
            ),
          );
        },
      ),
    );
  }
}

이 Flutter 코드는 "Direct messages"라는 제목의 ChatsScreen을 구현하고 있으며, 여기서는 동적으로 채팅 목록을 관리할 수 있는 인터페이스를 제공합니다. 사용자는 채팅을 추가하거나 길게 눌러서 삭제할 수 있으며, 특정 채팅을 탭하여 자세한 채팅 화면으로 이동할 수 있습니다.

주요 구성 요소 및 기능:

  1. AnimatedList와 GlobalKey:

    • AnimatedList 위젯은 채팅 목록을 동적으로 관리할 수 있게 해주며, 채팅이 추가되거나 삭제될 때 애니메이션 효과를 제공합니다.
    • GlobalKey<AnimatedListState>AnimatedList의 상태를 관리하고, 채팅 아이템을 추가하거나 삭제할 수 있는 메서드(insertItem, removeItem)에 접근할 수 있게 해줍니다.
  2. _addItem 메서드:

    • 새로운 채팅 아이템을 리스트에 추가하는 기능을 수행합니다. AnimatedListStateinsertItem 메서드를 호출하여 새 아이템을 리스트에 삽입하고, 해당 아이템에 대한 애니메이션을 적용합니다.
  3. _deleteItem 메서드:

    • 사용자가 길게 누른 채팅 아이템을 리스트에서 삭제하는 기능을 수행합니다. AnimatedListStateremoveItem 메서드를 호출하여 지정된 인덱스의 아이템을 삭제하고, 삭제 애니메이션을 적용합니다.
  4. _onChatTap 메서드:

    • 채팅 아이템을 탭했을 때 호출되며, ChatDetailScreen으로 화면 전환을 수행합니다. Navigator를 사용하여 새로운 화면으로 이동합니다.
  5. _makeTile 메서드:

    • 각 채팅 아이템을 구성하는 ListTile 위젯을 생성합니다. 사용자의 프로필 이미지, 이름, 메시지 내용, 메시지 시간 등을 표시합니다.
  6. AppBar와 IconButton:

    • 앱의 상단에 위치한 AppBar에는 화면의 제목과 새 채팅을 추가할 수 있는 IconButton이 포함됩니다.
  7. AnimatedList의 itemBuilder:

    • AnimatedList의 각 아이템을 빌드하는 데 사용되며, FadeTransitionSizeTransition을 사용하여 아이템이 리스트에 추가될 때의 애니메이션 효과를 정의합니다.

작동 원리:

  • 사용자가 상단의 '+' 아이콘 버튼을 탭하면 _addItem 메서드가 호출되어 새로운 채팅 아이템이 리스트에 추가됩니다.
  • 각 채팅 아이템은 길게 눌러서 삭제할 수 있으며, 이 때 _deleteItem 메서드가 호출됩니다.
  • 채팅 아이템을 탭하면 _onChatTap 메서드가 호출되어 ChatDetailScreen으로 화면이 전환됩니다.
  • AnimatedList는 채팅 아이템이 추가되거나 삭제될 때 부드러운 애니메이션 효과를 제공합니다.

이 코드는 AnimatedList 위젯과 함께 동적인 아이템 리스트를 관리하는 데 사용되는 두 가지 주요 메서드 _addItem_deleteItem을 정의합니다. 이 메서드들은 리스트에 아이템을 추가하거나 삭제할 때 부드러운 애니메이션 효과와 함께 이러한 변경사항을 적용합니다.

_addItem 메서드:

  • _addItem 메서드는 새로운 아이템을 리스트에 추가합니다.
  • 먼저, _key.currentStatenull이 아닌지 확인하여 AnimatedList의 현재 상태가 유효한지 검사합니다.
  • 유효한 경우, AnimatedListStateinsertItem 메서드를 호출하여 새 아이템을 삽입합니다. 이때, 삽입될 아이템의 인덱스는 _items.length로 지정되며, 즉 현재 리스트의 끝에 새 아이템을 추가하는 것을 의미합니다.
  • duration: _duration을 통해 아이템 삽입 시 발생하는 애니메이션의 지속 시간을 설정합니다.
  • 마지막으로, _items.add(_items.length);를 통해 아이템을 관리하는 리스트(_items)에 새 아이템을 실제로 추가합니다. 여기서 새 아이템의 값은 리스트의 현재 길이를 사용합니다.

_deleteItem 메서드:

  • _deleteItem 메서드는 지정된 인덱스의 아이템을 리스트에서 삭제합니다.
  • 마찬가지로, _key.currentStatenull이 아닌지 확인하여 AnimatedList의 현재 상태가 유효한지 검사합니다.
  • 유효한 경우, AnimatedListStateremoveItem 메서드를 호출하여 지정된 인덱스의 아이템을 삭제합니다.
  • removeItem 메서드는 삭제될 아이템의 애니메이션을 정의하기 위해 빌더 함수를 요구합니다. 여기서는 SizeTransition 위젯을 사용하여 아이템이 수축하며 사라지는 애니메이션을 구현합니다. sizeFactor: animation은 애니메이션의 진행 상태에 따라 위젯의 크기를 조절합니다.
  • duration: _duration을 통해 삭제 애니메이션의 지속 시간을 설정합니다.
  • 마지막으로, _items.removeAt(index);를 통해 아이템을 관리하는 리스트(_items)에서 실제로 해당 아이템을 삭제합니다.

결론:

이 두 메서드는 AnimatedList를 사용하여 Flutter 앱에서 동적인 리스트 관리와 함께 사용자에게 시각적으로 매력적인 애니메이션 효과를 제공합니다. 아이템 추가와 삭제 시 부드러운 애니메이션은 앱의 사용자 경험을 크게 향상시킬 수 있습니다.

_key.currentStatenull인지 확인하는 과정은 AnimatedList의 현재 상태에 안전하게 접근하기 위한 필수적인 단계입니다. GlobalKey<AnimatedListState>를 사용하는 주된 목적 중 하나는 직접적으로 위젯의 상태에 접근하여 메서드를 호출할 수 있도록 하는 것입니다. 예를 들어, AnimatedListStateinsertItemremoveItem 같은 메서드를 호출하기 위해서는 currentState가 실제로 존재해야만 합니다.

안 하면 발생할 수 있는 오류:

  • Null Pointer Exception: 만약 _key.currentStatenull이라면, 즉 AnimatedListState에 접근할 수 없는 상태에서 insertItem이나 removeItem 같은 메서드를 호출하려고 하면, 애플리케이션은 Null Pointer Exception을 발생시킬 수 있습니다. 이는 프로그램이 예상치 못한 방식으로 종료되는 원인이 될 수 있습니다.
  • 위젯 트리 상태 불일치: Flutter의 위젯 트리가 빌드 과정에 있거나 위젯이 아직 완전히 초기화되지 않은 시점에서 currentState에 접근하려고 하면, currentState가 아직 null일 수 있습니다. 이는 위젯이 아직 화면에 그려지기 전이거나, 위젯 트리에서 제거된 후일 수 있습니다.

왜 이 과정을 거쳐야 하는가?

  • 안정성 확보: null 체크를 통해 코드의 안정성을 확보하며, 예외 상황에서도 앱이 강제 종료되지 않고 적절히 대응할 수 있도록 합니다.
  • 위젯의 생명주기 관리: Flutter의 위젯 생명주기는 동적이며, 특히 AnimatedList와 같이 동적인 컨텐츠를 다루는 위젯에서는 위젯의 상태가 항상 예측 가능한 것은 아닙니다. null 체크를 함으로써 위젯의 현재 상태가 안전하게 접근 가능한지 확인하고, 위젯의 생명주기에 따른 변경사항을 적절히 관리할 수 있습니다.

이러한 이유로, AnimatedList의 상태에 접근하기 전에 _key.currentStatenull이 아닌지 확인하는 것은 중요한 프로그래밍 관행입니다. 이를 통해 더 견고하고 오류를 방지하는 코드를 작성할 수 있습니다.

_key.currentState에서 _keyGlobalKey의 인스턴스입니다. Flutter에서 GlobalKey는 위젯 트리 전체에서 고유한 키를 제공하며, 주로 위젯의 상태에 직접적으로 접근할 필요가 있을 때 사용됩니다. GlobalKey를 사용하면 위젯 트리의 다른 부분에서도 해당 키가 할당된 위젯의 상태(State)에 접근할 수 있습니다.

_key.currentState의 의미

  • _key는 특정 위젯에 고유한 식별자 역할을 하는 GlobalKey입니다.
  • currentState_key가 할당된 위젯의 State 객체에 대한 참조를 제공합니다. 이를 통해 위젯의 현재 상태에 접근하고, 해당 상태 객체 내의 메서드를 호출하거나, 상태 변수를 읽거나 변경할 수 있습니다.

사용 예시

예를 들어, AnimatedList 위젯에 GlobalKey<AnimatedListState>를 할당하면, 위젯 트리의 다른 부분에서 _key.currentState를 사용하여 AnimatedListState의 메서드를 호출할 수 있습니다. 이를 통해 프로그래밍적으로 아이템을 추가하거나 삭제하는 등의 작업을 수행할 수 있습니다.

GlobalKey<AnimatedListState> _key = GlobalKey<AnimatedListState>();

위의 코드에서 _keyAnimatedListState에 대한 전역 키를 생성합니다. 이 키를 AnimatedList 위젯의 key 속성에 할당함으로써, 앱의 다른 부분에서 _key.currentState를 통해 AnimatedList의 상태에 접근할 수 있게 됩니다.

_key.currentState의 중요성

_key.currentState를 사용하면, Flutter의 선언적 UI 모델 내에서 명령적인 작업을 수행할 수 있습니다. 이는 특히 동적인 목록 관리, 폼 필드의 데이터 검증 및 저장, 인터랙티브 애니메이션 제어 등의 경우에 유용합니다. 그러나 GlobalKey의 사용은 자원을 추가적으로 소모하고, 위젯 트리의 재구성을 유발할 수 있으므로 필요한 경우에만 제한적으로 사용하는 것이 좋습니다.

profile
공부하는 개발자

0개의 댓글