본문 바로가기
프로그래밍/Flutter & Dart

Flutter 터치로 사진 확대/축소 시키기

by 어느덧중반 2020. 8. 27.
반응형

Flutter 터치로 사진 확대/축소 시키기

이번에는 화면 터치를 통해 사진/그림을 확대/축소 시키는 방법에 대해 알아보겠다.

Animation 위젯을 응용하여 사용할 것이고 관련 내용을 통해

progress bar 등으로의 활용도 가능하다.

사용법은 매우매우 간단하다.

 

동작 원리

1. Animation, AnimationController 생성

2. 특정 행동(터치)을 감지하여 행동 발생시 설정한 애니메이션이 동작하도록 수행

 


 

1. Animation, AnimationController 생성

  Animation _animation;
  AnimationController _animationController;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _animationController = new AnimationController(vsync: this, duration: Duration(milliseconds: 100));
    _animation = Tween(begin: 1.0, end: 2.0).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut))..addListener(() {
      setState(() {

      });
    });
  }

 

2. 특정 행동(터치)을 감지하여 행동 발생시 설정한 애니메이션이 동작하도록 수행

GestureDetector(
  onTap: () {
    if(_animationController.isCompleted) {
      _animationController.reverse();
    } else {
      _animationController.forward();
    }
  },
  child: Container(
    child: Transform(
      alignment: Alignment.center,
      transform: Matrix4.diagonal3(Vector3(_animation.value, _animation.value, _animation.value)),
      child: Image.network('https://images.unsplash.com/photo-1598294203238-ed1ac7484b8b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=676&q=80')
    ),
    width: MediaQuery.of(context).size.width * 0.5,
    height: MediaQuery.of(context).size.height * 0.5,
  ),
),

 

3. 결과 화면

사진을 터치하면 2배로 확대된다. (Column으로 텍스트를 놓고 텍스트 위에 그려지는지 테스트해보니 아래 텍스트들은 사진의 위에 동작하는데 왜 그런지 아직 원인을 찾지 못했다.

 

4. 전체 소스

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart';
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: DoubleTapZoom(),
    );
  }
}

class DoubleTapZoom extends StatefulWidget {
  const DoubleTapZoom({
    Key key,
  }) : super(key: key);

  @override
  _DoubleTapZoomState createState() => _DoubleTapZoomState();
}

class _DoubleTapZoomState extends State<DoubleTapZoom> with SingleTickerProviderStateMixin {
  Animation _animation;
  AnimationController _animationController;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _animationController = new AnimationController(vsync: this, duration: Duration(milliseconds: 100));
    _animation = Tween(begin: 1.0, end: 2.0).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut))..addListener(() {
      setState(() {

      });
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('1111', style: TextStyle(fontSize: 20)),
            Text('2222', style: TextStyle(fontSize: 20)),
            Text('3333', style: TextStyle(fontSize: 20)),
            Text('4444', style: TextStyle(fontSize: 20)),
            Text('5555', style: TextStyle(fontSize: 20)),
            GestureDetector(
              onTap: () {
                if(_animationController.isCompleted) {
                  _animationController.reverse();
                } else {
                  _animationController.forward();
                }
              },
              child: Container(
                child: Transform(
                  alignment: Alignment.center,
                  transform: Matrix4.diagonal3(Vector3(_animation.value, _animation.value, _animation.value)),
                  child: Image.network('https://images.unsplash.com/photo-1598294203238-ed1ac7484b8b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=676&q=80')
                ),
                width: MediaQuery.of(context).size.width * 0.5,
                height: MediaQuery.of(context).size.height * 0.5,
              ),
            ),
            Text('6666', style: TextStyle(fontSize: 20)),
            Text('7777', style: TextStyle(fontSize: 20)),
            Text('8888', style: TextStyle(fontSize: 20)),
          ],
        ),
      )
    );
  }
}
반응형

댓글