Flutter:使用 Sliver 小部件时如何隐藏滚动时的 BottomAppBar?

2023-11-25

当用户向下滚动列表时,我试图隐藏底部应用程序栏,就像材料设计文档中行为部分中显示的那样:

https://material.io/design/components/app-bars-bottom.html#behavior

我正在寻找的效果如下所示:https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1gaSrddolFHd8BwOioeYz0ODiyEhCevtn%2Fbehavior-scroll.mp4

到目前为止,我向脚手架添加了底部应用栏,但它没有滚动行为。

StackOverflow 上有一个类似的问题得到了回答,但它显示了一种解决方法,并且不久前已经得到了回答。

Flutter 中是否有合法的方法来实现这种效果?

我的代码:

import 'package:fitness_fatality_flutter/data/entities/exercise.dart';
import 'package:fitness_fatality_flutter/data/entities/workout.dart';
import 'package:flutter/material.dart';

class WorkoutDetailsPage extends StatelessWidget {
  Workout _workout = Workout();

  final List<Exercise> exercises = [
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
  ];

  WorkoutDetailsPage(this._workout);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling,
      floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.blue,
        elevation: 12,
        onPressed: () {},
      ),
      bottomNavigationBar: BottomAppBar(
        elevation: 8,
        shape: CircularNotchedRectangle(),
        color: Colors.blue,
        child: Container(
          height: 50,
          child: Row(
            children: <Widget>[Text("data")],
          ),
        ),
      ),
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            bottom:BottomAppBar(), //<-- This would throw an error
            expandedHeight: 150,
            pinned: true,
            floating: true,
            snap: true,
            flexibleSpace: FlexibleSpaceBar(
              title: Text(_workout.name),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(buildSliverListItem,
                childCount: exercises.length),
          ),
        ],
      ),
    );
  }

  Widget buildSliverListItem(BuildContext context, int index) {
    return Center(
      child: ListTile(
        title: Text(exercises[index].name),
      ),
    );
  }
}

BottomAppBar是其一部分Scaffold小部件,不是Sliver。有一种方法可以实现您所描述的目标,但是有点复杂并且需要StatefulWiget and ScrollController, AnimatedContainer。请参阅下面的完整示例代码:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: WorkoutDetailsPage(Workout()),
    );
  }
}

class Exercise {
  String name;
  Exercise({@required name}) {
    this.name = name;
  }
}

class Workout {
  String name = "my name";
}

class WorkoutDetailsPage extends StatefulWidget {
  Workout _workout = Workout();

  WorkoutDetailsPage(this._workout);

  @override
  _WorkoutDetailsPageState createState() => _WorkoutDetailsPageState();
}

class _WorkoutDetailsPageState extends State<WorkoutDetailsPage> {
  final List<Exercise> exercises = [
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
    Exercise(name: "Push Ups"),
    Exercise(name: "Bench press"),
    Exercise(name: "Pull ups"),
    Exercise(name: "Press ups"),
    Exercise(name: "Crunches"),
    Exercise(name: "Sit ups"),
    Exercise(name: "BIceps curl"),
    Exercise(name: "Something else"),
  ];

  ScrollController _hideButtonController;

  bool _isVisible = true;
  @override
  void initState() {
    super.initState();
    _isVisible = true;
    _hideButtonController = new ScrollController();
    _hideButtonController.addListener(() {
      print("listener");
      if (_hideButtonController.position.userScrollDirection ==
          ScrollDirection.reverse) {
        setState(() {
          _isVisible = false;
          print("**** $_isVisible up");
        });
      }
      if (_hideButtonController.position.userScrollDirection ==
          ScrollDirection.forward) {
        setState(() {
          _isVisible = true;
          print("**** $_isVisible down");
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling,
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: _isVisible
          ? FloatingActionButton(
              backgroundColor: Colors.blue,
              elevation: 12,
              onPressed: () {},
            )
          : null,
      bottomNavigationBar: AnimatedContainer(
        duration: Duration(milliseconds: 200),
        height: _isVisible ? 60 : 0.0,
        child: BottomAppBar(
          elevation: 8,
          shape: CircularNotchedRectangle(),
          color: Colors.blue,
          child: Container(
            height: 60,
            child: Row(
              children: <Widget>[Text("data")],
            ),
          ),
        ),
      ),
      body: CustomScrollView(
        controller: _hideButtonController,
        slivers: <Widget>[
          SliverAppBar(
            expandedHeight: 150,
            pinned: true,
            floating: true,
            snap: true,
            flexibleSpace: FlexibleSpaceBar(
              title: Text(widget._workout.name),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(buildSliverListItem,
                childCount: exercises.length),
          ),
        ],
      ),
    );
  }

  Widget buildSliverListItem(BuildContext context, int index) {
    return Center(
      child: ListTile(
        title: Text(exercises[index].name),
      ),
    );
  }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter:使用 Sliver 小部件时如何隐藏滚动时的 BottomAppBar? 的相关文章

  • 由于现有相机用户,相机“0”的手电筒不可用

    我想创建一个应用程序 它有一个用于录制视频的按钮和另一个单独的切换按钮 用于在录制视频期间打开闪光灯 我已经使用camera2 API为最近的androids构建了相机应用程序 可以通过图像按钮访问 我将火炬模式设置为切换按钮 但这根本不起
  • 处理 SavedInstances 并恢复活动

    基本上我的应用程序有 2 个活动 说 A 和 B A 启动 B Activity B 播放音乐并且还有通知 情况 1 当视图仍在活动 B 上时 我按主页按钮 然后单击通知 活动 B 将打开 其视图完好无损并播放音乐 因为在清单中我使用 an
  • 如何在 Android 中的 Chrome 或 Firefox 等特定浏览器的 Web 视图中加载应用程序

    我是 Android 新手 我正在做一个应用程序 我需要在平板电脑上的 Web 视图中加载现有的应用程序 在平板电脑中 当我使用 Web 视图加载应用程序时 我的应用程序将加载到默认浏览器中 如何在平板电脑上的 Web 视图中的特定浏览器
  • Android任务执行中的“platformAttrExtractor”是什么?

    我介绍了我的构建关注者操作说明 https developer android com studio build optimize your build html profile在安卓中 gradlew profile recompile
  • 垂直 ViewPager 中的动画

    我需要垂直制作这个动画ViewPager https www youtube com watch v wuE 4jjnp3g https www youtube com watch v wuE 4jjnp3g 这是我到目前为止所尝试的 vi
  • Android 位置 API:获取提供商状态

    在 Android 中获取位置提供商状态的最佳方式是什么 当注册 LocationListener 以进行位置更新时 onStatusChanged String provider int status Bundle extras 每当状态
  • Android:将声音保存为铃声/SQLiteConstraintException

    我正在尝试使用 Android 将声音保存为铃声this http www stealthcopter com blog 2010 01 android saving a sound file to sd from resource and
  • 获取Android库中的上下文

    我正在编写一个 Android 应用程序 它的一些功能封装在内部库中 但是 要使此功能发挥作用 库需要一个应用程序上下文的实例 为图书馆提供这种上下文的最佳方式是什么 我看到了一些选择 但没有一个有吸引力 Have my library c
  • 使用全局变量从内部函数获取空字符串

    请帮助我解决一些小问题 我确信你能做到 D 我试图在 firestore 文档 user cases information 上设置一个字段 其中包含一个字段 case number 首先我声明这个全局变量 private String c
  • Android 和 Honeycomb - 如何使用 SDK 13 拥有菜单图标而不需要“操作栏”

    我想最大限度地利用 Honeycomb 应用程序的屏幕 由于屏幕底部已经被 始终打开 的项目所困 我想在该空间中添加一个菜单按钮 而不是牺牲更多的屏幕空间 在顶部放置一个 操作栏 我怎样才能做到这一点without降级到 API 10 或更
  • 绘制平滑曲线

    我想创建更平滑的曲线 而不仅仅是线角 这是我现在画的图 这是我的代码 case FREEHAND float pts float ptk ptk new float 2 imageMatrix invert inv if mCurrentS
  • 导航到 Flutter 中的新屏幕

    如何在 Flutter 中导航到新屏幕 这些问题很相似 但比我问的要多 Flutter 导航到新屏幕 并清除所有以前的屏幕 https stackoverflow com questions 52689049 flutter navigat
  • RxJava android mvp 单元测试 NullPointerException

    我是 mvp 单元测试的新手 我想对演示者进行一个非常基本的测试 它负责登录 我只想断言 view onLoginSuccess 这是演示者代码 public LoginPresenter LoginViewContract loginVi
  • 当类明显存在时,我收到 java.lang.NoClassDefFoundError

    当我尝试在运行时使用该库时 出现以下错误 java lang NoClassDefFoundError com google api client extensions android2 AndroidHttp 我已经将此库添加到我的项目中
  • 错误膨胀类 android.support.design.widget.NavigationView [启动时崩溃]

    该应用程序应该有一个导航抽屉 可以从左侧拉出并显示各种活动 但是一旦将导航栏添加到 XML Activity homescreen 文档中 应用程序一启动就会崩溃 主屏幕 java package com t99sdevelopment c
  • Android 应用程序不需要任何特殊访问权限

    当我开始安装时myapp apk 我得到下面的屏幕 我的应用程序需要位置 外部存储权限 上述权限应该根据需要向用户请求 即在需要这些权限的代码之前 现在 当安装应用程序时 我会看到一个屏幕 上面显示应用程序不需要任何特殊访问权限 如下图所示
  • Android 导航组件 - 从“任何地方”/基本片段导航?

    我正在开发一个应用程序 它有一个奇怪的花招 可以在设备旋转时打开特定的片段 在实现 android 的导航组件之前 所需要的只是对当前活动的引用 并且可以在特定时刻向用户显示的任何内容之上执行手动片段事务 但是在转移到导航组件之后 我发现很
  • Firebase:用户注册后如何进行电话号码验证?

    所以我知道我可以使用电子邮件验证或电话号码验证 但我想做的是在用户注册或登录后进行电话号码验证 如何连接这两种身份验证方法 最后 Firebase中是否有一个函数可以检查用户是否通过电话号码验证 谢谢 即使用户已通过身份验证 您仍然可以使用
  • 永久删除Android文件

    我发现了一个名为这会从 Android 设备中永久删除文件和文件夹 以便删除的文件无法再恢复 这是我正在谈论的应用程序 但我想知道如何做到这一点 我知道它是用 android studio 制作的 i尝试了常规的删除方式file delet
  • Android ClassNotFoundException:在路径上找不到类

    10 22 15 29 40 897 E AndroidRuntime 2561 FATAL EXCEPTION main 10 22 15 29 40 897 E AndroidRuntime 2561 java lang Runtime

随机推荐