개발노트

33. [Flutter] AnimatedList 로 쉽게 List 애니메이션 효과 구현하기 (with GlobalKey) 본문

앱 개발/Flutter

33. [Flutter] AnimatedList 로 쉽게 List 애니메이션 효과 구현하기 (with GlobalKey)

mroh1226 2023. 9. 22. 14:52
반응형

AnimatedList

  • AnimatedList가 앞서 소개해드린 ListView 애니메이션 효과 구현 보다 더욱 간단한 이유는 위젯 자체에서 Animation<double>을 제공한다는 점입니다.
  • 따라서 Animation Tween을 따로 구현할 필요가 없어 소스가 더욱 간결해집니다.
  • ListView 위젯에 애니메이션 효과를 넣어야한다면 AnimatedList를 사용하는 것이 더욱 간단합니다.

예시.

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

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

  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  final List<int> list = [];
  final GlobalKey<AnimatedListState> _key = GlobalKey<AnimatedListState>();

  //ListTile 생성
  void _onAddTap() {
    if (_key.currentState != null) {
      _key.currentState!
          .insertItem(list.length, duration: const Duration(milliseconds: 200));
      list.add(list.length);
    }
    setState(() {});
  }

  void _onDeleteTap(int index) {
    _key.currentState!.removeItem(
        index,
        (context, animation) => SizeTransition(
            sizeFactor: animation,
            child: FadeTransition(
              opacity: animation,
              child: Container(color: Colors.red, child: _makeListTile(index)),
            )));
    list.removeAt(index);
  }

  Widget _makeListTile(int index) {
    return ListTile(
      key: UniqueKey(),
      onLongPress: () => _onDeleteTap(index),
      leading: const FaIcon(
        FontAwesomeIcons.robot,
        color: Colors.purple,
      ),
      title: Text(
        "$index번 Bot",
        style:
            const TextStyle(color: Colors.brown, fontWeight: FontWeight.bold),
      ),
      subtitle: const Text("Ready"),
      trailing: const FaIcon(
        FontAwesomeIcons.solidCircleCheck,
        color: Colors.green,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 1,
        title: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const Text(
              "Bot List",
              style: TextStyle(color: Colors.black),
            ),
            IconButton(
                onPressed: _onAddTap,
                icon: const FaIcon(FontAwesomeIcons.userPlus)),
          ],
        ),
      ),
      body: AnimatedList(
        key: _key,
        itemBuilder: (context, index, animation) {
          return FadeTransition(
              opacity: animation,
              child: ScaleTransition(
                  scale: animation, child: _makeListTile(index)));
        },
      ),
    );
  }
}

 

 

FadeTransition( opacity: animation ...
ScaleTransition( scale: animation ...


위와 같이 AnimatedList에서 제공하는 animation을 Animation<double>형을 갖는 속성에 매핑하여 손쉽게 구현할 수 있습니다.


메소드별 설명.

1. _onAddTap()

  • 이 메소드는 "User Plus" 아이콘 버튼이 눌렸을 때 호출됩니다.
  • _key.currentState를 사용하여 현재 AnimatedListState를 가져옵니다. 이것은 AnimatedList 위젯의 상태를 제어하기 위한 핵심입니다.
  • _key.currentState!.insertItem(list.length, duration: const Duration(milliseconds: 200));을 호출하여 새 항목을 리스트에 추가합니다. insertItem은 새 항목을 삽입하고 애니메이션 효과를 제공합니다.
  • list.add(list.length);를 통해 list 리스트에 항목을 추가합니다. 이것은 리스트에 새 항목을 추가한 것을 추적하는 데 사용됩니다.
  • setState(() {});를 호출하여 상태를 업데이트하고 화면을 다시 빌드하도록 알립니다.

2. _onDeleteTap()

  • 이 메소드는 리스트 항목을 삭제하기 위해 호출됩니다.
    ListTile 위젯의 onLongPress: 속성에 연결되어 각 리스트 항목에 있는 "Robot" 아이콘을 길게 누르면 호출됩니다.
  • _key.currentState!.removeItem(...)을 호출하여 AnimatedList에서 항목을 제거합니다.
  • removeItem 메소드의 두 번째 인수로 제거 애니메이션을 정의합니다. 여기서는 SizeTransition과 FadeTransition을 사용하여 크기 변경 및 투명도 효과를 적용합니다.
  • list.removeAt(index);를 호출하여 list 리스트에서 해당 항목을 제거합니다.

3. _makeListTile 메소드:

  • 이 메소드는 각각의 리스트 항목을 생성하고 반환합니다.
  • ListTile 위젯을 사용하여 리스트 항목의 모양과 내용을 정의합니다. 
  • ListTile은 각 항목의 레이아웃을 정의하는 데 사용됩니다.


GlobalKey 사용이유

이 소스 코드에서 GlobalKey는 AnimatedList 위젯을 제어하기 위한 키로 사용됩니다. GlobalKey는 위젯 트리에서 특정 위젯의 고유한 식별자 역할을 하며, 해당 위젯을 참조하거나 제어할 때 사용됩니다. 

 

1. GlobalKey<AnimatedListState>를 전역변수로 선언합니다.

final GlobalKey<AnimatedListState> _key = GlobalKey<AnimatedListState>();
  • GlobalKey<> 안에는 Generic 형식을 사용하며, _key 변수에서는 AnimatedListState 형식을 Generic으로 사용하였습니다.
  • final 키워드를 사용하여 _key 변수를 상수로 선언하고 나중에 수정되지 않도록 합니다.

 

2. _key.currentState는 현재 AnimatedListState를 참조합니다. 이것은 AnimatedList 위젯을 제어하는 데 사용됩니다.

if (_key.currentState != null) {
  _key.currentState!
    .insertItem(list.length, duration: const Duration(milliseconds: 200));
  list.add(list.length);
}
  • insertItem 메서드를 호출하여 AnimatedList에 새 항목을 추가하고 애니메이션 효과를 부여합니다. 

3. _onDeleteTap 메서드 내에서 _key.currentState를 사용

_key.currentState!.removeItem(
  index,
  (context, animation) => SizeTransition(
    sizeFactor: animation,
    child: FadeTransition(
      opacity: animation,
      child: Container(color: Colors.red, child: _makeListTile(index)),
    ),
  ),
);
  • _key.currentState를 사용하여 AnimatedList에서 항목을 제거하고 제거 애니메이션을 부여합니다.
  • 요약하면, GlobalKey를 사용하여 AnimatedList 위젯의 상태를 관리하고 제어합니다. 이렇게 하면 AnimatedList의 상태를 다른 메서드에서도 조작할 수 있으며, 애니메이션과 함께 리스트 항목을 추가하거나 제거할 수 있습니다.

빌드.

반응형
Comments