news 2026/10/9 7:48:10

Android学Flutter学习笔记 第三节 Android视角认知Flutter(触摸事件,List,Text,Input)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android学Flutter学习笔记 第三节 Android视角认知Flutter(触摸事件,List,Text,Input)

序言

认识flutter已经到了第三节。我们了解到了flutter的启动入口,weight类别和常见的类型,页面之间的跳转,资源文件的配置,如何实现weight的排列、以及如何和Android互动,下面我们继续已Android视角认识flutter中的细节。

手势检测和触摸事件处理

如何在 Flutter 中给一个组件添加 onClick 监听器?

在安卓系统中,你可以通过调用 “setOnClickListener” 方法,将 onClick(点击事件)附加到按钮等视图上。

在 Flutter 中,有两种添加触摸监听器的方法:
1、如果微件(Widget)支持事件检测,可以向其传递一个函数,并在该函数中进行处理。例如,ElevatedButton 具有 onPressed 参数:

@overrideWidgetbuild(BuildContext context){returnElevatedButton(onPressed:(){developer.log('click');},child:constText('Button'),);}

2、如果 Widget 不支持事件检测,请将该 widget 包裹在 GestureDetector 中,并向 onTap 参数传递一个函数。

classSampleTapApp extends StatelessWidget{constSampleTapApp({super.key});@overrideWidgetbuild(BuildContext context){returnScaffold(body:Center(child:GestureDetector(onTap:(){developer.log('tap');},child:constFlutterLogo(size:200),),),);}}

如何处理小部件上的其他手势?

使用 GestureDetector,你可以监听各种各样的手势,例如:
Tap:
onTapDown - 一个可能触发点击操作的指针已在屏幕特定位置接触屏幕。
onTapUp - 一个触发点击操作的指针已在屏幕特定位置停止接触屏幕。
onTap - 点击操作已发生。
onTapCancel - 先前触发onTapDown的指针将不会导致点击操作。



Double tap
onDoubleTap 用户快速连续两次点击了屏幕上的同一位置

Long press
onLongPress 指针长时间与屏幕上的同一位置保持接触。

Vertical drag
onVerticalDragStart - 指针已接触屏幕并可能开始垂直移动。
onVerticalDragUpdate - 与屏幕接触的指针在垂直方向上进一步移动。
onVerticalDragEnd - 先前与屏幕接触并垂直移动的指针已不再接触屏幕,且在停止接触时具有特定速度。

Horizontal drag
onHorizontalDragStart - 指针已接触屏幕,并可能开始水平移动。
onHorizontalDragUpdate - 与屏幕接触的指针在水平方向上已进一步移动。
onHorizontalDragEnd - 先前与屏幕接触并水平移动的指针已不再接触屏幕,且在停止接触时具有特定速度。

下面是一个双击和旋转动画结合的例子

classSampleApp extends StatefulWidget{constSampleApp({super.key});@overrideState<SampleApp>createState()=>_SampleAppState();}class_SampleAppState extends State<SampleApp>with SingleTickerProviderStateMixin{late AnimationController controller;late CurvedAnimation curve;@overridevoidinitState(){super.initState();controller=AnimationController(vsync:this,duration:constDuration(milliseconds:2000),);curve=CurvedAnimation(parent:controller,curve:Curves.easeIn);}@overrideWidgetbuild(BuildContext context){returnScaffold(body:Center(child:GestureDetector(onDoubleTap:(){if(controller.isCompleted){controller.reverse();}else{controller.forward();}},child:RotationTransition(turns:curve,child:constFlutterLogo(size:200),),),),);}}

ListView

Flutter 中 ListView 的替代方案是什么?

Flutter 中与 ListView 等效的组件依然是ListView!

在 Android 的 ListView 中,你需要创建一个适配器并将其传入 ListView,ListView 会根据适配器返回的内容来渲染每一行。不过,你必须确保对行进行回收,否则会出现各种奇怪的视觉故障和内存问题。

由于 Flutter 的不可变组件模式,你可以将一个组件列表传递给 ListView,而 Flutter 会负责确保滚动既快速又流畅。

import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleApp extends StatelessWidget{constSampleApp({super.key});// This widget is the root of your application.@overrideWidgetbuild(BuildContext context){returnMaterialApp(title:'Sample App',theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),),home:constSampleAppPage(),);}}classSampleAppPage extends StatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageState extends State<SampleAppPage>{@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView(children:_getListData()),);}List<Widget>_getListData(){List<Widget>widgets=[];for(int i=0;i<100;i++){widgets.add(Padding(padding:constEdgeInsets.all(10),child:Text('Row $i')),);}returnwidgets;}}

如何给item设置点击

在 Android 中,ListView 有一个用于查明哪个条目被点击的方法,即 “onItemClickListener”。在 Flutter 中,使用传入的小部件所提供的触摸处理。

import'dart:developer'asdeveloper;import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleApp extends StatelessWidget{constSampleApp({super.key});// This widget is the root of your application.@overrideWidgetbuild(BuildContext context){returnMaterialApp(title:'Sample App',theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),),home:constSampleAppPage(),);}}classSampleAppPage extends StatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageState extends State<SampleAppPage>{@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView(children:_getListData()),);}List<Widget>_getListData(){List<Widget>widgets=[];for(int i=0;i<100;i++){widgets.add(GestureDetector(onTap:(){developer.log('row tapped');},child:Padding(padding:constEdgeInsets.all(10),child:Text('Row $i'),),),);}returnwidgets;}}

如何动态更新 ListView?

在安卓系统上,你需要更新适配器并调用 notifyDataSetChanged 方法。
在 Flutter 中,如果你要在 setState () 里更新 widget 列表,你会很快发现数据在视觉上并没有发生变化。这是因为当调用 setState () 时,Flutter 渲染引擎会查看 widget 树,判断是否有内容发生了改变。当它检查到你的 ListView 时,会执行一个 == 检查,然后判定这两个 ListView 是相同的。既然没有变化,也就不需要进行更新了。

要以简单的方式更新你的 ListView,请在 setState () 中创建一个新的 List,并将数据从旧列表复制到新列表。虽然这种方法很简单,但不建议用于大型数据集,如下一个示例所示。

import'dart:developer'asdeveloper;import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleApp extends StatelessWidget{constSampleApp({super.key});// This widget is the root of your application.@overrideWidgetbuild(BuildContext context){returnMaterialApp(title:'Sample App',theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),),home:constSampleAppPage(),);}}classSampleAppPage extends StatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageState extends State<SampleAppPage>{List<Widget>widgets=[];@overridevoidinitState(){super.initState();for(int i=0;i<100;i++){widgets.add(getRow(i));}}@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView(children:widgets),);}WidgetgetRow(int i){returnGestureDetector(onTap:(){setState((){widgets=List.from(widgets);widgets.add(getRow(widgets.length));developer.log('row $i');});},child:Padding(padding:constEdgeInsets.all(10),child:Text('Row $i')),);}}

推荐的、高效且有效的构建列表的方法是使用 ListView.Builder。当你有一个动态列表或包含大量数据的列表时,这种方法非常好用。它本质上相当于 Android 上的 RecyclerView,会自动为你回收列表元素:

import'dart:developer'asdeveloper;import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleApp extends StatelessWidget{constSampleApp({super.key});// This widget is the root of your application.@overrideWidgetbuild(BuildContext context){returnMaterialApp(title:'Sample App',theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),),home:constSampleAppPage(),);}}classSampleAppPage extends StatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageState extends State<SampleAppPage>{List<Widget>widgets=[];@overridevoidinitState(){super.initState();for(int i=0;i<100;i++){widgets.add(getRow(i));}}@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView.builder(itemCount:widgets.length,itemBuilder:(context,position){returngetRow(position);},),);}WidgetgetRow(int i){returnGestureDetector(onTap:(){setState((){widgets.add(getRow(widgets.length));developer.log('row $i');});},child:Padding(padding:constEdgeInsets.all(10),child:Text('Row $i')),);}}

不要创建 “ListView”,而是创建一个 ListView.builder,它接受两个关键参数:列表的初始长度和一个 ItemBuilder 函数。

ItemBuilder 函数类似于 Android 适配器中的 getView 函数,它接收一个位置参数,并返回你希望在该位置渲染的行。

最后,但最重要的是,注意 onTap () 函数不再重新创建列表,而是向列表中添加元素

Text

我如何在我的文本部件上设置自定义字体?

在 Android SDK(截至 Android O 版本)中,你需要创建一个字体资源文件,并将其传入 TextView 的 FontFamily 参数中。

在 Flutter 中,将字体文件放在一个文件夹中,并在 pubspec.yaml 文件中引用它,类似于导入图片的方式。

fonts:-family:MyCustomFont fonts:-asset:fonts/MyCustomFont.ttf-style:italic
@overrideWidgetbuild(BuildContext context){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:constCenter(child:Text('Thisisa custom font text',style:TextStyle(fontFamily:'MyCustomFont'),),),);}

我该如何设置我的文本小部件的样式?

除了字体,你还可以自定义文本组件上的其他样式元素。文本组件的 style 参数接受一个 TextStyle 对象,在该对象中,你可以自定义许多参数,例如:
color
decoration
decorationColor
decorationStyle
fontFamily
fontSize
fontStyle
fontWeight
hashCode
height
inherit
letterSpacing
textBaseline
wordSpacing


效果如下:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 4:13:36

技术文档即营销:Fun-ASR手册中自然嵌入商品链接

技术文档即营销&#xff1a;Fun-ASR手册中自然嵌入商品链接 在AI模型日益“卷”性能的今天&#xff0c;一个有趣的现象正在发生——技术文档本身&#xff0c;正悄悄变成最有效的营销工具。 钉钉联合通义实验室推出的 Fun-ASR 语音识别系统&#xff0c;没有大张旗鼓地投放广告&a…

作者头像 李华
网站建设 2026/10/8 2:00:50

腾讯AI Lab评估:WeNet生态外的新选择出现

腾讯AI Lab评估&#xff1a;WeNet生态外的新选择出现 在语音识别技术逐渐渗透进日常办公、教育记录和医疗文档的今天&#xff0c;一个现实问题摆在开发者面前&#xff1a;如何让高精度ASR系统不再只是科研团队手中的“重型武器”&#xff0c;而是普通用户也能轻松上手的实用工具…

作者头像 李华
网站建设 2026/10/5 2:32:58

asana任务分配:通过语音指派工作给团队成员

通过语音指派工作&#xff1a;构建智能任务分配系统 在现代企业中&#xff0c;一个常见的场景是&#xff1a;会议刚结束&#xff0c;管理者站在白板前口述一连串待办事项——“王芳负责整理Q2数据&#xff0c;周三前提交&#xff1b;李强跟进客户B的合同修改&#xff0c;周五下…

作者头像 李华
网站建设 2026/10/7 5:48:08

kindle标注同步:语音笔记与电子书内容位置绑定

Kindle 标注同步&#xff1a;语音笔记与电子书内容位置绑定 在数字阅读日益普及的今天&#xff0c;我们获取知识的方式早已不再局限于“看”这一种感官。然而&#xff0c;大多数电子书阅读器仍停留在传统的文本交互层面——翻页、标注、打星、写批注&#xff0c;每一步都需要手…

作者头像 李华
网站建设 2026/10/6 22:37:13

B站视频脚本:手把手教你部署Fun-ASR语音识别系统

手把手教你部署 Fun-ASR 语音识别系统 在内容创作者、教育从业者和企业团队越来越依赖语音转文字技术的今天&#xff0c;一个稳定、高效又易于上手的本地化语音识别工具显得尤为珍贵。市面上虽然有不少云服务 API 可用&#xff0c;但隐私顾虑、网络延迟和持续调用成本始终是绕不…

作者头像 李华
网站建设 2026/10/4 12:11:22

mybatisplus无关?但你可能需要它来存储识别记录

Fun-ASR 中的识别记录存储与语音处理机制解析 在如今本地化 AI 工具日益普及的背景下&#xff0c;一个语音识别系统是否“好用”&#xff0c;早已不再仅仅取决于模型本身的准确率。真正决定用户体验的关键&#xff0c;往往藏在那些看似不起眼的功能背后——比如&#xff0c;你上…

作者头像 李华