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

Flutter如何实现水平滑动切换为图片应用颜色滤镜

核心问题分析

你当前代码无法看到滤镜效果的根本原因是:ColorFiltered组件的滤镜仅会作用于自身的子组件树,你将空的透明/半透明Container作为它的子组件,滤镜自然无法作用到Stack下层的背景图上。


解决方案

方案1:PageView单页对应单滤镜图(实现最简)

直接在每个PageView的Item中放置套了对应滤镜的图片,Flutter会自动缓存同路径的FileImage,不会出现重复加载的性能问题。
修改后的核心代码如下:

class _PageFiltersState extends State<PageFilters> {
  FilterList filters = FilterList();
  // 新增PageController用于后续获取选中滤镜
  final PageController _pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: PageView.builder(
        controller: _pageController,
        physics: const ClampingScrollPhysics(),
        itemCount: filters.list.length,
        itemBuilder: (context,index) {
          return ColorFiltered(
            colorFilter: ColorFilter.matrix(filters.list[index].matrix),
            child: Image.file(File(widget.file), fit: BoxFit.cover),
          );
        },
      ),
    );
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }
}

此方案滑动切换时滤镜为直接跳变效果,不需要额外逻辑处理。


方案2:动态插值计算滤镜矩阵(贴合演示的渐变切换效果)

如果需要实现滑动过程中滤镜平滑过渡的效果,可以监听PageView的滚动偏移,对相邻两个滤镜的矩阵做数值插值,动态生成当前的滤镜矩阵,仅用一个ColorFiltered作用在顶层即可:

class _PageFiltersState extends State<PageFilters> {
  FilterList filters = FilterList();
  late final PageController _pageController;
  // 存储当前实时使用的滤镜矩阵
  List<double> _currentMatrix = [];

  @override
  void initState() {
    super.initState();
    _currentMatrix = filters.list.first.matrix;
    _pageController = PageController()
    ..addListener(() {
      final page = _pageController.page ?? 0;
      final currentPageIndex = page.floor();
      final nextPageIndex = currentPageIndex + 1;
      final progress = page - currentPageIndex;
      if (nextPageIndex >= filters.list.length) return;
      // 矩阵插值计算
      final currentMatrix = filters.list[currentPageIndex].matrix;
      final nextMatrix = filters.list[nextPageIndex].matrix;
      final newMatrix = <double>[];
      for (int i = 0; i < currentMatrix.length; i++) {
        newMatrix.add(currentMatrix[i] * (1 - progress) + nextMatrix[i] * progress);
      }
      setState(() {
        _currentMatrix = newMatrix;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: [
          // 底层原图
          Image.file(File(widget.file), fit: BoxFit.cover),
          // 顶层滤镜层
          ColorFiltered(
            colorFilter: ColorFilter.matrix(_currentMatrix),
            child: Container(
              color: Colors.white.withOpacity(0.1),
              width: double.infinity,
              height: double.infinity,
            ),
          ),
          // 透明PageView仅用于处理滑动手势,不需要展示内容
          PageView.builder(
            controller: _pageController,
            physics: const ClampingScrollPhysics(),
            itemCount: filters.list.length,
            itemBuilder: (context,index) => const SizedBox.expand(),
          )
        ],
      ),
    );
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }
}

此方案可以实现和你演示效果一致的滑动时滤镜平滑过渡效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 05:36:02