Flutter 手指放大 平移 旋转 Widget

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double _scale = 1.0;
  double _baseScale = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          onScaleStart: (ScaleStartDetails scaleStartDetails) {
            _baseScale = _scale;
          },
          onScaleUpdate: (ScaleUpdateDetails scaleUpdateDetails) {
            double _ns = _baseScale * scaleUpdateDetails.scale;
            printf('[scale]: %f %f', [scaleUpdateDetails.scale, _ns]);
            if (_ns <= 1.0) return;
            setState(() {
              _scale = _ns;
            });
          },
          child: Transform.scale(
            scale: _scale,
            child: Container(
              width: 300,
              height: 300,
              color: Colors.red,
            ),
          ),
        ),
      ),
    );
  }
}

移动它

class _HomePageState extends State<HomePage> {
  double _scale = 1.0;
  double _baseScale = 0;
  Offset _to = Offset(0, 0);
  Offset _baseTo = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          onDoubleTap: () {
            setState(() {
              _scale = 1.0;
              _to = Offset(0, 0);
              _baseTo = Offset(0, 0);
            });
          },
          onScaleStart: (ScaleStartDetails d) {
            _baseScale = _scale;
            _baseTo = d.localFocalPoint;
          },
          onScaleUpdate: (ScaleUpdateDetails d) {
            double _ns = _baseScale * d.scale;
            if (_ns > 1.0) {
              setState(() {
                _scale = _ns;
              });
            }

            setState(() {
              _to = d.localFocalPoint;
            });
          },
          child: Transform(
            transform: Matrix4.identity()
              ..scale(_scale, _scale, 1.0)
              ..translate(_to.dx - _baseTo.dx, _to.dy - _baseTo.dy),
            alignment: Alignment.center,
            child: Container(
              width: 200,
              height: 200,
              color: Colors.red,
            ),
          ),
        ),
      ),
    );
  }
}

简单的碰撞检测

class _HomePageState extends State<HomePage> {
  double _scale = 1.0;
  double _baseScale = 0;
  Offset _to = Offset(0, 0);
  Offset _baseTo = Offset(0, 0);
  GlobalKey stickyKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    Size window = MediaQuery.of(context).size;
    return Scaffold(
      body: Center(
        child: GestureDetector(
          onDoubleTap: () {
            setState(() {
              _scale = 1.0;
              _to = Offset(0, 0);
              _baseTo = Offset(0, 0);
            });
          },
          onScaleStart: (ScaleStartDetails d) {
            _baseScale = _scale;
            _baseTo = d.localFocalPoint;
          },
          onScaleUpdate: (ScaleUpdateDetails d) {
            double _ns = _baseScale * d.scale;
            if (_ns > 0.8) {
              setState(() {
                _scale = _ns;
              });
            }

            Offset lfp = d.localFocalPoint;
            var _box = stickyKey.currentContext.findRenderObject() as RenderBox;
            Offset _pos = _box.localToGlobal(Offset.zero);
            var _boxsize = _box.size * _ns;

            if (_boxsize.width <= window.width) {
              if (!(_pos.dx <= 0 && lfp.dx < _to.dx ||
                  _pos.dx + _boxsize.width >= window.width && lfp.dx > _to.dx ||
                  _pos.dy <= 0 && lfp.dy < _to.dy ||
                  _pos.dy + _boxsize.height >= window.height &&
                      lfp.dy > _to.dy)) {
                setState(() {
                  _to = d.localFocalPoint;
                });
              }
            } else {
              if (!(_pos.dx >= 0 && lfp.dx > _to.dx ||
                  _pos.dx + _boxsize.width <= window.width && lfp.dx < _to.dx ||
                  _pos.dy >= 0 && lfp.dy > _to.dy ||
                  _pos.dy + _boxsize.width <= window.height &&
                      lfp.dy < _to.dy)) {
                setState(() {
                  _to = d.localFocalPoint;
                });
              }
            }
          },
          child: Transform(
            transform: Matrix4.identity()
              ..scale(_scale, _scale)
              ..translate(_to.dx - _baseTo.dx, _to.dy - _baseTo.dy),
            alignment: Alignment.center,
            child: Image.network(
              'https://i.loli.net/2020/01/14/w1dcNtf4SECG6yX.jpg',
              key: stickyKey,
            ),
          ),
        ),
      ),
    );
  }
}

Z轴旋转

class _HomePageState extends State<HomePage> {
  double _rotation = 0.0;
  double _lastRotation = 0.0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          onScaleUpdate: (ScaleUpdateDetails d) {
            printf('[rotation] %f', [d.rotation]);
            setState(() {
              _rotation = d.rotation;
            });
          },
          onScaleEnd: (_) {
            _lastRotation += _rotation;
          },
          child: Transform(
            transform: Matrix4.identity()..rotateZ(_lastRotation + _rotation),
            alignment: Alignment.center,
            child: Image.network(
              'https://i.loli.net/2020/01/14/w1dcNtf4SECG6yX.jpg',
            ),
          ),
        ),
      ),
    );
  }
}

保存上一次的移动偏移

class _HomePageState extends State<HomePage> {
  Offset pos = Offset(0, 0);
  Offset basePos = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          onScaleStart: (ScaleStartDetails d) {
            basePos = d.localFocalPoint - pos;
          },
          onScaleUpdate: (ScaleUpdateDetails d) {
            setState(() {
              pos = d.localFocalPoint - basePos;
            });
          },
          child: Transform(
            transform: Matrix4.identity()..translate(pos.dx, pos.dy),
            alignment: Alignment.center,
            child: Container(
              width: 200,
              height: 200,
              color: Colors.red,
            ),
          ),
        ),
      ),
    );
  }
}
posted @ 2020-10-04 12:04  Ajanuw  阅读(280)  评论(0编辑  收藏  举报