Flutter 学习9:Positioned、Transform等控件使用以及手势控制

Categories: flutter
  1. Flutter 学习1:开发环境、开发工具、初始化一个项目
  2. Flutter 学习2:从main.dart文件说起
  3. Flutter 学习3:转场、导航
  4. Flutter 学习4:集成到原有的项目中
  5. Flutter 学习5:开发Dart包和插件包
  6. Flutter 学习6:绘制动画
  7. Flutter 学习7:Dart语言基础
  8. Flutter 学习8:BottomSheet
  9. Flutter 学习9:Positioned、Transform等控件使用以及手势控制
  10. Flutter 学习10:NestedScrollView、SliverAppBar、TabBar

上次说了一个BottomSheet的控件,非常实用的一个弹出控件。Flutter提供了很多有意思的控件,好好利用这些控件就能搭建出任何你想要的效果。

Positioned

看这个名字就大概能了解到这个是定位用的,但是它不是随便哪里都能定位的,它必须配合Stack控件用。它通过 [left], [right], [width],[top], [bottom], [height] 这六个属性将Stack的某个子控件定位到特定的位置上。

    Stack(
        children: <Widget>[
          Positioned(
            top: 150,
            left: 30,
            child: Container(
              color: Colors.red,
              width: 200,
              height: 200,
            ),
          ),
          Positioned(
            left: 40,
            top: 200,
            width: 50,
            height: 50,
            child: Container(
              color: Colors.teal,
            ),
          )
        ],
      )

Screen Shot 2019-01-31 at 14.14.28-w417

Transform

Transform已经有写好的三种用法分别是scale、rotate、translate 。用起来非常方便,一个个来看看怎么用

Transform.scale

它就一个参数scale。在上面代码的基础上,我们把那个红色方块用Transform.scale包起来就可以放大缩小了。

var myScale = 1.0;
void _scale(bool plus) {
    if(plus) {
      myScale += 0.1;
    }else {
      myScale -= 0.1;
    }
    setState(() {});
  }
  ...
    Stack(
        children: <Widget>[
          Positioned(
            top: 150,
            left: 30,
            child: Transform.scale(
              scale: myScale,
              child: Container(
              color: Colors.red,
              width: 200,
              height: 200,
            ),
            ),
          ),
          Positioned(
            left: 40,
            top: 200,
            width: 50,
            height: 50,
            child: Container(
              color: Colors.teal,
            ),
          ),
          Positioned(
            bottom: 20,
            right: 40,
            child: Container(
              width: 200,
              height: 64,
              child: Row(
                children: <Widget>[
                  FlatButton(
                    child: Icon(Icons.add_circle),
                    onPressed: () => _scale(true),
                  ),
                  FlatButton(
                    onPressed:  () => _scale(false),
                    child: Icon(Icons.remove_circle),
                  )
                ],
              ),
            ),
          )
        ],
      )

Transform.2019-01-31 15_16_14

Transform.rotate

它是用来旋转一定的角度用的,也只有一个参数angle。

    Positioned(
            left: 40,
            top: 200,
            width: 50,
            height: 50,
            child: Transform.rotate(
              angle: math.pi / 2, //90度
              child: Container(
                color: Colors.teal,
                child: Center(child: Text('中国', style: TextStyle(color: Colors.white),)),
              ),
            ),
          )

Screen Shot 2019-01-31 at 15.38.26-w417

Transform.translate

最后一个是变化位置,有点类似Positioned的,就是x轴y轴的移动。

    Positioned(
            left: 40,
            top: 200,
            width: 50,
            height: 50,
            child: Transform.translate(
              offset: Offset(130, 0),//x轴方向移动130
              child: Container(
                color: Colors.teal,
                child: Center(child: Text('中国', style: TextStyle(color: Colors.white),)),
              ),
            ),
          )

Screen Shot 2019-01-31 at 15.51.17-w417

手势控制

做移动开发的看到这里其实很容易就能想到我们经常用到的图片查看器,图片可以用双指放大缩小,单指移动位置。 那用上面两个控件结合手势控制的GestureDetector是否就可以实现图片查看器的功能了呢,试试!

网上随便找了一个小姐姐的图片,我随便找你们随便看!放大缩小移动的效果如下:

ScreenRecording_01-31-2019 17-30-23.2019-01-31 17_33_36

下面是实现的代码:

class _MyHomePageState extends State<MyHomePage> {
  var myScale = 1.0;
  var myPosition = Offset(0.0, 0.0);
  var mySize = Size(0.0, 0.0);
  var lastPosition = Offset(0.0, 0.0);
  var startMovePosition = Offset(0.0, 0.0);
  var edgePosition = Offset(0.0, 0.0);
  int numPointers = 0;
  var lastScale = 1.0; // 多次放大缩小的时候保存上一次的结果。
  var scaling = false;

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    mySize = size * myScale;
    final dx = -(mySize.width - size.width);
    final dy = -(mySize.height - size.height);
    edgePosition = Offset(dx, dy);
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Listener(
            onPointerDown: (_) => numPointers++,
            onPointerUp: (_) => numPointers--,
            child: GestureDetector(
              child: Stack(
                children: <Widget>[
                  Positioned(
                    top: myPosition.dy,
                    left: myPosition.dx,
                    width: mySize.width,
                    height: mySize.height,
                    child: Transform.scale(
                      scale: myScale,
                      child: Image.network(
                        'http://img.muliba.net/post/timg.jpeg',
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
                ],
              ),
              onScaleStart: _scaleStart,
              onScaleEnd: _scaleEnd,
              onScaleUpdate: _scaleUpdate,
            )));
  }

  void _scaleStart(ScaleStartDetails detail) {
    if (numPointers == 1 && !scaling) {
    lastPosition = myPosition; //标记下位置
    startMovePosition = detail.focalPoint;
    }
    if (numPointers == 2) {
      if (!scaling) {
        scaling = true;
      }
    }
  }

  void _scaleUpdate(ScaleUpdateDetails detail) {
    if (numPointers == 1 && !scaling) {
    final distance = detail.focalPoint - startMovePosition; // 移动距离
    final newPosition = lastPosition + distance; //移动
    var x = newPosition.dx;
    if (x > 0) {
      x = 0.0;
    }
    if (x < edgePosition.dx) {
      x = edgePosition.dx;
    }
    var y = newPosition.dy;
    if (y > 0) {
      y = 0.0;
    } else if (y < edgePosition.dy) {
      y = edgePosition.dy;
    }
    myPosition = Offset(x, y); //移动
    setState(() {});
    }
    if (numPointers == 2) {
      if (scaling) {
        var newScale = lastScale * detail.scale;
        if (newScale < 1.0) {
          newScale = 1.0;
        } else if (newScale > 5.0) {
          newScale = 5.0;
        }
        myScale = newScale;
        // 计算大小
        setState(() {});
      }
    }
  }

  void _scaleEnd(ScaleEndDetails detail) {
    if (scaling) {
      lastScale = myScale;
      scaling = false;
    }
  }
}

是不是很方便实用,Flutter确实让开发越来越简单了!👍