文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Flutter实现固定header底部滑动页效果示例

2022-12-29 12:00

关注

正文

实现的效果是这样的:

刚开始的时候,是在dev上找了两个轮子,简单测了下,都不太满意,滑动事件处理的比较粗糙,总有bug。就在想着,要不要拿源码改一版的时候,让我无意间看到了这个帖子

image.png

里面的想法,大开眼界,是通过 DraggableScrollableSheet 和 IgnorePointer 来完美实现上面的效果。

实现

这是 DraggableScrollableSheet 的代码,

DraggableScrollableSheet(
  maxChildSize: 0.8,
  minChildSize: 0.25, // 注意都是占父组件的比例
  initialChildSize: 0.25,
  expand: true,
  builder: (BuildContext context, ScrollController controller) {
    return Stack(); // body列表和header栏都在stack内
  },
)

这是 body 列表和 header,这里的 body 是个 list,

Stack(
  children: [
    Container(
      color: Colors.blue,
      child: Body( // ListView.separated
        controller: controller,
        paddingTop: headerHeight, // 防止压盖
      ),
    ),
    const IgnorePointer( // 这里不接收事件,所以拖动 header 也能够滑动页面
      child: Header( // Container[Center[Text]]
        height: headerHeight,
      ),
    ),
  ],
)

但如果我们想在 header 内加点击事件呢?那在 Stack header 上层再加 widget 就好了。

代码就这点,我放在了 gitHub 上,感兴趣的可以看下。

2022.8.23 补充:

这是在上面功能基础上的一个小扩展,即当滑动距离超过一半则自动滚至顶部,反之回到底部,来看下效果:

思路也很简单,首先我要知道当前滚动的距离或其占比,DraggableScrollableController 提供了这个能力:

void _draggableScrollListener() {
  // [_currStale] 记录下当前的占比
  // [_controller.size] 即占比, 范围[minChildSize,maxChildSize]
  // [_controller.pixels] 即距离
  if (_currStale != _controller.size) {
    _currStale = _controller.size;
  }
  debugPrint('[listener] size: ${_controller.size}'
      ', pixels : ${_controller.pixels}');
}

其次要知道用户何时停止了滚动,我们可以使用 NotificationListener 来监听 DraggableScrollableSheet 的滚动状态:

NotificationListener<ScrollNotification>(
  onNotification: (ScrollNotification notification) {
    ...
    return false;
  },
child: DraggableScrollableSheet(...),

之后在用户停止滚动的时候,我们判断当前距离,并根据结果让 DraggableScrollableSheet 自动滚动到顶部或底部。

onNotification: (ScrollNotification notification) {
  if (_animation) { // 动画中,不处理状态
    return false;
  }
  if (notification is ScrollStartNotification) {
    debugPrint('start scroll');
  } else if (notification is ScrollEndNotification) {
    debugPrint('stop scroll');
    // 通过 [_controller.animateTo] 方法滚动
    _scrollAnimation();
  }
  return false;

在 _scrollAnimation 内就是滚动的方法了,这里要注意的是,不能直接使用 await Feature,我测试在频繁不同方向滑动时,可能会导致方法被挂起。在这直接 dedelayed(duration: xx) 即可:

Future<void> _scrollAnimation() async {
  if (_animation) {
    return;
  }
  _animation = true;
  //debugPrint('async start');
  final int duration;
  // `await`ing the returned Feature(of [animateTo]) may cause the method to hang
  // So, Start a timer to set [_animation].
  if (_currStale >= (_maxScale + _minScale) * 0.5) {
    duration =
        (_duration * ((_maxScale - _currStale) / (_maxScale - _minScale)))
            .toInt();
    if (duration == 0) {
      _animation = false;
      return;
    } else {
      // [duration] control speed, Avoid situations where it's equal to 0
      _animationTo(_maxScale, duration);
    }
  } else {
    duration =
        (_duration * ((_currStale - _minScale) / (_maxScale - _minScale)))
            .toInt();
    if (duration == 0) {
      _animation = false;
      return;
    } else {
      _animationTo(_minScale, duration);
    }
  }
  Future.delayed(
    Duration(milliseconds: duration),
  ).then((value) => {
        //debugPrint('async stop'),
        _animation = false,
      });
}

其中 _animationTo 是实际控制控件滚动的方法:

void _animationTo(double scale, int duration) {
  _controller.animateTo(
    scale,
    duration: Duration(milliseconds: duration),
    curve: Curves.ease,
  );
}

2022.9.24 补充:

那如果再提供一种通过点击按钮来控制 DraggableScrollableSheet 收起和弹出的方法呢?

我们可以直接这样,是不是很简单:

Future<void> _scrollAnimation2() async {
  if (_animation) {
    return;
  }
  if (_currStale > (_maxScale + _minScale) * 0.5) {
    _animationTo(_minScale, _duration);
  } else {
    _animationTo(_maxScale, _duration);
  }
}

以上就是Flutter实现固定header底部滑动页效果示例的详细内容,更多关于Flutter固定header底部滑动页的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯