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

如何在SlidingUpPanel下滑时逐步隐藏BottomNavigationBar?

解决SlidingUpPanel下滑时平滑隐藏BottomNavigationBar的方案

针对你遇到的onPanelSlide回调卡顿问题,核心原因是频繁调用setState导致整个页面频繁重建。以下是两种高效且专业的实现方案,能达到类似Airbnb的流畅效果:

方案一:使用AnimatedBuilder联动PanelController

利用SlidingUpPanel的PanelController内置动画驱动,通过AnimatedBuilder仅更新BottomNavigationBar组件,避免全局刷新:

import 'package:flutter/material.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final PanelController _panelController = PanelController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: AnimatedBuilder(
        animation: _panelController,
        builder: (context, child) {
          // 获取面板当前位置:0=完全收起,1=完全展开
          final panelPosition = _panelController.isAttached ? _panelController.position : 0.0;
          // 设置触发隐藏的阈值,面板滑动超过20%时开始隐藏导航栏
          final threshold = 0.2;
          final hideProgress = (panelPosition / threshold).clamp(0.0, 1.0);

          return Transform.translate(
            offset: Offset(0, hideProgress * kBottomNavigationBarHeight),
            child: Opacity(
              opacity: 1.0 - hideProgress,
              child: child,
            ),
          );
        },
        child: BottomNavigationBar(
          items: const [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
            BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
          ],
        ),
      ),
      body: SlidingUpPanel(
        controller: _panelController,
        minHeight: 80,
        panel: const Center(child: Text('滑动面板内容')),
        body: const Center(child: Text('主页面内容')),
      ),
    );
  }
}

方案二:使用ValueListenableBuilder监听面板位置

PanelController的position属性是ValueNotifier<double>,通过ValueListenableBuilder精准监听位置变化,仅更新导航栏的动画状态:

import 'package:flutter/material.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final PanelController _panelController = PanelController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: ValueListenableBuilder<double>(
        valueListenable: _panelController.position,
        builder: (context, position, child) {
          final threshold = 0.2;
          final hideProgress = (position / threshold).clamp(0.0, 1.0);

          return AnimatedSlide(
            offset: Offset(0, hideProgress),
            duration: const Duration(milliseconds: 150),
            curve: Curves.easeInOut,
            child: AnimatedOpacity(
              opacity: 1.0 - hideProgress,
              duration: const Duration(milliseconds: 150),
              curve: Curves.easeInOut,
              child: child,
            ),
          );
        },
        child: BottomNavigationBar(
          items: const [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
            BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
          ],
        ),
      ),
      body: SlidingUpPanel(
        controller: _panelController,
        minHeight: 80,
        panel: const Center(child: Text('滑动面板内容')),
        body: const Center(child: Text('主页面内容')),
      ),
    );
  }
}

核心优化点

  1. 避免全局刷新:两种方案都只针对BottomNavigationBar组件进行局部更新,不会触发整个页面的setState
  2. 平滑动画过渡:通过计算面板滑动进度,结合透明度和位移动画,实现和Airbnb一致的自然隐藏效果
  3. 性能高效:利用Flutter内置的动画组件,避免手动计算和频繁回调导致的性能损耗

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:57:45