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
相关产品推荐
相关产品推荐

