Flutter绘制-11-旋转小人儿造成的视觉错效

查看目录–>

旋转小人

几年前在某一个地方看到过这个效果:

rotategirl.gif

今天又偶然看到,最神奇的地方在于:

  • 在盯着gif看的某一瞬间,旋转方向突然就逆向旋转了
  • 在旋转方向发送变化的同时,左腿变右腿,左手变右手

所以我在想,是不是看的时间久了,就可以任我切换旋转方向,于是盯了半个小时,结果是没成功,收获是方向切换的频次提高了。

我知道它肯定是向着一个方向旋转的,但到现在我依然不能理解为什么会是这样,困惑中。

那,是否能用canvas实现一个呢?

带来的困惑

苦苦思索:

  • 这个人影是立体的,前面《太空人》 曾用到立体投影,这里估计要处理。
  • 我该怎么画这个人儿呢? 用长方体拼凑怕是不合适吧。。。
  • 这人儿的手臂还是伸开的。
  • 在旋转的同时,看脚丫子,好像高低起伏。
第一版效果
  • 先画左右腿
  • 上下起伏

v5.gif

差距,有点远。。。

代码如下:

import 'dart:ui';
import 'dart:math';

import 'package:flutter/material.dart';

// 旋转小人儿
class RotateGirlMainPage extends StatefulWidget {
  @override
  _RotateGirlMainPageState createState() => _RotateGirlMainPageState();
}

class _RotateGirlMainPageState extends State<RotateGirlMainPage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 1500));
    _controller.repeat();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("旋转小人儿"),
        centerTitle: true,
      ),
      body: CustomPaint(
        size: MediaQuery.of(context).size,
        painter: _MyPainter(_controller),
      ),
    );
  }
}

class _MyPainter extends CustomPainter {
  AnimationController _controller;

  _MyPainter(this._controller) : super(repaint: _controller);

  @override
  void paint(Canvas canvas, Size size) {
    translateToCenter(canvas, size);
    double dy = 10 * sin(pi * 2 * _controller.value);
    Path path = new Path()
      ..moveTo(30 * sin(pi * 2 * _controller.value), dy)
      ..lineTo(100 * sin(pi * 2 * _controller.value), 220 + dy)
      ..moveTo(0, dy)
      ..lineTo(0, 200 + dy)
    ..lineTo(300, 200 + dy)
      ..lineTo(-300, 200 + dy);
    Paint paint = new Paint()
      ..color = Colors.black
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2
      ..isAntiAlias = true;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
  }
}

复制代码
第二版效果

又仔细观察好像是斜对角的线,即

  • 线的上端点,移动方向,左->右
  • 线的下端点,移动方向,右->左
  • 围绕着y轴旋转,y的坐标上下有波动,x的值通过radiussin(pi2*_controller.value)获取。(_controller是设定的一个动画,value取值范围在0-1,radius是旋转半径)

再看下效果:

v6.gif

是不是有那个味儿了。。。

最后,代码如下:

import 'dart:ui';
import 'dart:math';

import 'package:flutter/material.dart';

// 旋转小人儿
class RotateGirlMainPage extends StatefulWidget {
  @override
  _RotateGirlMainPageState createState() => _RotateGirlMainPageState();
}

class _RotateGirlMainPageState extends State<RotateGirlMainPage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 1500));
    _controller.repeat();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("旋转小人儿"),
        centerTitle: true,
      ),
      body: CustomPaint(
        size: MediaQuery.of(context).size,
        painter: _MyPainter(_controller),
      ),
    );
  }
}

class _MyPainter extends CustomPainter {
  AnimationController _controller;

  _MyPainter(this._controller) : super(repaint: _controller);

  @override
  void paint(Canvas canvas, Size size) {
    translateToCenter(canvas, size);
    double dy = 10 * sin(pi * 2 * _controller.value);
    Path path = new Path()
      ..moveTo(30 * -sin(pi * 2 * _controller.value), -100+dy)
      ..lineTo(100 * sin(pi * 2 * _controller.value), 220 + dy);
    Paint paint = new Paint()
      ..color = Colors.black
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2
      ..isAntiAlias = true;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
    Paint paint = new Paint()
      ..color = Colors.black12
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1
      ..isAntiAlias = true;
    canvas.drawLine(Offset(-300,0), Offset(300,0), paint);
    canvas.drawLine(Offset(0,300), Offset(0,-300), paint);
  }
}

复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享