Flutter 一次性全屏 lerp 出一个 rect 的渐变色 Shader

36 min read

这里是一个样例代码,可以实现一次性全屏 lerp 出一个 rect 的渐变色 Shader:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  AnimationController _controller;
  Animation<Color> _colorTween;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..forward();

    _colorTween = ColorTween(
      begin: Colors.blue,
      end: Colors.red,
    ).animate(_controller);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: AnimatedBuilder(
        animation: _colorTween,
        builder: (BuildContext context, Widget child) {
          return ShaderMask(
            shaderCallback: (Rect bounds) {
              return LinearGradient(
                colors: [_colorTween.value.withOpacity(0.3), _colorTween.value.withOpacity(0.6)],
                tileMode: TileMode.mirror,
              ).createShader(bounds);
            },
            child: DecoratedBox(
              decoration: BoxDecoration(
                color: Colors.white,
              ),
              child: SizedBox.expand(),
            ),
          );
        },
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

在这个例子中,我们创建了一个 AnimationController 和一个 ColorTween,并把它们传给 AnimatedBuilder。在 AnimatedBuilder 中,我们使用了 ShaderMask 来创建一个 Shader,这个 Shader 是使用 LinearGradient 渐变生成的。最后,我们把 ShaderMask 作为背景的 DecoratedBox 放入了 SizedBox.expand() 中。

在运行时,我们启动了 AnimationController 并且让它向前运行。这将自动更新 ColorTween 中的插值,并且触发动画重绘。最终,我们将得到一个渐变色的背景作为屏幕的全屏背景。