You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为布局变化导致位置变更的Flutter Widget添加位移动画

Flutter 键盘弹出/收起时动态偏移Widget的平滑动画实现方案

你的场景核心矛盾是无法提前确定位移终态,所以无需使用需要显式设置终态的显式动画组件(如SlideTransition),采用Flutter自带的隐式动画组件即可实现需求,它会自动监听属性变化、生成补间动画,完全适配动态计算的偏移场景。

实现思路

  • 关闭Scaffold默认的键盘顶起行为,避免系统默认的生硬跳转
  • 通过MediaQuery.of(context).viewInsets.bottom实时获取当前键盘高度,无需手动计算偏移量
  • 用隐式动画组件包裹目标Widget(放大镜+文字组),动态传入位置参数即可自动生成过渡动画

示例代码

import 'package:flutter/material.dart';

class SearchPage extends StatelessWidget {
  const SearchPage({super.key});

  @override
  Widget build(BuildContext context) {
    // 实时获取当前键盘弹出高度,键盘收起时该值为0
    final keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
    return Scaffold(
      // 关闭系统默认的布局resize行为,避免生硬跳转
      resizeToAvoidBottomInset: false,
      body: LayoutBuilder(
        builder: (context, constraints) {
          // 计算键盘弹出后的页面可用高度
          final availableHeight = constraints.maxHeight - keyboardHeight;
          return Stack(
            children: [
              // 顶部搜索框
              const Positioned(
                top: 24,
                left: 16,
                right: 16,
                child: TextField(
                  decoration: InputDecoration(
                    hintText: '请输入搜索内容',
                    border: OutlineInputBorder(),
                    contentPadding: EdgeInsets.symmetric(horizontal: 12),
                  ),
                ),
              ),
              // 目标动画组件:放大镜+文字组
              AnimatedPositioned(
                // 动态计算垂直居中位置:(可用高度 - 组件高度) / 2
                // 如果你不知道组件实际高度,可以通过GlobalKey在布局完成后动态获取
                top: (availableHeight - 100) / 2,
                left: 0,
                right: 0,
                // 动画时长和系统键盘动画时长保持一致,体验更连贯
                duration: const Duration(milliseconds: 250),
                curve: Curves.easeInOut,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: const [
                    Icon(Icons.search, size: 48, color: Colors.grey),
                    SizedBox(height: 12),
                    Text(
                      '搜索你感兴趣的内容',
                      style: TextStyle(
                        color: Colors.grey,
                        fontSize: 14,
                      ),
                    ),
                  ],
                ),
              )
            ],
          );
        },
      ),
    );
  }
}

优化提示

  • 若不需要嵌套Stack,也可以用AnimatedPadding包裹目标组件,设置padding: EdgeInsets.only(bottom: keyboardHeight * 0.5),调整比例即可控制组件上移幅度,同样会自动生成过渡动画
  • 若页面全量内容都需要跟随键盘平滑偏移,直接将整个body用AnimatedPadding包裹,设置padding: EdgeInsets.only(bottom: keyboardHeight)即可实现全局平滑过渡效果
  • 如需获取目标组件的实际高度,给组件绑定GlobalKey,在WidgetsBinding.instance.addPostFrameCallback回调中通过key.currentContext?.size获取后再计算位置即可

内容的提问来源于stack exchange,提问作者Danny Allen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 20:36:07