likes
comments
collection
share

深入了解Flutter滚动组件

作者站长头像
站长
· 阅读数 11

前言

本文适合有一定Flutter基础,但是对于Flutter滚动组件不够深入理解的同学。从应用场景入手,在合适的场景使用合适的组件。

ListView

单纯的使用ListView的话它会把列表数据全部渲染出来这样可能会有性能问题

ListView.builder

使用ListView.builder的话有虚拟列表的功能,它只会显示当前视口及视口之外的几个临近子组件,它是按照视口之外的高度作为参照渲染多出的组件的

ListView.separated

ListView.builder也有虚拟列表的功能但是比虚拟列表多出一个插入功能,比如可以在第一行和第二行之间插入组件

ListView.separated(
  controller: _controller, // 控制滚动位置
  // 安卓的效果:ClampingScrollPhysics
  // IOS的效果:BouncingScrollPhysics
  // 用户无法滚动:NeverScrollableScrollPhysics
  // 自动对焦项目: FixedExtentScrollPhysics
  physics: BouncingScrollPhysics(), // 控制滚动到边界的效果
  separatorBuilder: (context, index) {
    return Divider(); // 插入一个组件在两个项目中间
  },
  itemCount: 800,
  itemBuilder: (context, index) {
    return Text("index $index");
  },
)

滚动条

  • CupertinoScrollbar 按住可以拖动滚动条位置
  • Scrollbar 默认的滚动条(无法拖动)

滚动效果

  • 安卓波浪的效果:ClampingScrollPhysics
  • IOS的拉伸效果:BouncingScrollPhysics
  • 自动对齐某个项目: FixedExtentScrollPhysics
  • 用户无法滚动:NeverScrollableScrollPhysics
// 自定义ScrollBehavior来清除操作系统上的默认滚动效果,有时候我们并不需要这些效果
class ClearEffectScrollBehavior extends ScrollBehavior {
  @override
  Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
    return child;
  }
}

刷新列表

RefreshIndicator(
  onRefresh: () {
    return Future.delayed(const Duration(seconds: 2)); // 等待两秒
  },
  child: ListView.builder(
    physics: const BouncingScrollPhysics(),
    itemCount: 800,
    itemBuilder: (context, index) {
      return Text("index $index");
    },
  ),
),

滑动移除某项

基于Dismissible组件来做的滑动移除效果

Dismissible(
  key: UniqueKey(), // 必须传递Key
  background: Container( // 背景其实不单只是颜色
    child: Icon(Icons.ios_share_sharp),
  ),
  onDismissed: (direction) { // 移除后的事件
    print(direction);
  },
  onResize: () { // 移除后调整大小事件
    print('resize');
  },
  direction: DismissDirection.vertical, // 可滑动的主轴方向
  child: Container(
    height: 80,
    color: Colors.blue[100],
  ),
)

GridView

设置一行放置多少个元素:

  • SliverGridDelegateWithFixedCrossAxisCount 按照指定数量
  • SliverGridDelegateWithMaxCrossAxisExtent 按照能容纳比例放置

GridView.builder

可以达到虚拟列表的效果,缺点是需要写更多的代码,配合SliverGridDelegateWithFixedCrossAxisCount或SliverGridDelegateWithMaxCrossAxisExtent使用,达到一行展示多少个

GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 8,
    mainAxisSpacing: 5, // 主轴上元素之前的间距
    crossAxisSpacing: 5, // 次轴上元素之前的间距
  ),
  itemBuilder: (context, index) {
    return Icon(Icons.abc);
  },
),

GridView.extent和GridView.count

可以直接将一行展示多少个直接写在自己属性中,不需要额外的组件

GridView.extent(
  maxCrossAxisExtent: 150, // 按照一行能够放下多少个来计算 一行的数量 = 屏幕宽度 / 150 
  children: [
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
  ],
);

GridView.count(
  crossAxisCount: 5, // 一行必须放置5个
  children: [
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
    Icon(Icons.abc),
  ],
)

ListWheelScrollView

深入了解Flutter滚动组件效果图

ListWheelScrollView(
  itemExtent: 40, // 子级的大小
  // offAxisFraction: -1.5, // 右边偏移量
  magnification: 1.5, // 放大
  useMagnifier: true, // 使用放大
  diameterRatio: 2, // 圆的弧度
  overAndUnderCenterOpacity: 0.5, // 中心项目透明度是0.5
  physics: FixedExtentScrollPhysics(),
  children: List.generate(
    20,
    (index) => Container(color: Colors.blue[300]),
  ),
)

PageView

多用于手势滑动切换整屏,这里有个头大的问题就是需要清除掉默认的滚动边界样式,通过自定义的 ClearEffectScrollBehavior 类实现清除

深入了解Flutter滚动组件安卓上的滚动边界样式(小波浪)

PageView(
  controller: PageController(),
  pageSnapping: false, // 取消自动对齐
  scrollBehavior: ClearEffectScrollBehavior(), // 清除默认的滚动边界样式,你也可以直接用于根MetairieApp组件中
  onPageChanged: (val) { // 滑动到某个页面组件,在没有松手的情况下也会触发这个事件
    print(val);
  },
  children: [
    Container(
      color: Colors.amber,
    ),
    Container(
      color: Colors.blue[200],
    )
  ],
)

class ClearEffectScrollBehavior extends ScrollBehavior {
  @override
  Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) {
    return child;
  }
}

ReorderableListView

实现按住拖动排序的功能

ReorderableListView(
  onReorder: (int oldIndex, int newIndex) {
    print(oldIndex);
    print(newIndex);
  },
  children: List.generate(
    20,
    (index) => Container(
      key: UniqueKey(),
      color: Colors.orange,
      child: Text('index $index'),
    ),
  ),
)

SingleChildScrollerView

我们需要滚动的时候再出现滚动的行为,不需要滚动的时候不会出现任何可滚动的征兆。

它和其他滚动组件的区别就在于,内容如果没有超过页面宽或高的时候不会出现任何能够滚动的特征。(例如:安卓中的上滚动到容器边界会出现波浪效果,或者IOS上的拉伸效果)

我们应该在将合适的组件应用于合适的场景中,不能盲目使用ListView哦

深入了解Flutter滚动组件IOS上的的拉伸效果

ReorderableListView(
  onReorder: (int oldIndex, int newIndex) { // 拖动后的排序函数,这个排序需要自己手动来排序
    print(oldIndex);
    print(newIndex);
  },
  children: List.generate(
    20,
    (index) => Container(
      key: UniqueKey(),
      color: Colors.orange,
      child: Text('index $index'),
    ),
  ),
)

如何加入比特鹰

目前我们在招聘的岗位有:投研分析师,Python 后端研发工程师,前端研发工程师,AI研发工程师。

可以将简历投递到邮箱 join@bitying.cn