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

Flutter:根据ListView内可见性更新Widget,实现滚动计时器效果

实现垂直滚动计时器(带动态模糊效果)

核心思路

通过ScrollController监听ListView滚动位置,计算每个列表项与视口中心的偏移量,根据偏移比例动态调整项的透明度、模糊度和缩放比例,实现中心内容清晰、边缘内容渐变模糊的视觉效果。

具体实现步骤

1. 初始化控制器与状态变量

late ScrollController _scrollController;
double _viewportHeight = 0; // 记录ListView视口高度
final double _itemHeight = 60; // 单个数字项的固定高度

在initState中完成控制器初始化并添加滚动监听:

@override
void initState() {
  super.initState();
  _scrollController = ScrollController()
    ..addListener(() {
      setState(() {}); // 滚动时触发UI重绘
    });
}

2. 计算列表项的视觉参数

先计算列表项中心与视口中心的垂直偏移:

double _calculateCenterOffset(int index) {
  final itemTop = index * _itemHeight - _scrollController.offset;
  final viewportCenterY = _viewportHeight / 2;
  // 返回项中心与视口中心的距离绝对值
  return (itemTop + _itemHeight / 2 - viewportCenterY).abs();
}

根据偏移距离计算样式参数:

Map<String, double> _getItemVisualStyle(int index) {
  final offset = _calculateCenterOffset(index);
  const maxEffectRange = 80.0; // 超过此距离的项完全模糊
  
  if (offset > maxEffectRange) {
    return {
      'opacity': 0.3,
      'blur': 4.0,
      'scale': 0.8
    };
  }
  
  final ratio = offset / maxEffectRange;
  return {
    'opacity': 1 - ratio * 0.7,
    'blur': ratio * 4.0,
    'scale': 1 - ratio * 0.2
  };
}

3. 构建带动态效果的ListView

用LayoutBuilder获取视口高度,再渲染列表项:

@override
Widget build(BuildContext context) {
  return LayoutBuilder(
    builder: (context, constraints) {
      _viewportHeight = constraints.maxHeight;
      return ListView.builder(
        controller: _scrollController,
        itemCount: 60, // 计时器数字范围0-59
        itemExtent: _itemHeight,
        itemBuilder: (context, index) {
          final style = _getItemVisualStyle(index);
          return Center(
            child: BackdropFilter(
              filter: ImageFilter.blur(sigmaX: style['blur']!, sigmaY: style['blur']!),
              child: Opacity(
                opacity: style['opacity']!,
                child: Transform.scale(
                  scale: style['scale']!,
                  child: Text(
                    '$index',
                    style: const TextStyle(
                      fontSize: 32,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      );
    },
  );
}

4. 优化:滚动结束后自动居中选中项

添加自动对齐逻辑,让滚动停止时中心项自动对齐视口中心:

void _autoAlignCenterItem() {
  final currentOffset = _scrollController.offset;
  final closestIndex = (currentOffset + _viewportHeight/2) ~/ _itemHeight;
  final targetOffset = closestIndex * _itemHeight - (_viewportHeight/2 - _itemHeight/2);
  
  _scrollController.animateTo(
    targetOffset,
    duration: const Duration(milliseconds: 200),
    curve: Curves.easeOut,
  );
}

修改滚动监听,在滚动停止时触发对齐:

_scrollController.addListener(() {
  if (!_scrollController.position.isScrollingNotifier.value) {
    _autoAlignCenterItem();
  }
  setState(() {});
});

关键注意事项

  • BackdropFilter需要配合明确的组件边界(比如父容器设置clipBehavior: Clip.hardEdge),避免模糊效果溢出
  • 可通过调整maxEffectRange和样式比例参数,适配不同的视觉需求
  • 若列表项高度不固定,需修改_calculateCenterOffset中的高度计算逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:15:46