周末也需要学习 分享一个 Flutter 波浪波动效果的登录页面的背景 Flutter ClipPath实现的波动
Posted 早起的年轻人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了周末也需要学习 分享一个 Flutter 波浪波动效果的登录页面的背景 Flutter ClipPath实现的波动相关的知识,希望对你有一定的参考价值。
优美的应用体验 来自于细节的处理,更源自于码农的自我要求与努力,当然也需要码农年轻灵活的思维,不局限于思维,不局限语言限制,才是编程的最高境界。
本文章实现的效果如下图所示:
1 Flutter项目中单文件定义启动测试入口
void main()
//启动根目录
runApp(MaterialApp(
//默认的页面
home: Example820(),
));
2 页面初始化
波浪也是在波动,所以先来个动画控制器 Example820 的构建如下:
class Example820 extends StatefulWidget
@override
State<StatefulWidget> createState()
return _ExampleState();
class _ExampleState extends State with SingleTickerProviderStateMixin
///动画控制器
AnimationController _animationController;
@override
void initState()
super.initState();
//创建动画控制器
_animationController = AnimationController(
//默认的初始值
value: 0.0,
//执行时间
duration: Duration(seconds: 10),
//值变化范围
upperBound: 1,
lowerBound: -1,
vsync: this,
);
//重复执行
_animationController.repeat();
@override
void dispose()
//销毁
_animationController.dispose();
super.dispose();
...
3 页面的主体UI构建
页面主体使用 Scaffold脚手架构建,通过层叠布局Stack来组合,代码如下:
@override
Widget build(BuildContext context)
//获取当前组件的大小
Size size = MediaQuery
.of(context)
.size;
return Scaffold(
//允许键盘弹出布局文件上移
resizeToAvoidBottomPadding: true,
body: Container(
//填充
width: size.width,
height: size.height,
//层叠
child: Stack(
children: <Widget>[
//第一部分 水波纹背景
buildFirstAnimation(size),
//第二部分 顶部的文本
buildTopText(size),
//第三部分 底部的按钮
buildBottomButton(size),
],
),
),
);
3.1 Hello World
Stack 中有三层,先来看最简单的文本 ,代码如下:
/// 代码清单 8-31 顶部对齐的文本
///
Positioned buildTopText(Size size)
return Positioned(
top: size.height * 0.2,
left: 0,
right: 0,
child: Text(
"Hello World",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 33, color: Colors.white, fontWeight: FontWeight.bold),
),
);
3.2 底部的文本输入区域
使用线性布局Column 来构建,代码如下:
///底部对齐的输入框
Positioned buildBottomButton(Size size)
return Positioned(
bottom: 60,
left: 0,
right: 0,
child: Column(
//包裹子Widget
mainAxisSize: MainAxisSize.min,
//主方向子Widget 底部对齐 (Column的垂直方向)
mainAxisAlignment: MainAxisAlignment.end,
//次方向子Widget居中对齐 (Column的水平方向)
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: size.width * 0.8,
margin: EdgeInsets.only(top: 18),
child: buildInputWidget('请输入账号'),
),
Container(
width: size.width * 0.8,
margin: EdgeInsets.only(top: 18),
child: buildInputWidget('请输入密码', isPass: true),
),
Container(
margin: EdgeInsets.only(top: 20),
padding: EdgeInsets.only(bottom: 60),
width: size.width * 0.7,
child: ElevatedButton(
onPressed: () ,
child: Text(
'登录',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
),
],
),
);
因为这里的文本输入框是比较类似的,所以也进行了封装调用 ,代码如下:
///
Widget buildInputWidget(String hint, bool isPass = false)
return TextField(
//是否隐藏文本
obscureText: isPass,
//文本的边框装饰
decoration: InputDecoration(
//提示文本
hintText: hint,
//提示文本的样式
hintStyle: TextStyle(color: Color(0xFFACACAC), fontSize: 14),
//输入内容的内边距
contentPadding: EdgeInsets.only(top: 20, bottom: 20, left: 38),
//输入框可用时的边框样式
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlueAccent),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
),
//输入框获取输入焦点时的边框样式
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.green),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
),
),
);
4 波浪样式的背景构建
先通过 Container 的BoxDecoration 来设置渐变的背景样式,然后再通过 ClipPath 来裁剪,最后通过 AnimatedBuilder 与 AnimationController 动起来,代码如下:
/// 构建 AnimatedBuilder 与裁剪水波纹
///
AnimatedBuilder buildFirstAnimation(Size size)
return AnimatedBuilder(
//绑定动画控制器
animation: _animationController,
builder: (BuildContext context, Widget child)
//裁剪组件
return ClipPath(
//自定义裁剪路径
clipper: HeaderClipper(_animationController.value),
//裁剪的子Widget
child: Container(
//高度
height: size.height * 0.5,
//线性渐变颜色的样式
decoration: BoxDecoration(
gradient: LinearGradient(
//线性渐变的方向
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [Color(0xFFE0647B), Color(0xFFFCDD89)]),
),
),
);
,
);
ClipPath 用来裁剪自定义图片,定义如下:
/// 代码清单 8-34 自定义 Clipper
///
class HeaderClipper extends CustomClipper<Path>
///取值为 -1 ~ 1.0
double moveFlag = 0;
HeaderClipper(this.moveFlag);
@override
Path getClip(Size size)
//创建 Path
Path path = Path();
//移动到点 P0点 也是曲线的起点
path.lineTo(0, size.height * 0.8);
//计算控制点 P1 的坐标
double xCenter = size.width * 0.5 +
(size.width * 0.6 + 1) * sin(moveFlag * pi);
double yCenter = size.height * 0.8 + 69 * cos(moveFlag*pi);
//构建 二阶贝塞尔曲线
path.quadraticBezierTo(xCenter, yCenter, size.width, size.height * 0.8);
path.lineTo(size.width, 0);
return path;
@override
bool shouldReclip(CustomClipper<Path> oldClipper)
//刷新
return true;
用到了 二阶贝塞尔曲线 ,占位分析图如下:
二阶贝塞尔曲线:
也用到了 pi :
pi 、cos、sin 是Flutter Sdk dart.math类中提供的。
【x1】微信公众号的每日提醒 随时随记 每日积累 随心而过 文章底部扫码关注
不局限于思维,不局限语言限制,才是编程的最高境界。
以小编的性格,肯定是要录制一套视频的,随后会上传
有兴趣 你可以关注一下 西瓜视频 — 早起的年轻人
以上是关于周末也需要学习 分享一个 Flutter 波浪波动效果的登录页面的背景 Flutter ClipPath实现的波动的主要内容,如果未能解决你的问题,请参考以下文章
一起Talk Android吧(第五百一十九回:波浪上升动画)