상세 컨텐츠

본문 제목

제스처와 고급 물리 효과를 결합하는 방법

공부/Flutter

by micalcomanie 2025. 1. 3. 21:25

본문

728x90
반응형
SMALL

Flutter는 제스처와 물리 효과를 결합하여 실제와 유사한 상호작용을 구현할 수 있는 강력한 도구를 제공합니다.
이 글에서는 제스처와 물리 효과를 활용한 고급 사용자 인터랙션 기법을 소개합니다.


1. 물리 효과란?

Flutter에서 물리 효과는 사용자가 화면에서 드래그, 스와이프 또는 플링(fling)과 같은 동작을 수행할 때 애니메이션에 물리 법칙(가속도, 마찰 등)을 적용하는 것입니다. 이를 통해 더욱 자연스러운 사용자 경험을 제공합니다.

1.1 주요 도구

  • Physics Simulation: BouncingScrollPhysics, ClampingScrollPhysics 등 다양한 물리 효과 제공.
  • AnimationController와 결합하여 맞춤형 물리 효과 구현.

2. 물리 효과와 제스처 결합: 기본 예제

카드를 드래그하면 물리 효과를 적용하여 자연스럽게 복귀하거나 이동합니다.

예제 코드: 기본 드래그와 복귀 애니메이션

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

class DragWithPhysicsExample extends StatefulWidget {
  @override
  _DragWithPhysicsExampleState createState() => _DragWithPhysicsExampleState();
}

class _DragWithPhysicsExampleState extends State<DragWithPhysicsExample> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _animation;
  Offset _position = Offset.zero;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 300),
    );

    _animation = Tween<Offset>(begin: Offset.zero, end: Offset.zero).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );

    _controller.addListener(() {
      setState(() {
        _position = _animation.value;
      });
    });
  }

  void _onDragUpdate(DragUpdateDetails details) {
    setState(() {
      _position += Offset(details.delta.dx, details.delta.dy);
    });
  }

  void _onDragEnd(DragEndDetails details) {
    final velocity = details.velocity.pixelsPerSecond;
    final magnitude = velocity.distance;
    final direction = velocity / magnitude;

    final distance = Offset(-_position.dx * direction.dx, -_position.dy * direction.dy);

    _animation = Tween<Offset>(begin: _position, end: Offset.zero).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );

    _controller.forward(from: 0.0);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Drag with Physics')),
      body: Center(
        child: GestureDetector(
          onPanUpdate: _onDragUpdate,
          onPanEnd: _onDragEnd,
          child: Transform.translate(
            offset: _position,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.blue,
            ),
          ),
        ),
      ),
    );
  }
}

3. 플링 효과 적용하기

플링(fling)은 사용자가 빠르게 스와이프했을 때 화면에서 위젯이 자연스럽게 이동하거나 멈추는 효과를 구현합니다.

예제 코드: 플링 효과 적용

class FlingWithPhysicsExample extends StatefulWidget {
  @override
  _FlingWithPhysicsExampleState createState() => _FlingWithPhysicsExampleState();
}

class _FlingWithPhysicsExampleState extends State<FlingWithPhysicsExample> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _animation;
  Offset _position = Offset.zero;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500),
    );

    _animation = Tween<Offset>(begin: Offset.zero, end: Offset.zero).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );

    _controller.addListener(() {
      setState(() {
        _position = _animation.value;
      });
    });
  }

  void _onPanEnd(DragEndDetails details) {
    final velocity = details.velocity.pixelsPerSecond;
    final direction = velocity / velocity.distance;

    _animation = Tween<Offset>(
      begin: _position,
      end: Offset(_position.dx + direction.dx * 100, _position.dy + direction.dy * 100),
    ).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );

    _controller.forward(from: 0.0);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Fling with Physics')),
      body: Center(
        child: GestureDetector(
          onPanEnd: _onPanEnd,
          child: Transform.translate(
            offset: _position,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.red,
            ),
          ),
        ),
      ),
    );
  }
}

4. 추가 아이디어

  1. 탄성 효과 추가: 위젯이 경계에 닿을 때 탄성 효과를 추가하여 실제감을 강화.
  2. 물리 기반 게임 요소: 중력 및 충돌 효과를 결합하여 게임 애니메이션 구현.
  3. 제스처와 마찰 효과 결합: 사용자의 드래그 속도에 따라 애니메이션 종료 지점을 동적으로 설정.

5. 결론

Flutter에서 제스처와 물리 효과를 결합하면 실제와 유사한 사용자 경험을 제공할 수 있습니다. 이 글에서 소개한 예제를 바탕으로 다양한 사용자 인터랙션을 구현해 보세요. 다음 글에서는 물리 효과를 활용한 고급 게임 애니메이션을 다룰 예정입니다.


참고 자료

728x90
반응형
LIST

관련글 더보기