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
을 구현하고 있으며, 여기서는 동적으로 채팅 목록을 관리할 수 있는 인터페이스를 제공합니다. 사용자는 채팅을 추가하거나 길게 눌러서 삭제할 수 있으며, 특정 채팅을 탭하여 자세한 채팅 화면으로 이동할 수 있습니다.
AnimatedList와 GlobalKey:
AnimatedList
위젯은 채팅 목록을 동적으로 관리할 수 있게 해주며, 채팅이 추가되거나 삭제될 때 애니메이션 효과를 제공합니다.GlobalKey<AnimatedListState>
는 AnimatedList
의 상태를 관리하고, 채팅 아이템을 추가하거나 삭제할 수 있는 메서드(insertItem
, removeItem
)에 접근할 수 있게 해줍니다._addItem 메서드:
AnimatedListState
의 insertItem
메서드를 호출하여 새 아이템을 리스트에 삽입하고, 해당 아이템에 대한 애니메이션을 적용합니다._deleteItem 메서드:
AnimatedListState
의 removeItem
메서드를 호출하여 지정된 인덱스의 아이템을 삭제하고, 삭제 애니메이션을 적용합니다._onChatTap 메서드:
ChatDetailScreen
으로 화면 전환을 수행합니다. Navigator
를 사용하여 새로운 화면으로 이동합니다._makeTile 메서드:
ListTile
위젯을 생성합니다. 사용자의 프로필 이미지, 이름, 메시지 내용, 메시지 시간 등을 표시합니다.AppBar와 IconButton:
AppBar
에는 화면의 제목과 새 채팅을 추가할 수 있는 IconButton
이 포함됩니다.AnimatedList의 itemBuilder:
AnimatedList
의 각 아이템을 빌드하는 데 사용되며, FadeTransition
과 SizeTransition
을 사용하여 아이템이 리스트에 추가될 때의 애니메이션 효과를 정의합니다._addItem
메서드가 호출되어 새로운 채팅 아이템이 리스트에 추가됩니다._deleteItem
메서드가 호출됩니다._onChatTap
메서드가 호출되어 ChatDetailScreen
으로 화면이 전환됩니다.AnimatedList
는 채팅 아이템이 추가되거나 삭제될 때 부드러운 애니메이션 효과를 제공합니다.이 코드는 AnimatedList
위젯과 함께 동적인 아이템 리스트를 관리하는 데 사용되는 두 가지 주요 메서드 _addItem
과 _deleteItem
을 정의합니다. 이 메서드들은 리스트에 아이템을 추가하거나 삭제할 때 부드러운 애니메이션 효과와 함께 이러한 변경사항을 적용합니다.
_addItem
메서드는 새로운 아이템을 리스트에 추가합니다._key.currentState
가 null
이 아닌지 확인하여 AnimatedList
의 현재 상태가 유효한지 검사합니다.AnimatedListState
의 insertItem
메서드를 호출하여 새 아이템을 삽입합니다. 이때, 삽입될 아이템의 인덱스는 _items.length
로 지정되며, 즉 현재 리스트의 끝에 새 아이템을 추가하는 것을 의미합니다.duration: _duration
을 통해 아이템 삽입 시 발생하는 애니메이션의 지속 시간을 설정합니다._items.add(_items.length);
를 통해 아이템을 관리하는 리스트(_items
)에 새 아이템을 실제로 추가합니다. 여기서 새 아이템의 값은 리스트의 현재 길이를 사용합니다._deleteItem
메서드는 지정된 인덱스의 아이템을 리스트에서 삭제합니다._key.currentState
가 null
이 아닌지 확인하여 AnimatedList
의 현재 상태가 유효한지 검사합니다.AnimatedListState
의 removeItem
메서드를 호출하여 지정된 인덱스의 아이템을 삭제합니다.removeItem
메서드는 삭제될 아이템의 애니메이션을 정의하기 위해 빌더 함수를 요구합니다. 여기서는 SizeTransition
위젯을 사용하여 아이템이 수축하며 사라지는 애니메이션을 구현합니다. sizeFactor: animation
은 애니메이션의 진행 상태에 따라 위젯의 크기를 조절합니다.duration: _duration
을 통해 삭제 애니메이션의 지속 시간을 설정합니다._items.removeAt(index);
를 통해 아이템을 관리하는 리스트(_items
)에서 실제로 해당 아이템을 삭제합니다.이 두 메서드는 AnimatedList
를 사용하여 Flutter 앱에서 동적인 리스트 관리와 함께 사용자에게 시각적으로 매력적인 애니메이션 효과를 제공합니다. 아이템 추가와 삭제 시 부드러운 애니메이션은 앱의 사용자 경험을 크게 향상시킬 수 있습니다.
_key.currentState
가 null
인지 확인하는 과정은 AnimatedList
의 현재 상태에 안전하게 접근하기 위한 필수적인 단계입니다. GlobalKey<AnimatedListState>
를 사용하는 주된 목적 중 하나는 직접적으로 위젯의 상태에 접근하여 메서드를 호출할 수 있도록 하는 것입니다. 예를 들어, AnimatedListState
의 insertItem
과 removeItem
같은 메서드를 호출하기 위해서는 currentState
가 실제로 존재해야만 합니다.
_key.currentState
가 null
이라면, 즉 AnimatedListState
에 접근할 수 없는 상태에서 insertItem
이나 removeItem
같은 메서드를 호출하려고 하면, 애플리케이션은 Null Pointer Exception
을 발생시킬 수 있습니다. 이는 프로그램이 예상치 못한 방식으로 종료되는 원인이 될 수 있습니다.currentState
에 접근하려고 하면, currentState
가 아직 null
일 수 있습니다. 이는 위젯이 아직 화면에 그려지기 전이거나, 위젯 트리에서 제거된 후일 수 있습니다.null
체크를 통해 코드의 안정성을 확보하며, 예외 상황에서도 앱이 강제 종료되지 않고 적절히 대응할 수 있도록 합니다.AnimatedList
와 같이 동적인 컨텐츠를 다루는 위젯에서는 위젯의 상태가 항상 예측 가능한 것은 아닙니다. null
체크를 함으로써 위젯의 현재 상태가 안전하게 접근 가능한지 확인하고, 위젯의 생명주기에 따른 변경사항을 적절히 관리할 수 있습니다.이러한 이유로, AnimatedList
의 상태에 접근하기 전에 _key.currentState
가 null
이 아닌지 확인하는 것은 중요한 프로그래밍 관행입니다. 이를 통해 더 견고하고 오류를 방지하는 코드를 작성할 수 있습니다.
_key.currentState
에서 _key
는 GlobalKey
의 인스턴스입니다. Flutter에서 GlobalKey
는 위젯 트리 전체에서 고유한 키를 제공하며, 주로 위젯의 상태에 직접적으로 접근할 필요가 있을 때 사용됩니다. GlobalKey
를 사용하면 위젯 트리의 다른 부분에서도 해당 키가 할당된 위젯의 상태(State
)에 접근할 수 있습니다.
_key
는 특정 위젯에 고유한 식별자 역할을 하는 GlobalKey
입니다.currentState
는 _key
가 할당된 위젯의 State
객체에 대한 참조를 제공합니다. 이를 통해 위젯의 현재 상태에 접근하고, 해당 상태 객체 내의 메서드를 호출하거나, 상태 변수를 읽거나 변경할 수 있습니다.예를 들어, AnimatedList
위젯에 GlobalKey<AnimatedListState>
를 할당하면, 위젯 트리의 다른 부분에서 _key.currentState
를 사용하여 AnimatedListState
의 메서드를 호출할 수 있습니다. 이를 통해 프로그래밍적으로 아이템을 추가하거나 삭제하는 등의 작업을 수행할 수 있습니다.
GlobalKey<AnimatedListState> _key = GlobalKey<AnimatedListState>();
위의 코드에서 _key
는 AnimatedList
의 State
에 대한 전역 키를 생성합니다. 이 키를 AnimatedList
위젯의 key
속성에 할당함으로써, 앱의 다른 부분에서 _key.currentState
를 통해 AnimatedList
의 상태에 접근할 수 있게 됩니다.
_key.currentState
를 사용하면, Flutter의 선언적 UI 모델 내에서 명령적인 작업을 수행할 수 있습니다. 이는 특히 동적인 목록 관리, 폼 필드의 데이터 검증 및 저장, 인터랙티브 애니메이션 제어 등의 경우에 유용합니다. 그러나 GlobalKey
의 사용은 자원을 추가적으로 소모하고, 위젯 트리의 재구성을 유발할 수 있으므로 필요한 경우에만 제한적으로 사용하는 것이 좋습니다.