Flutter滑动冲突处理——GestureDetector嵌套ListView

Flutter 中的 AnimatedPositioned 小部件:全面指南 是 Flutter 的动画库中的一个 widget,它根据给定的值动态地改变其子组件的位置。通常与Stackwidget 结合使用,因为它需要一个父组件来提供定位上下文。 阅读详情

哈喽,我是老刘

几年前分享了一篇GestureDetector嵌套ListView的文章

Flutter多控件滑动事件联动(滑动冲突处理) - 知乎 (zhihu.com)

由于文章中只给出了关键部位的代码,另外使用的技术也偏底层

所以很多同学私信我要完整的源码

这里把原先的方案整理一下,另外也给出完整的代码供大家参考

我们先一点一点来看这个问题

滑动关闭组件

首先大家一定在各种App中见过这个滑动关闭组件

就是手指向下滑动,组件跟随手指移动

手指抬起后组件滑出屏幕

我们先来实现这个组件,然后来讨论一下如果组件中的内容时一个ListView,要怎么处理

如果这个组件的内容时固定内容,不是ListView这样的可滚动组件

实现起来其实很简单

我这里直接放源码

import 'package:flutter/material.dart';

class CloseOnSwipeDownWidget extends StatefulWidget {
  final Widget child;

  const CloseOnSwipeDownWidget({
    Key? key,
    required this.child,
  }) : super(key: key);

  @override
  CloseOnSwipeDownWidgetState createState() => CloseOnSwipeDownWidgetState();
}

class CloseOnSwipeDownWidgetState extends State
    with TickerProviderStateMixin {
  double yOffset = 0.0;
  double initialPosition = 0.0;
  bool isAnimatingOut = false;
  int animTime = 0;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onVerticalDragDown: (details) {
        initialPosition = details.globalPosition.dy;
      },
      onVerticalDragUpdate: (details) {
        double updatedPosition = details.globalPosition.dy;
        double deltaY = updatedPosition - initialPosition;

        animTime = 0;

        setState(() {
          yOffset = yOffset + deltaY;
          initialPosition = updatedPosition;
        });
      },
      onVerticalDragEnd: (details) {
        animTime = 300;

        if (yOffset > 200) {
          // 触发滑出动画
          _startSlideOutAnimation();
        } else {
          // 触发返回原始位置的动画
          _startReturnToOriginalPositionAnimation();
        }
      },
      child: Stack(
        children: [
          AnimatedPositioned(  // 组件跟随手指位移,以及抬起手指后组件移动动画
            duration: Duration(milliseconds: animTime),
            curve: Curves.easeInOut,
            top: yOffset,
            left: 0,
            right: 0,
            child: widget.child,
            onEnd: () {
              if(isAnimatingOut) {
                Navigator.of(context).pop();
              }
            },
          ),
        ],
      ),
    );
  }

  // 开始滑出动画
  void _startSlideOutAnimation() {
    setState(() {
      isAnimatingOut = true;
      yOffset = MediaQuery.of(context).size.height;
    });
  }

  // 开始返回原始位置的动画
  void _startReturnToOriginalPositionAnimation() {
    setState(() {
      yOffset = 0.0;
    });
  }
}

这里的原理很简单

就是通过GestureDetector检测用户的滑动行为

并且通过AnimatedPositioned将用户手指的每一段位移转换成整个组件的移动

并且在最终手指抬起时,通过AnimatedPositioned的动画效果让组件移出屏幕或者复位

我们写一个页面来使用这个组件

class TestPage extends StatelessWidget {
  const TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: CloseOnSwipeDownWidget(
        child: Column(
          children: [
            SizedBox(
              height: MediaQuery.of(context).size.height - 500,
            ), // 让组件内容在页面底部
            Container(
              height: 500,
              color: Colors.blue,
              alignment: Alignment.bottomCenter,
              child: const Center(
                child: Text('我是内容'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

看一下效果

那么现在如果把传入的内容换成一个ListView

你会发现ListView内部的内容可以正常滑动

但是外部的GestureDetector无法响应用户的手势了

我们下面就来解决这个问题

GestureDetector嵌套ListView

首先我们要知道为什么嵌入ListView后GestureDetector会失效

这是Flutter的竞技场机制导致的

用户的一个滑动行为其实在底层时通过down、move和up三种事件完成的

当一个down事件出现后,如果手指按下的坐标位置有多个组件可以响应滑动事件

就是我们目前例子中的GestureDetector嵌套ListView的场景

Flutter框架会将这些组件都加入竞技场

然后通过一定的逻辑选择一个组件胜出

通常同类组件嵌套时最内层的组件胜出

胜出的组件会处理接下来的move和up事件,其它组件则不会继续处理这些事件了

在GestureDetector嵌套ListView的场景中

ListView最终胜出,所以后续的事件都交由ListView处理

而GestureDetector收不到后续的事件,也就不会响应用户的手势了

因此,我们解决这个问题的第一步就是要让GestureDetector在这种场景下也能收到后续的事件

决胜竞技场

其实要做到这一步很简单

GestureDetector真正处理用户手势事件的是内部的Recognizer

比如处理上下滑动的是VerticalDragGestureRecognizer

而Recognizer在竞技场失败后也可以单方面宣布自己胜出

这样即使在竞技场失败了,GestureDetector也能收到后续的手势事件

因此我们现定义一个单方面宣布胜出的Recognizer

class _MyVerticalDragGestureRecognizer extends VerticalDragGestureRecognizer {
  @override
  void rejectGesture(int pointer) {
    // 单方面宣布自己胜出
    acceptGesture(pointer);
  }
}

接下来,把这个Recognizer加入到GestureDetector中

这时就需要用到一个GestureDetector的底层组件RawGestureDetector

通过它我们可以自己指定需要的Recognizer

RawGestureDetector(
      gestures: {
        _MyVerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<
                _MyVerticalDragGestureRecognizer>(
            () => _MyVerticalDragGestureRecognizer(),
            (_MyVerticalDragGestureRecognizer recognizer) {
          recognizer
            ..onStart = (DragStartDetails details) {
              
            }
            ..onUpdate = (DragUpdateDetails details) {
              
            }
            ..onEnd = (DragEndDetails details) {
             
            };
        }),
      },
      child: ...
    );

这其中的onStart、onUpdate和onEnd 方法

就对应了GestureDetector中的onVerticalDragDown、onVerticalDragUpdate和onVerticalDragEnd方法

好的,到目前为止,我们已经解决了竞技场造成的只有ListView能收到手势事件的问题

但是这样的话就会造成用户滑动,内外两层组件都在移动的问题

因此,接下来我们就来解决如何两个滑动组件如何相互配合

监听ListView的滚动

ListView是ScrollView的子类

所有的ScrollView都会在滚动过程中沿着组件树向上发出各种滚动状态变化的通知

通过监听这些通知事件,就可以判断ScrollView的滚动状态

NotificationListener(  // 监听内部ListView的滑动变化
              onNotification: (ScrollNotification notification) {
                if (notification is OverscrollNotification && notification.overscroll < 0) {
                  // 用户向下滑动,ListView已经滑动到顶部,处理GestureDetector的滑动事件
                } else if (notification is ScrollUpdateNotification) {
                  // 用户在ListView中执行滑动动作,关闭外部GestureDetector的滑动处理
                } else {
                  
                }

                return false;
              },
              child:  //ListView
            ),

好的,把这些组合起来,完整的代码如下

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class CloseOnSwipeDownWidget2 extends StatefulWidget {
  final Widget child;

  const CloseOnSwipeDownWidget2({
    Key? key,
    required this.child,
  }) : super(key: key);

  @override
  CloseOnSwipeDownWidget2State createState() => CloseOnSwipeDownWidget2State();
}

class CloseOnSwipeDownWidget2State extends State
    with TickerProviderStateMixin {
  double yOffset = 0.0;
  double initialPosition = 0.0;
  bool isAnimatingOut = false;
  int animTime = 0;
  bool needDrag = true;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      gestures: {
        _MyVerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<
                _MyVerticalDragGestureRecognizer>(
            () => _MyVerticalDragGestureRecognizer(),
            (_MyVerticalDragGestureRecognizer recognizer) {
          recognizer
            ..onStart = (DragStartDetails details) {
              initialPosition = details.globalPosition.dy;
            }
            ..onUpdate = (DragUpdateDetails details) {
              if (!needDrag) {
                return;
              }
              double updatedPosition = details.globalPosition.dy;
              double deltaY = updatedPosition - initialPosition;

              animTime = 0;

              setState(() {
                yOffset = yOffset + deltaY;
                initialPosition = updatedPosition;
              });
            }
            ..onEnd = (DragEndDetails details) {
              animTime = 300;

              if (yOffset > 200) {
                // 触发滑出动画
                _startSlideOutAnimation();
              } else {
                // 触发返回原始位置的动画
                _startReturnToOriginalPositionAnimation();
              }
            };
        }),
      },
      child: Stack(
        children: [
          AnimatedPositioned(
            duration: Duration(milliseconds: animTime),
            curve: Curves.easeInOut,
            top: yOffset,
            left: 0,
            right: 0,
            child: NotificationListener(  // 监听内部ListView的滑动变化
              onNotification: (ScrollNotification notification) {
                if (notification is OverscrollNotification && notification.overscroll < 0) {
                  // 用户向下滑动,ListView已经滑动到顶部,处理GestureDetector的滑动事件
                  needDrag = true;
                } else if (notification is ScrollUpdateNotification) {
                  // 用户在ListView中执行滑动动作,关闭外部GestureDetector的滑动处理
                  needDrag = false;
                } else {
                }

                return false;
              },
              child: widget.child,
            ),
            onEnd: () {
              if (isAnimatingOut) {
                Navigator.of(context).pop();
              }
            },
          ),
        ],
      ),
    );
  }

  // 开始滑出动画
  void _startSlideOutAnimation() {
    setState(() {
      isAnimatingOut = true;
      yOffset = MediaQuery.of(context).size.height;
    });
  }

  // 开始返回原始位置的动画
  void _startReturnToOriginalPositionAnimation() {
    setState(() {
      yOffset = 0.0;
    });
  }
}

class _MyVerticalDragGestureRecognizer extends VerticalDragGestureRecognizer {
  bool needDrag = true;

  @override
  void rejectGesture(int pointer) {
    // 单方面宣布自己胜出
    acceptGesture(pointer);
  }
}

简单来说就是通过needDrag来判断外部GestureDetector是否跟随用户手势移动

needDrag的值基于监听ListView的状态

当ListView已经滑动到顶部,就开始响应用户的手势动作

下面是使用这个组件的代码

class TestPage2 extends StatelessWidget {
  const TestPage2({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: CloseOnSwipeDownWidget2(
        child: Column(
          children: [
            SizedBox(
              height: MediaQuery.of(context).size.height - 500,
            ), // 让组件内容在页面底部
            Container(
              height: 500,
              color: Colors.blue,
              child: ListView.builder(
                  itemCount: 20,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text('index $index'),
                    );
                  }),
            ),
          ],
        ),
      ),
    );
  }
}

实现效果如下

好了,关于手势组件嵌套的问题就先聊到这里

如果看到这里的同学有学习Flutter的兴趣,欢迎联系老刘,我们互相学习。

点击免费领老刘整理的《Flutter开发手册》,覆盖90%应用开发场景。

可以作为Flutter学习的知识地图。

覆盖90%开发场景的《Flutter开发手册》 (qq.com)

【Flutter】解决多级列表嵌套滑动冲突方案选择 本文介绍了 Transition 组件的原理与实现。它的核心原理可以总结为:在DOM元素挂载时,将动效附加到DOM元素上,而在卸载DOM元素之前,等到附加到DOM元素上的动效执行完成后再卸载DOM元素。在实现动效的过程中,可以将其分为 beforeEnter、enter、leave 等阶段,在不同的阶段执行不同的操作。 阅读详情

相关推荐

Flutter手势检测:GestureDetector原理与实战

手势检测是现代移动应用开发中的基础交互技术,通过解析用户的触摸、滑动等操作实现直观的UI控制。在Flutter框架中,GestureDetector作为核心组件,封装了底层指针事件系统,提供点击、拖动、缩放等高级手势识别能力。其工作原理基于命中测试和手势竞技场机制,确保准确的事件分发。GestureDetector特别适用于实现图片点击、元素拖拽等常见交互场景,同时支持通过RawGestureDetector进行性能优化。结合Flutter的热重载特性,开发者可以快速迭代手势交互设计,提升应用用户体验。

weixin_34364071的博客 374

一文搞懂Flutter的手势事件——事件分发与冲突处理详解

本文字数:43617字预计阅读时间:110分钟前言之前有两篇文章都围绕着runApp()进行展开,讲解了布局绘制的详细过程。https://www.jianshu.com/p/2ef749ff4d40/https://www.jianshu.com/p/f37f8da235ec那么接下来我们想详细的说一说Flutter是如何处理手势事件的。本文将通过源码详细分析Flutter的事件分发与冲突处理...

SOHU_TECH的博客 1486

Flutter生产级柱状图实战:charts_flutter性能优化与深色模式适配

柱状图是数据可视化中最基础的图表类型,其核心在于将离散数据映射为视觉长度,依赖坐标轴缩放、像素对齐与状态同步等底层渲染原理。在Flutter中,charts_flutter虽提供标准BarChart组件,但默认实现未考虑生产环境对性能、可访问性与跨平台一致性的严苛要求。尤其在深色模式适配、点击交互穿透、大数据量重绘及内存泄漏防控等方面存在系统性短板。本文聚焦真实业务场景——电商销售分析、IoT设备监控与教育数据看板,结合charts_flutter的Canvas渲染机制与Flutter Widget树生命周

weixin_30258901的博客 322

flutter中column中嵌套listview有啥注意的

下面是一个示例代码,展示如何在 Flutter 中实现嵌套。组件来使中间部分的子组件占据剩余空间,并设置了一个高度为。的布局比较常见,但需要注意上述几点细节。在上面的示例代码中,我们创建了一个。在 Flutter 中,将。组件,它包含了一个嵌套的。参数来设置滚动方向为横向。在 Flutter 中实现。的顶部标题栏和底部页脚。

qq_28563283的博客 3048

《Flutter 控件大全》第十四个:AnimatedPositioned

如果你对Flutter还有疑问或者技术方面的疑惑,欢迎加入Flutter交流群(微信:laomengit)。 同时也欢迎关注我的Flutter公众号【老孟程序员】,公众号首发Flutter的相关内容。 Flutter地址:http://laomengit.com 里面包含160多个组件的详细用法。 AnimatedPositioned是一个隐式的动画组件,提供动态改变位置的动画组件,用法如...

老孟Flutter 2041

B站李沐讲论文笔记AlexNet

B站李沐讲论文笔记AlexNet

夏知识不进脑子薇的博客 790

flutter开发实战-手势Gesture与ListView滚动竞技场的可滑动关闭组件

flutter开发实战-手势Gesture与ListView滚动竞技场的可滑动关闭组件最近看到了一个插件,实现一个可滑动关闭组件。滑动关闭组件即手指向下滑动,组件随手指移动,当移动一定位置时候,手指抬起后组件滑出屏幕。

一名开发者 2002

【Python爬虫案例教学】超简洁代码采集原神所有角色信息

(。・∀・)ノ゙嗨 大家好,这里是池鱼

xiaoyuan_____的博客 2421

Flutter Engine手势冲突解决:嵌套滚动与事件拦截

在Flutter应用开发中,手势冲突是常见问题,尤其在实现复杂UI交互时。典型场景包括: - 列表项内部包含可滑动组件(如卡片内的横向滑动与列表纵向滑动冲突) - 自定义下拉刷新与列表滚动事件争夺 - 地图控件与覆盖层手势交互干扰 Flutter Engine通过**事件分发机制**处理用户输入,当多个组件同时监听相似手势时,就可能出现冲突。核心问题在于:**如何准确识别用户意图并将事件传递给正...

gitblog_00811的博客 831

对于基本的捕鱼游戏设计思路(五)——鱼

今天讲捕鱼游戏里鱼的部分,也是比较关键的一部分。 一步一步来,先分析游戏,首先鱼是从屏幕外生成,然后它有个移动的动作,而且分为不同的类型。 然后就可以进入代码部分,首先设置一个计时器,控制时间生成鱼,而鱼分种类,所以就用到随机函数,随机输出一个值,传入switch语句,从而生成不同的鱼。 void GameScene::xiaoyuupdate(float dt){ Size visibl

Cineze的博客 1万+

别再手动调参了!用Optuna+PyTorch搞定Transformer时序预测超参数(附完整代码)

本文详细介绍了如何利用Optuna和PyTorch实现Transformer时序预测模型的自动化超参数调优。通过贝叶斯优化技术,显著提升单变量时序预测的效率和准确性,并附有完整代码实现。文章涵盖模型架构设计、数据预处理、Optuna调参实战及生产环境部署建议,为开发者提供一站式解决方案。

weixin_33704234的博客 579

OpenHarmony Flutter列表手势冲突与性能优化实战

在跨端应用开发中,触摸事件分发与手势竞技场决定滑动是否跟手,构建、布局与光栅化耗时决定列表能否满帧。一次触摸会经过系统输入分发、Flutter指针事件、命中测试与竞技场裁决;一次绘制则跨越构建、布局和渲染通道。理解这些原理,可用于商品流、资讯列表、长列表分页、左滑删除和嵌套滚动等场景,定位斜向滑动误判、左滑与点击抢权、原生组件吞事件、itemBuilder隐性开销及图片解码掉帧。围绕Flutter在OpenHarmony/鸿蒙真机上的列表手势冲突与性能优化,拆解五类高频冲突和十二条改动,并结合帧率与耗时对比

weixin_34268843的博客 459

Supervisor 安装与使用

一、Supervisor 介绍 Supervisor 是一个用 Python 编写的进程管理工具,它可以用于监控和控制类 UNIX 操作系统上的多个进程。它是一个客户端/服务器系统,其中 Supervisor 的服务器端称为 supervisord,负责启动管理的子进程、响应客户端命令、重启崩溃或退出的子进程、记录子进程的 stdout 和 stderr 输出,以及处理子进程生命周期中的事件。客...

疯子丶pony的博客 3864

Flutter手势机制详解:GestureDetector与InkWell的选用与避坑

在移动应用开发中,触摸事件是交互的基础,而Flutter提供了一套完整的手势竞技场机制来识别和处理手指的按下、移动与抬起。无论是新手还是资深工程师,在构建可点击组件时,都会面临GestureDetector与InkWell的选择困惑:前者功能全面但缺乏默认视觉反馈,后者自带Material水波动画却又依赖祖先组件。理解命中测试、手势竞技场以及onTap、onDoubleTap等回调的时序,是解决点击无响应、水波不显示、手势被抢占等高频问题的关键。从列表卡片到拖拽排序,正确选用手势组件能显著提升交互用户体验。

weixin_31155097的博客 228

基于 Python + Flask + Echarts 的疫情监控系统

基于 Python + Flask + Echarts 的疫情监控系统

743

爬虫逆向:Hook 技术原理与实战

Hook 技术​(钩子技术)是一种通过拦截和修改程序执行流程的技术手段。它允许开发者在目标程序的特定位置插入自定义代码,以改变程序的默认行为或获取运行时信息。Hook 技术广泛应用于调试、逆向工程、性能分析、安全防护等领域。Hook 技术在爬虫逆向中非常有用,能够有效获取和修改目标程序的数据。通过合理使用 Hook 工具和技术,可以显著提升爬虫的效率和成功率。但使用时需注意法律和道德问题,确保行为合规。

数据知道的博客 1万+

Flutter for OpenHarmony 实战:HarmonyOS ArkTS API 24 列表项滑动出现的交互动效

本项目通过自定义实现列表项滑动交互动效,深入展示了 Flutter 手势系统和动画系统的核心原理:首先是自定义手势交互的实现。项目使用 GestureDetector 监听水平拖动手势,实时更新偏移量,并在手势结束时自动判断展开或收起。这种对手势的精细控制是构建自定义交互组件的基础。其次是 Flutter 动画系统的应用。项目使用 AnimationController + Tween + CurvedAnimation 的标准动画模式,实现了平滑的过渡效果。

2301_79516858的博客 167

Qt软件开发-Qt编译zlib完成文件压缩解压(win10)

在软件开发中进行有需求需要将生成的一些文件打包上传到服务器,或者从服务器下载压缩包下来内部解压。或者自己做一些打包工具,那么使用zlib开源就可以很方便的完成。接下来介绍在zlib在windows下如何利用Qt进行编译,调用,介绍mingw、msvc,32/64位编译办法,完成zip文件打包生成例子。可以单文件压缩打包,多文件压缩打包,目录压缩打包等等。

2217

Flutter手势系统与冲突处理实战

本文系统讲解了Flutter手势交互的核心原理与实战技巧。

linwenglong7155的博客 549

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【Flutter入门练中学】第10课:手势与交互——点击、拖拽、缩放指南

本文系统讲解 Flutter 手势体系,涵盖从指针事件到手势识别的完整流程。重点掌握 GestureDetector 的各类回调(点击、双击、长按、拖动、缩放),理解 InkWell 的水波纹反馈机制及其与 GestureDetector 的差异。通过 Draggable/DragTarget 实现拖拽放置,利用 InteractiveViewer 完成缩放平移,深入解析手势竞技场与冲突解决策略。结合实战案例(拖拽排序、滑动卡片、长按菜单等),实现“题目→答案→解读”的练中学模式,全面提升交互开发能力。

jackchuanqi的博客 221

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Flutter GestureDetector 失灵原因与手势系统深度解析

GestureDetector 是 Flutter 中实现用户交互的核心组件,其本质是将底层 PointerEvent 转换为 tap、longPress 等语义化手势的识别器。它依赖命中测试(Hit Testing)决定事件接收资格,并通过手势竞技场(Gesture Arena)协调多个识别器的竞争关系。这种设计保障了跨平台行为一致性,但也带来 onTap 失灵、onLongPress 不触发等典型问题。理解 hitTestBehavior、behavior 配置及 TapGestureRecognize

weixin_29001327的博客 199

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Flutter Widget 归类汇总:从最常用组件到源码原理的完整实践指南

本篇技术指南以 YCBlogs 仓库中 [flutter/02.基础知识/01.Widget归类汇总.md](https://link.gitcode.com/i/e1e88566d8519cad5a469ab81e3f64e4) 为骨架,系统梳理 Flutter 中 Widget 的九大分类:最常用、基础、布局、容器、滚动、弹窗反馈、常见场景、功能型与手势组件。在逐类讲解使用方式的同时,结合仓库

gitblog_00320的博客 424

Flutter在OpenHarmony上实现高性能表格组件:方案选型与踩坑实践

移动跨端开发中,表格是高频使用的数据展示组件,尤其在鸿蒙生态设备上,如何兼顾多端一致性与渲染性能成为工程难点。Flutter自绘引擎与OpenHarmony的适配能力,为复杂表格提供了新的技术路径。在日常实践中,开发者常遇到列表性能瓶颈、数据解析阻塞UI、依赖库兼容性等问题:通过Isolate隔离耗时操作、采用按需构建与统一文本行高,能有效提升表格滚动流畅度与内存表现。本文从表格组件的技术选型出发,对比原生DataTable与第三方库的优劣,重点阐述手写轻量表格的布局原理、滚动同步机制及排序筛选交互,并结合

weixin_34214500的博客 338

flutter学习笔记

1.跨平台移动UI框架2.与现有的代码一起工作(可以直接嵌入到原生代码中或直接把原生代码嵌入到自己的代码中运行)3. 完全免费、开源。

haoxuhong的博客 8246

Flutter for OpenHarmony 实战:基于HarmonyOS API 24 卡片布局与阴影效果

本项目实现了一套功能完善的卡片组件库,包括基础卡片、带图卡片和卡片网格布局三个组件,覆盖了卡片布局的主要使用场景。项目深入探索了 Flutter 中阴影、圆角、边框等视觉效果的实现方式,展示了如何通过 Container 的 BoxDecoration 创造丰富的视觉效果。在组件设计方面,项目体现了良好的组合式架构思想。基础卡片组件提供核心的视觉效果能力,带图卡片组件通过组合基础卡片构建特定的内容结构,卡片网格组件提供批量布局能力。

2301_79516858的博客 411

Flutter for OpenHarmony深度定制:HarmonyOS ArkTS API 24 仿原生系统的侧滑删除与批量操作列表

本项目通过实现侧滑删除与批量操作列表,展示了 Flutter 中列表交互开发的多个高级技巧:首先是组件的泛型化设计。通过泛型参数,组件可以适配任意业务数据类型,大大提高了复用性。这是 Flutter 中设计可复用组件的重要方法。其次是 Dismissible 组件的深入应用。项目不仅实现了基本的侧滑删除,还通过 confirmDismiss 回调的巧妙使用,实现了自定义删除确认逻辑和与外部数据的协调。第三是多模式交互的设计。

2301_79516858的博客 381
下一篇: Flutter在一个预览界面中同时实现OCR和二维码识别
程序员老刘·
博客等级 码龄3年 622粉丝 143原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值