Flutter中如何对double、int类型数值实现lerp线性插值?
Flutter 按压渐变Card阴影实现方案
核心实现逻辑
不用手动编写lerp插值计算逻辑,直接依托Flutter原生动画体系完成两段动效控制:
- 用
AnimationController托管elevation数值变化,初始值设为50,取值区间0-50 - 绑定InkWell的三个手势回调:
- 按下(
onTapDown)时,触发线性动画,在设定的按压时长内将数值从当前值匀速降到0,对应按住时阴影逐渐消失的效果 - 松开(
onTapUp)、手势取消(onTapCancel)时,触发短时长快速动画,将数值从当前值快速恢复到50,对应松手后阴影回弹效果
- 按下(
- 用
AnimatedBuilder监听动画值变化,实时更新Card的elevation属性,保证渲染性能
完整可复用代码
import 'package:flutter/material.dart'; class PressSinkingCard extends StatefulWidget { const PressSinkingCard({ super.key, required this.child, this.pressDuration = const Duration(milliseconds: 300), this.releaseDuration = const Duration(milliseconds: 100), this.initElevation = 50, }); /// Card内部内容 final Widget child; /// 按住到阴影完全消失的时长 final Duration pressDuration; /// 松手后阴影回弹恢复时长 final Duration releaseDuration; /// 初始阴影高度 final double initElevation; @override State<PressSinkingCard> createState() => _PressSinkingCardState(); } class _PressSinkingCardState extends State<PressSinkingCard> { late AnimationController _elevationCtrl; @override void initState() { super.initState(); _elevationCtrl = AnimationController( vsync: this, value: widget.initElevation, lowerBound: 0, upperBound: widget.initElevation, ); } @override void dispose() { _elevationCtrl.dispose(); super.dispose(); } void _handlePressDown(TapDownDetails _) { _elevationCtrl.animateTo( 0, duration: widget.pressDuration, curve: Curves.linear, // 按压阶段用线性插值,符合匀速递减需求 ); } void _handlePressUp(TapUpDetails _) { _elevationCtrl.animateTo( widget.initElevation, duration: widget.releaseDuration, curve: Curves.easeOut, // 回弹阶段用快出曲线,手感更自然 ); } void _handlePressCancel() { _elevationCtrl.animateTo( widget.initElevation, duration: widget.releaseDuration, curve: Curves.easeOut, ); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _elevationCtrl, builder: (context, _) { return Card( elevation: _elevationCtrl.value, clipBehavior: Clip.antiAlias, child: InkWell( onTapDown: _handlePressDown, onTapUp: _handlePressUp, onTapCancel: _handlePressCancel, onTap: () {}, // 必须设置非空onTap,否则InkWell不响应手势 child: widget.child, ), ); }, ); } }
参数调整说明
- 想要按住后阴影消失得更慢,就调大
pressDuration的时长,反之调小 - 想要松手后阴影回弹更快,就调小
releaseDuration的时长 - 回弹阶段如果想要弹跳效果,可以把
Curves.easeOut换成Curves.bounceOut - 动画内部自动执行
lerpDouble插值计算,不需要额外手动处理进度映射,和需求里的线性插值逻辑完全一致
注意:如果需要给Card加圆角、背景色等属性,直接透传给Card组件即可,不会影响按压动效。
内容的提问来源于stack exchange,提问作者Jiehfeng
相关产品推荐
相关产品推荐

