返回

揭开贝塞尔的动感之谜:Flutter 实战波浪

Android

在视觉表现的世界里,动效宛若感官上的魔术师,用看似欺骗的手法牵动我们的心灵。贝塞尔曲线,作为动效界的点睛之笔,让线条动感十足,成为设计师和程序员手中不可或缺的利器。

本篇 Flutter 实战教程,我们以波浪绘制为例,带你深入贝塞尔的动感奥秘,用代码和灵感点燃你的创作激情。

绘制单体波

一切动效都始于基本元素。单体波,顾名思义,是由单个贝塞尔曲线组成的波浪。绘制它,就像用线勾勒出波浪的轮廓。

import 'package:flutter/material.dart';

class SingleWave extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 5;

    final path = Path();
    path.moveTo(0, size.height / 2);
    path.quadraticBezierTo(size.width / 4, size.height, size.width / 2, size.height / 2);
    path.quadraticBezierTo(3 * size.width / 4, 0, size.width, size.height / 2);

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

二阶贝塞尔的相对绘制

单体波只是一幅静止的画,要让它动起来,就需要二阶贝塞尔曲线的相对绘制。它将多个贝塞尔曲线巧妙地连接起来,形成连续的波浪运动。

import 'package:flutter/material.dart';

class MultiWaves extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 5;

    double waveHeight = size.height / 4;
    double waveWidth = size.width;
    double offset = 0;

    for (int i = 0; i < 2; i++) {
      final path = Path();
      path.moveTo(0 - offset, size.height / 2 + waveHeight * i);
      path.quadraticBezierTo(waveWidth / 4 - offset, size.height - waveHeight * i, waveWidth / 2 - offset, size.height / 2 + waveHeight * i);
      path.quadraticBezierTo(3 * waveWidth / 4 - offset, waveHeight * i, waveWidth - offset, size.height / 2 + waveHeight * i);
      canvas.drawPath(path, paint);
      offset += waveWidth / 2;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

实现波动的原理

波浪的动感来自周期性的纵向位移。通过改变贝塞尔曲线的控制点,我们可以让波浪上下浮动。

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

class AnimatedWaves extends CustomPainter {
  double waveHeight = 50;
  double offset = 0;

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 5;

    for (int i = 0; i < 2; i++) {
      final path = Path();
      path.moveTo(0 - offset, size.height / 2 + sin(offset / 20) * waveHeight * i);
      path.quadraticBezierTo(size.width / 4 - offset, size.height - sin(offset / 20) * waveHeight * i, size.width / 2 - offset, size.height / 2 + sin(offset / 20) * waveHeight * i);
      path.quadraticBezierTo(3 * size.width / 4 - offset, sin(offset / 20) * waveHeight * i, size.width - offset, size.height / 2 + sin(offset / 20) * waveHeight * i);
      canvas.drawPath(path, paint);
      offset += size.width / 2;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

总结

贝塞尔曲线,作为 UI 动效的秘密武器,赋予线条以生命。通过掌握它的基本原理和实现技巧,你可以创造出令人惊叹的波浪动画和其他动效效果。让你的应用动感十足,引领用户进入一个更加生动、交互的数字世界。

实践出真知,不妨亲自动手尝试一下,用贝塞尔曲线勾勒出你心中的波浪吧!