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

如何在Flutter中结合GetX实现滚动时隐藏/显示FloatingActionButton

Flutter + GetX 实现滚动时隐藏/显示FloatingActionButton

实现思路

通过监听滚动通知,对比前后滚动偏移量判断滚动方向,用GetX的响应式状态控制FAB的显示/隐藏状态,配合动画组件实现平滑过渡效果。

步骤1:创建GetX控制器

定义控制器管理滚动偏移记录和FAB可见状态:

class ScrollFabController extends GetxController {
  // 记录上一次滚动位置
  final RxDouble _lastScrollOffset = 0.0.obs;
  // FAB可见状态
  final RxBool _fabVisible = true.obs;

  bool get fabVisible => _fabVisible.value;

  void handleScroll(ScrollNotification notification) {
    final currentOffset = notification.metrics.pixels;
    // 设置滚动阈值,避免轻微滚动触发状态切换
    const scrollThreshold = 10.0;

    if (currentOffset - _lastScrollOffset.value > scrollThreshold) {
      // 向下滚动超过阈值,隐藏FAB
      _fabVisible.value = false;
    } else if (_lastScrollOffset.value - currentOffset > scrollThreshold) {
      // 向上滚动超过阈值,显示FAB
      _fabVisible.value = true;
    }

    _lastScrollOffset.value = currentOffset;
  }
}

步骤2:在页面中实现滚动监听与FAB控制

用NotificationListener监听滚动事件,通过Obx响应状态变化,配合AnimatedOpacity实现平滑过渡:

class ScrollFabPage extends StatelessWidget {
  final controller = Get.put(ScrollFabController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('滚动控制FAB示例')),
      body: NotificationListener<ScrollNotification>(
        onNotification: (notification) {
          controller.handleScroll(notification);
          return true;
        },
        child: ListView.builder(
          itemCount: 50,
          itemBuilder: (ctx, index) => ListTile(title: Text('列表项 $index')),
        ),
      ),
      floatingActionButton: Obx(
        () => AnimatedOpacity(
          opacity: controller.fabVisible ? 1.0 : 0.0,
          duration: const Duration(milliseconds: 300),
          // 隐藏时移除点击区域
          child: Visibility(
            visible: controller.fabVisible,
            child: FloatingActionButton(
              onPressed: () => print('FAB被点击'),
              child: const Icon(Icons.add),
            ),
          ),
        ),
      ),
    );
  }
}

可选优化:滑入滑出动画

如果想要更自然的滑入滑出效果,可以替换AnimatedOpacity为SlideTransition(需要将页面改为StatefulWidget):

class ScrollFabPage extends StatefulWidget {
  const ScrollFabPage({super.key});

  @override
  State<ScrollFabPage> createState() => _ScrollFabPageState();
}

class _ScrollFabPageState extends State<ScrollFabPage> with SingleTickerProviderStateMixin {
  final controller = Get.put(ScrollFabController());
  late final AnimationController _animationController;
  late final Animation<Offset> _slideAnimation;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
    _slideAnimation = Tween<Offset>(
      begin: Offset.zero,
      end: const Offset(0, 2), // 向下滑出屏幕
    ).animate(CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeInOut,
    ));

    // 监听FAB状态变化,控制动画
    ever(controller._fabVisible, (isVisible) {
      if (isVisible) {
        _animationController.reverse();
      } else {
        _animationController.forward();
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('滚动控制FAB示例')),
      body: NotificationListener<ScrollNotification>(
        onNotification: (notification) {
          controller.handleScroll(notification);
          return true;
        },
        child: ListView.builder(
          itemCount: 50,
          itemBuilder: (ctx, index) => ListTile(title: Text('列表项 $index')),
        ),
      ),
      floatingActionButton: SlideTransition(
        position: _slideAnimation,
        child: FloatingActionButton(
          onPressed: () => print('FAB被点击'),
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:36:27