• Flutter 一个气泡动画背景的登录页面


    import 'dart:math';
    import 'dart:ui';
    
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MaterialApp(
        home: DemoLoginUI(),
      ));
    }
    
    class DemoLoginUI extends StatefulWidget {
      @override
      _DemoLoginUIState createState() => _DemoLoginUIState();
    }
    
    //全局定义获取颜色的方法
    Color getRandomWhiteColor(Random random) {
      int a = random.nextInt(200);
      return Color.fromARGB(a, 255, 255, 255);
    }
    
    class _DemoLoginUIState extends State<DemoLoginUI>
        with TickerProviderStateMixin {
      List<BobbleBean> _list = [];
    
      Random _random = new Random(DateTime.now().microsecondsSinceEpoch);
    
      // 运动速度控制
      double _maxSpeed = 2.0;
    
      // 设置最大半径
      double _maxRadius = 100;
    
      // 设置最大角度
      double _maxTheta = 2 * pi;
    
      AnimationController _animationController;
    
      AnimationController _fadeAnimationController;
    
      @override
      void initState() {
        super.initState();
    
        for (int i = 0; i < 20; i++) {
          BobbleBean bean = new BobbleBean();
    
          bean.color = getRandomWhiteColor(_random);
          bean.position = Offset(-1, -1);
    
          bean.speed = _random.nextDouble() * _maxSpeed;
    
          bean.radius = _random.nextDouble() * _maxRadius;
          bean.theta = _random.nextDouble() * _maxTheta;
    
          _list.add(bean);
        }
        //创建动画控制器 1秒
        _animationController = new AnimationController(
            vsync: this, duration: Duration(milliseconds: 1000));
        // 执行刷新监听
        _animationController.addListener(() {
          setState(() {});
        });
        // 重复执行
        // _animationController.repeat();
    
        _fadeAnimationController = new AnimationController(
            vsync: this, duration: Duration(milliseconds: 1800));
        _fadeAnimationController.forward();
        _fadeAnimationController.addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            _animationController.repeat();
          }
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.white,
          body: Container(
             double.infinity,
            height: double.infinity,
            child: Stack(
              children: [
                // 第一部分 渐变背景
                buildBackground(),
                // 第二部分 气泡
                buildBobbleWeight(context),
                //  第三部分 高斯模糊
                buildBlurWeight(),
                //  第四部分 顶部的稳步
                buildTopText(),
                //  第五部分 输入区域
                buildBottomColumn()
              ],
            ),
          ),
        );
      }
    
      // 第一部分 渐变背景
      buildBackground() {
        return Container(
          decoration: BoxDecoration(
              gradient: LinearGradient(
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight,
                  colors: [
                Colors.lightBlueAccent.withOpacity(0.3),
                Colors.lightBlue.withOpacity(0.3),
                Colors.blue.withOpacity(0.3),
              ])),
        );
      }
    
      buildBobbleWeight(BuildContext context) {
        //画板
        return CustomPaint(
          size: MediaQuery.of(context).size,
          painter: CustomMyPainter(list: _list, random: _random),
        );
      }
    
      buildBlurWeight() {
        return BackdropFilter(
          filter: ImageFilter.blur(sigmaX: 0.3, sigmaY: 0.3),
          child: Container(
            color: Colors.white.withOpacity(0.1),
          ),
        );
      }
    
      buildTopText() {
        return Positioned(
          left: 0,
          right: 0,
          top: 160,
          child: Text(
            'Hello World',
            style: TextStyle(fontSize: 44, color: Colors.deepPurple),
            textAlign: TextAlign.center,
          ),
        );
      }
    
      buildBottomColumn() {
        return Positioned(
          left: 44,
          right: 44,
          bottom: 84,
          child: FadeTransition(
            opacity: _fadeAnimationController,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                //  自定义文本输入框
                TextFieldWidget(
                  obscureText: false,
                  labelText: "账号",
                  prefixIconData: Icons.phone_android_outlined,
                ),
                SizedBox(
                  height: 14,
                ),
                TextFieldWidget(
                  obscureText: true,
                  labelText: "密码",
                  prefixIconData: Icons.lock_outline,
                  suffixIconData: Icons.visibility,
                ),
                SizedBox(
                  height: 14,
                ),
                Container(
                  alignment: Alignment.centerRight,
                  child: Text(
                    '忘记密码',
                    textAlign: TextAlign.end,
                    style: TextStyle(fontSize: 14, color: Colors.blue),
                  ),
                ),
    
                SizedBox(
                  height: 14,
                ),
    
                Container(
                  height: 42,
                   double.infinity,
                  child: ElevatedButton(
                    onPressed: () {},
                    child: Text('登录'),
                  ),
                ),
    
                SizedBox(
                  height: 12,
                ),
    
                Container(
                  height: 42,
                   double.infinity,
                  child: ElevatedButton(
                    onPressed: () {},
                    child: Text('注册'),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class TextFieldWidget extends StatelessWidget {
      Function(String value) onChanged;
      bool obscureText;
      String labelText;
      IconData prefixIconData;
      IconData suffixIconData;
    
      TextFieldWidget(
          {this.onChanged,
          this.obscureText,
          this.labelText,
          this.prefixIconData,
          this.suffixIconData});
    
      @override
      Widget build(BuildContext context) {
        return TextField(
          onChanged: onChanged,
          obscureText: obscureText,
          style: TextStyle(color: Colors.blue, fontSize: 14.0),
          //  输入框可用时边框配置
          decoration: InputDecoration(
            filled: true,
            labelText: labelText,
            // 去掉默认的下划线
            enabledBorder: UnderlineInputBorder(borderSide: BorderSide.none),
            // 获取输入焦点时的边框样式
            focusedBorder: OutlineInputBorder(
                borderRadius: BorderRadius.all(Radius.circular(10)),
                borderSide: BorderSide(color: Colors.blue)),
            prefixIcon: Icon(
              prefixIconData,
              size: 18,
              color: Colors.blue,
            ),
            suffixIcon: Icon(
              suffixIconData,
              size: 18,
              color: Colors.blue,
            ),
          ),
        );
      }
    }
    
    class CustomMyPainter extends CustomPainter {
      List<BobbleBean> list;
    
      Random random;
    
      Paint _paint = new Paint()..isAntiAlias = true;
    
      CustomMyPainter({this.list, this.random});
    
      @override
      void paint(Canvas canvas, Size size) {
        list.forEach((element) {
          Offset newCenterOffset = calculateXY(element.speed, element.theta);
    
          double dx = newCenterOffset.dx + element.position.dx;
          double dy = newCenterOffset.dx + element.position.dy;
    
          if (dx < 0 || dx > size.width) {
            dx = random.nextDouble() * size.width;
          }
    
          if (dy < 0 || dy > size.height) {
            dy = random.nextDouble() * size.height;
          }
    
          element.position = Offset(dx, dy);
        });
    
        list.forEach((element) {
          _paint.color = element.color;
    
          canvas.drawCircle(element.position, element.radius, _paint);
        });
      }
    
      @override
      bool shouldRepaint(covariant CustomPainter oldDelegate) {
        return true;
      }
    
      Offset calculateXY(double speed, double theta) {
        return Offset(speed * cos(theta), speed * sin(theta));
      }
    }
    
    /// 定义气泡
    class BobbleBean {
      //位置
      Offset position;
    
      //颜色
      Color color;
    
      //速度
      double speed;
    
      // 角度
      double theta;
    
      // 半径
      double radius;
    }
    View Code

     

    原文地址

  • 相关阅读:
    Smobiler的复杂控件的由来与创造
    WMS仓库管理应用——SwebUI开源应用解决方案
    iOS开发_接收airdrop发送来的文件
    名人名言
    App开发_Unicode编码范围说明
    Mac开发_隐藏与显示Dock 上的程序图标
    Apple开发_工程调试次数,自动计数
    Apple开发_Swift语言地标注释
    Apple开发_判断一个对象是实例对象还是类对象
    WeControl 隐私政策
  • 原文地址:https://www.cnblogs.com/buyiblogs/p/14431853.html
Copyright © 2020-2023  润新知