
import 'package:flutter/material.dart';
class SwipingCardsScreen extends StatefulWidget {
const SwipingCardsScreen({super.key});
State<SwipingCardsScreen> createState() => _SwipingCardsScreenState();
}
class _SwipingCardsScreenState extends State<SwipingCardsScreen>
with SingleTickerProviderStateMixin {
// 현재 컨텍스트의 크기를 얻어옵니다. 이를 통해 카드의 크기 및 위치 조정에 사용됩니다.
late final size = MediaQuery.of(context).size;
// 애니메이션 컨트롤러를 초기화합니다. 이 컨트롤러는 카드의 위치를 제어합니다.
late final AnimationController _animationController = AnimationController(
vsync: this, // 프레임 업데이트에 맞춰 애니메이션을 동기화합니다.
duration: const Duration(seconds: 2), // 애니메이션의 전체 길이를 2초로 설정합니다.
lowerBound: size.width * -1, // 애니메이션의 하한값을 화면 너비의 -1배로 설정합니다.
upperBound: size.width, // 애니메이션의 상한값을 화면 너비로 설정합니다.
value: 0.0, // 애니메이션의 시작값을 0으로 설정합니다.
);
// 사용자가 카드를 드래그할 때 호출됩니다.
void _onHorizontalDragUpdate(DragUpdateDetails details) {
_animationController.value += details.delta.dx; // 드래그 거리만큼 애니메이션 값을 조정합니다.
}
// 사용자가 드래그를 끝내고 손을 떼었을 때 호출됩니다.
void _onHorizontalDragEnd(DragEndDetails details) {
_animationController.animateTo(
0, // 카드를 중앙으로 되돌립니다.
curve: Curves.bounceOut, // 부드럽게 되돌리는 효과를 추가합니다.
);
}
void dispose() {
_animationController.dispose(); // 위젯이 제거될 때 애니메이션 컨트롤러를 정리합니다.
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Swiping Cards'),
),
body: AnimatedBuilder(
animation: _animationController, // 애니메이션 컨트롤러를 바탕으로 UI를 재구성합니다.
builder: (context, child) {
// 카드 위젯을 구성합니다.
return Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: GestureDetector(
onHorizontalDragUpdate: _onHorizontalDragUpdate, // 드래그 업데이트 콜백
onHorizontalDragEnd: _onHorizontalDragEnd, // 드래그 엔드 콜백
child: Transform.translate(
offset: Offset(_animationController.value, 0), // 카드의 위치를 애니메이션 값에 따라 조정합니다.
child: Material(
elevation: 10, // 카드에 그림자를 추가합니다.
color: Colors.red.shade100, // 카드의 배경색을 설정합니다.
child: SizedBox(
width: size.width * 0.8,
height: size.height * 0.5,
),
),
),
),
),
],
);
},
),
);
}
}
이 코드는 사용자가 카드를 좌우로 스와이프할 수 있는 간단한 UI를 구현한 예제입니다. SwipingCardsScreen 위젯은 스와이핑 동작을 감지하고, 카드가 사용자의 입력에 따라 움직이도록 합니다. 애니메이션 컨트롤러를 사용하여 카드의 위치를 조정하고, 스와이프 동작이 끝났을 때 카드가 원래 위치로 돌아오도록 합니다.
late final AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
lowerBound: size.width * -1, // 카드가 왼쪽으로 최대 얼마나 이동할 수 있는지 정의
upperBound: size.width, // 카드가 오른쪽으로 최대 얼마나 이동할 수 있는지 정의
value: 0.0, // 초기 카드 위치는 가운데
);
AnimationController는 카드의 현재 위치를 관리합니다. vsync는 애니메이션의 성능을 최적화하기 위해 현재 위젯의 상태와 동기화됩니다.void _onHorizontalDragUpdate(DragUpdateDetails details) {
_animationController.value += details.delta.dx; // 사용자가 카드를 드래그할 때 위치 업데이트
}
_animationController의 값이 업데이트되어, 카드가 수평으로 이동합니다.void _onHorizontalDragEnd(DragEndDetails details) {
_animationController.animateTo(
0,
curve: Curves.bounceOut, // 드래그가 끝난 후 카드가 부드럽게 원래 위치로 돌아감
);
}
_animationController는 animateTo 함수를 사용해 카드를 원래 위치(중앙)으로 부드럽게 이동시킵니다. Curves.bounceOut 커브는 이동이 끝날 때 탄성 효과를 추가합니다.AnimatedBuilder 위젯은 _animationController에 의해 제어되는 애니메이션 값이 변경될 때마다 builder 함수를 재실행하여 위젯 트리를 다시 빌드합니다. 이를 통해 카드의 위치가 실시간으로 업데이트됩니다.AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Stack(
children: [
Align(
alignment: Alignment.topCenter,
child: GestureDetector(
onHorizontalDragUpdate: _onHorizontalDragUpdate,
onHorizontalDragEnd: _onHorizontalDragEnd,
child: Transform.translate(
offset: Offset(_animationController.value, 0), // 카드 위치 조정
child: Material(
elevation: 10, // 카드에 그림자 효과 추가
color: Colors.red.shade100, // 카드 색상
child: SizedBox(
width: size.width * 0.8, // 카드 너비
height: size.height * 0.5, // 카드 높이
),
),
),
),
),
],
);
},
),
Material 위젯을 사용하여 구현되며, Transform.translate를 통해 현재 애니메이션 컨트롤러의 값에 따라 수평 위치가 조정됩니다. 사용자가 카드를 드래그하면 해당 방향으로 카드가 이동하며, 드래그가 끝나면 카드가 원래 위치로 돌아옵니다.이 예제는 플러터에서 애니메이션 컨트롤러와 드래그 이벤트를 사용하여 인터랙티브한 UI 컴포넌트를 구현하는 방법을 보여줍니다. 사용자의 입력에 반응하여 동적으로 변화하는 UI는 앱의 사용자 경험을 풍부하게 만듭니다.
GestureDetector 위젯은 플러터에서 다양한 사용자 제스처를 감지하고 처리하는 데 사용됩니다. 이 예제에서는 GestureDetector를 사용하여 사용자가 카드를 좌우로 스와이프하는 동작을 감지합니다. onHorizontalDragUpdate와 onHorizontalDragEnd 콜백을 통해 이러한 제스처에 대한 처리를 구현합니다.
onHorizontalDragUpdateonHorizontalDragUpdate 콜백은 사용자가 카드를 드래그하는 동안, 즉 손가락이 화면 위에서 움직일 때 지속적으로 호출됩니다. DragUpdateDetails 객체를 매개변수로 받습니다. 이 객체는 드래그 동작에 대한 세부 정보, 예를 들어 드래그의 위치 변화(delta)를 제공합니다.details.delta.dx를 사용해 드래그된 수평 거리를 얻고, 이 값을 _animationController의 현재 값에 더합니다. 결과적으로 카드의 수평 위치가 사용자의 드래그 동작에 실시간으로 반응하게 됩니다.onHorizontalDragEndonHorizontalDragEnd 콜백은 사용자가 드래그를 멈추고 손가락을 화면에서 떼었을 때 호출됩니다.DragEndDetails 객체를 매개변수로 받으며, 이 객체는 드래그가 끝날 때의 속도 등의 정보를 제공할 수 있습니다. 예제 코드에서는 이 정보를 직접 사용하지는 않습니다._animationController.animateTo 메서드를 호출하여 카드를 원래 위치(여기서는 중앙, 즉 0)으로 부드럽게 되돌립니다. curve: Curves.bounceOut을 지정하여, 카드가 중앙으로 돌아올 때 바운스 효과를 나타내게 합니다.GestureDetector(
onHorizontalDragUpdate: _onHorizontalDragUpdate, // 사용자가 카드를 좌우로 드래그하는 동안 호출됩니다.
onHorizontalDragEnd: _onHorizontalDragEnd, // 사용자가 드래그를 멈추고 손가락을 떼었을 때 호출됩니다.
child: ...
)
이렇게 GestureDetector를 활용하여 사용자의 드래그 동작을 감지하고, 애니메이션 컨트롤러를 통해 UI에 동적인 변화를 주는 방법은 플러터에서 인터랙티브한 애플리케이션을 구현할 때 매우 유용합니다. 사용자 경험을 향상시키고, 앱에 생동감을 부여할 수 있습니다.