Flutter实现截屏组件封装

先看效果:

在这里插入图片描述

  1. 用到的屏幕截屏插件(插件的用法大家参考该插件文档):
  screenshot: ^0.2.0
  1. 封装思路

  2. 手势如何操作执行截屏呢? -> GestureDetector

  3. 多子叶布局用什么?考虑应该覆盖,选用了Stack

  4. 截图显示的位置应该可以显示和隐藏,且将其放到Stack最后一层 -> Offstage

  5. 最后就是截屏显示后的动画

布局代码

@override
  Widget build(BuildContext context) {
    return GestureDetector(
      onLongPress: () {
        _screenShot();
      },
      child: Screenshot(
        controller: screenshotController,
        child: Container(
          width: double.infinity,
          height: double.infinity,
          child: Stack(
            children: [
              widget.child,
              Positioned(
                bottom: animationPadding.value,
                right: 20,
                child: Offstage(
                  offstage: isHideScreenArea,
                  child: Container(
                    decoration: BoxDecoration(
                        color: Colors.blueGrey, border: Border.all(width: 1)),
                    width: 120,
                    height: 200,
                    child: imageFile == null
                        ? null
                        : Image.file(imageFile, fit: BoxFit.fill),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

动画代码

动画想要实现跳动的感觉,用到补间对象tween和时间曲线函数对象Curve.
原理 : 根据时间曲线函数我们拿到时间内不同的值,然后给显示图片的组件设置padding值,从而达到移动的效果.

Cure动画效果可以参考这篇博客:
https://blog.csdn.net/qq_17766199/article/details/95632571

  _initAnim() {
    animationController = AnimationController(
        value: 40, duration: Duration(seconds: 2), vsync: this)
      ..addListener(() {
        setState(() {});
      });

    curve =
        CurvedAnimation(parent: animationController, curve: Curves.bounceOut);
    animationPadding = Tween(begin: 40.0, end: 10.0).animate(curve);
  }

代码中设置了40 - 10的区间变化,也就是padding值会随着时间函数在这个范围内变化,达到移动效果.

注意:动画开始前最好执行reset

	animationController.reset();
    animationController.forward();

最后附上组件所有代码


class ScreenshotWidget extends StatefulWidget {
  final Widget child;
  final Duration duration;

  ScreenshotWidget({Key key, this.child, this.duration});

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

class _ScreenshotWidgetState extends State<ScreenshotWidget>
    with TickerProviderStateMixin {
  ScreenshotController screenshotController = ScreenshotController();
  bool isHideScreenArea = true;
  File imageFile;
  Duration duration;

  AnimationController animationController;
  Animation animationPadding;
  CurvedAnimation curve;

  _screenShot() {
    if (!isHideScreenArea) {
      return;
    }

    screenshotController.capture().then((File image) {
      setState(() {
        imageFile = image;
        isHideScreenArea = false;
        _timerHideScreenWidget();
      });

      print(imageFile.path);

      animationController.reset();
      animationController.forward();
    }).catchError((onError) {
      print(onError);
    });
  }

  _timerHideScreenWidget() {
    Timer(duration, () {
      setState(() {
        isHideScreenArea = true;
        animationController.stop();
      });
    });
  }

  _initAnim() {
    animationController = AnimationController(
        value: 40, duration: Duration(seconds: 2), vsync: this)
      ..addListener(() {
        setState(() {});
      });

    curve =
        CurvedAnimation(parent: animationController, curve: Curves.bounceOut);
    animationPadding = Tween(begin: 40.0, end: 10.0).animate(curve);
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    duration = widget.duration != null ? widget.duration : Duration(seconds: 3);
    _initAnim();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    animationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onLongPress: () {
        _screenShot();
      },
      child: Screenshot(
        controller: screenshotController,
        child: Container(
          width: double.infinity,
          height: double.infinity,
          child: Stack(
            children: [
              widget.child,
              Positioned(
                bottom: animationPadding.value,
                right: 20,
                child: Offstage(
                  offstage: isHideScreenArea,
                  child: Container(
                    decoration: BoxDecoration(
                        color: Colors.blueGrey, border: Border.all(width: 1)),
                    width: 120,
                    height: 200,
                    child: imageFile == null
                        ? null
                        : Image.file(imageFile, fit: BoxFit.fill),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值