import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tracking Sample',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark().copyWith(
        primaryColor: Color(0xFF0D2336),
        scaffoldBackgroundColor: Color(0xFF12314A),
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Percentage calculation'),
      ),
      body: const TrackingSample(),
    );
  }
}

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

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

class _TrackingSampleState extends State<TrackingSample> {
  // デバッグ用
  String _position = 'Try the drag.';

  // GlobalKeyを用意
  final _globalKey = GlobalKey();

// Widgetのサイズ格納用の変数
  Size _widgetSize;

  @override
  void initState() {
    super.initState();

    // GlobalKeyのContextからSizeを取得
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _widgetSize = _globalKey.currentContext.size;
    });
  }

  // ドラッグ位置の割合を計算する
  Offset _calcPercentage(Offset dragPosition, Size widgetSize) {
    // x軸の割合
    final x = dragPosition.dx / widgetSize.width;
    // y軸の割合
    final y = dragPosition.dy / widgetSize.height;

    return Offset(x, y);
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // アニメーション表示用Widget
        Center(
          child: SizedBox(
            height: 120,
            width: 120,
            // 後ほどアニメーションに置き換える
            child: Placeholder(),
          ),
        ),
        // デバッグ用
        Center(child: Text(_position)),
        // ドラッグ位置取得用Widget
        GestureDetector(
          onPanDown: (detail) {
            // 初回画面タップ時に一度だけ呼び出される
            // トラッキングに使用

            final percentage = _calcPercentage(
              detail.localPosition,
              _widgetSize,
            );

            setState(
              () => _position = 'onPanDown: $percentage',
            );
          },
          onPanUpdate: (detail) {
            // ドラッグ位置が変化するたびに呼び出される
            // トラッキングに使用

            final percentage = _calcPercentage(
              detail.localPosition,
              _widgetSize,
            );

            setState(
              () => _position = 'onPanUpdate: $percentage',
            );
          },
          onPanEnd: (detail) {
            // ドラッグ終了時に呼び出される
            // トラッキングを終了し、アニメーションの初期化に使用
            setState(
              () => _position = 'onPanEnd',
            );
          },
          child: Container(
            key: _globalKey,
            color: Colors.transparent,
          ),
        ),
      ],
    );
  }
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.