Flutter交互实战-即刻App探索页下拉&拖拽效果

本文详细介绍了如何使用Flutter实现类似即刻App探索页的下拉和拖拽效果,涵盖下拉控件和卡片控件的布局、手势识别,以及自定义DragGestureRecognizer的实现。通过实例分享了Flutter手势处理和布局摆放的技巧,同时讨论了在实现过程中遇到的挑战和解决方案。
摘要由CSDN通过智能技术生成

Flutter最近比较热门,但是Flutter成体系的文章并不多,前期避免不了踩坑;我这篇文章主要介绍如何使用Flutter实现一个比较复杂的手势交互,顺便分享一下我在使用Flutter过程中遇到的一些小坑,减少大家入坑;

项目地址:https://github.com/HitenDev/FlutterDragCard

先睹为快

本项目支持iosandroid平台,效果如下

对了,顺便分享一下生成gif的小窍门,建议用手机自带录屏功能导出mp4文件到电脑,然后电脑端用ffmpeg命令行处理,控制gif的质量和文件大小,我的建议是分辨率控制在270p,帧率在10左右;

交互分析

看文章的小伙伴最好能手持即刻App,亲自体验一下探索页的交互,是黄色Logo黄色主题色的即刻,人称‘黄即’;

即刻App原版功能有卡片旋转,卡片撤回和卡片自动移除,时间关系暂时没有实现,但核心的功能都在;

从一个Android开发者的习惯来看待,这个交互可拆分内外两层控件,外层我们需要一个整体下拉的控件,我称为下拉控件;内层我们需要实现一个上、下、左、右四方向拖拽移动的控件,我们称为卡片控件下拉控件卡片控件不仅要处理手势,还需要处理子Widget的布局;下面我再分析细节功能:

下拉控件:

  • 子控件从上到下竖直摆放,顶部菜单默认隐藏在屏幕外
  • 下拉手势所有子控件下移,菜单视觉差效果
  • 支持点击自动展开、收起效果

卡片控件

  • 卡片层叠布局,错落有致
  • 最上层卡片支持手势拖拽
  • 其他卡片响应拖拽小幅位移
  • 松手移除卡片

码上入手

热身

套用App开发伎俩,实现上面的交互无非就是控件布局和手势识别。当然Flutter开发也是这些套路,只不过万物皆是Widget,在Flutter中常用的基本布局有ColumnRowStack等,手势识别有ListenerGestureDetectorRawGestureDetector等,这是本文重点讲解的控件,不限于上面这几个Widget,因为Flutter提供的Widget太多了,重点的控件需要牢记外,其他时候真是现用现查;

所以下面我们从布局和手势这两个大的技术点,来一一击破功能点;

布局摆放

这里所谓的布局,包括Widget的尺寸大小和位置的控制,一般都是父Widget掌管子Widget的命运,Flutter就是一层一层Widget嵌套,不要担心,下面从外到内具体案例讲解;

下拉控件

首先我们要实现最外层布局,效果是:子Widget竖直摆放,且最上面的Widget默认需要摆放在屏幕外;

如上图所示,红色区域是屏幕范围,header是头部隐藏的菜单布局,content是卡片布局的主体;

先说入的坑

竖直布局我最先想到的是Column,我想要的效果是content高度和父Widget的高度一致,我首先想到是让Expanded包裹content,结果是content的高度永远等于Column高度减header高度,造成现象就是content高度不填充,或者是挤压现象,如果继续使用Colunm可能就得放弃Expanded,手动给content赋值高度,没准是个办法,但我不愿意手动赋值content的高度,太不优雅了,最后果断弃用Column

另一个问题是如何隐藏header,我想到两种方案:

  1. 采用外层Transform包裹整个布局,内层Transform包裹header,然后赋值内层dy = -headerHeight,随着手势下拉动态,并不改变headerTransform,而是改变最外层Transformdy
  2. 动态改变header高度,初始高度为0,随着手势下拉动态计算;

但是上面这两种都有坑,第一种方式会影响控件的点击事件,onTap方法不会被回调;第二种由于高度在不断改变,会影响header内部子Widget的布局,很难做视觉差的控制;

最终方案

最后采用Stack来布局,通过Stack配合Positioned,实现header布局在屏幕外,而且可以做到让content布局填充父Widget;

PullDragWidget

Widget build(BuildContext context) {
  return RawGestureDetector(
      behavior: HitTestBehavior.translucent,
      gestures: _contentGestures,
      child: Stack(
        children: <Widget>[
          Positioned(//content布局
              top: _offsetY,
              bottom: -_offsetY,
              left: 0,
              right: 0,
              child: IgnorePointer(
                ignoring: _opened,
                child: widget.child,
              )),
          Positioned(header布局
              top: -widget.dragHeight + _offsetY,
              bottom: null,
              left: 0,
              right: 0,
              height: widget.dragHeight,
              child: _headerWidget()),
        ],
      ));
}

首先解释一下Positioned的基本用法,topbottomheig

很高兴为您解答问题!关于Flutter实战视频-移动电商-48.详细_详情和评论的切换,我可以提供以下解答: 在Flutter实战视频-移动电商-48中,详细的详情和评论的切换是通过一个TabBar实现的。具体来说,通过在AppBar中添加一个TabBar来实现不同面之间的切换。在这个TabBar中,我们可以添加两个Tab,分别为“详情”和“评论”,并分别对应两个面。当用户点击不同的Tab时,就可以切换到不同的面。 在Flutter中,TabBar可以使用DefaultTabController和TabBarView来实现。DefaultTabController是一个Widget,它可以管理TabBar和TabBarView之间的关系。TabBarView则是一个Widget,它可以显示不同的面。 具体实现方法如下: ```dart class DetailPage extends StatefulWidget { @override _DetailPageState createState() => _DetailPageState(); } class _DetailPageState extends State<DetailPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('商品详情'), bottom: TabBar( tabs: <Widget>[ Tab( text: '详情', ), Tab( text: '评论', ), ], ), ), body: DefaultTabController( length: 2, child: TabBarView( children: <Widget>[ // 详情面 DetailWidget(), // 评论面 CommentWidget(), ], ), ), ); } } ``` 在上面的代码中,我们首先创建了一个AppBar,并在其中添加了一个TabBar。然后,在Scaffold的body中,我们创建了一个DefaultTabController,并将其length设为2,即有两个面。最后,我们在TabBarView中添加了两个Widget,即DetailWidget和CommentWidget,分别对应详情面和评论面。 希望这个解答能够对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值