当前位置: 首页 > news >正文

深入浅出javaweb实战上海seo顾问推推蛙

深入浅出javaweb实战,上海seo顾问推推蛙,成都网站设计策划免费,模版网站建设步骤详解1.原始指针事件处理 一次完整的事件分为三个阶段:手指按下、手指移动、和手指抬起,而更高级别的手势(如点击、双击、拖动等)都是基于这些原始事件的。 Listener 组件 Flutter中可以使用Listener来监听原始触摸事件 Listener({…

1.原始指针事件处理

一次完整的事件分为三个阶段:手指按下、手指移动、和手指抬起,而更高级别的手势(如点击、双击、拖动等)都是基于这些原始事件的。

Listener 组件

Flutter中可以使用Listener来监听原始触摸事件

Listener({Key key,this.onPointerDown, //手指按下回调this.onPointerMove, //手指移动回调this.onPointerUp,//手指抬起回调this.onPointerCancel,//触摸事件取消回调this.behavior = HitTestBehavior.deferToChild, //先忽略此参数,后面小节会专门介绍Widget child
})

示例:手指在一个容器上移动时查看手指相对于容器的位置

class _PointerMoveIndicatorState extends State<PointerMoveIndicator> {PointerEvent? _event;@overrideWidget build(BuildContext context) {return Listener(child: Container(alignment: Alignment.center,color: Colors.blue,width: 300.0,height: 150.0,child: Text('${_event?.localPosition ?? ''}',style: TextStyle(color: Colors.white),),),onPointerDown: (PointerDownEvent event) => setState(() => _event = event),onPointerMove: (PointerMoveEvent event) => setState(() => _event = event),onPointerUp: (PointerUpEvent event) => setState(() => _event = event),);}
}

PointerEvent常用属性:

  • position:它是指针相对于当对于全局坐标的偏移。
  • localPosition: 它是指针相对于当对于本身布局坐标的偏移。
  • delta:两次指针移动事件(PointerMoveEvent)的距离。
  • pressure:按压力度,如果手机屏幕支持压力传感器(如iPhone的3D Touch),此属性会更有意义,如果手机不支持,则始终为1。
  • orientation:指针移动方向,是一个角度值。

忽略指针事件

不想让某个子树响应PointerEvent的话,我们可以使用IgnorePointer和AbsorbPointer,AbsorbPointer本身是可以接收指针事件的(但其子树不行),而IgnorePointer不可以

Listener(child: AbsorbPointer(child: Listener(child: Container(color: Colors.red,width: 200.0,height: 100.0,),onPointerDown: (event)=>print("in"),),),onPointerDown: (event)=>print("up"),
)

点击Container时,由于它在AbsorbPointer的子树上,所以不会响应指针事件,所以日志不会输出"in",
但AbsorbPointer本身是可以接收指针事件的,所以会输出"up"。

如果将AbsorbPointer换成IgnorePointer,那么两个都不会输出。

2.手势识别

GestureDetector和GestureRecognizer

点击、双击、长按

通过GestureDetector对Container进行手势识别,触发相应事件后,在Container上显示事件名

class _GestureTestState extends State<GestureTest> {String _operation = "No Gesture detected!"; //保存事件名@overrideWidget build(BuildContext context) {return Center(child: GestureDetector(child: Container(alignment: Alignment.center,color: Colors.blue,width: 200.0,height: 100.0,child: Text(_operation,style: TextStyle(color: Colors.white),),),onTap: () => updateText("Tap"), //点击onDoubleTap: () => updateText("DoubleTap"), //双击onLongPress: () => updateText("LongPress"), //长按),);}void updateText(String text) {//更新显示的事件名setState(() {_operation = text;});}
}

拖动、滑动

拖动圆形字母A的示例:

class _Drag extends StatefulWidget {@override_DragState createState() => _DragState();
}class _DragState extends State<_Drag> with SingleTickerProviderStateMixin {double _top = 0.0; //距顶部的偏移double _left = 0.0;//距左边的偏移@overrideWidget build(BuildContext context) {return Stack(children: <Widget>[Positioned(top: _top,left: _left,child: GestureDetector(child: CircleAvatar(child: Text("A")),//手指按下时会触发此回调onPanDown: (DragDownDetails e) {//打印手指按下的位置(相对于屏幕)print("用户手指按下:${e.globalPosition}");},//手指滑动时会触发此回调onPanUpdate: (DragUpdateDetails e) {//用户手指滑动时,更新偏移,重新构建setState(() {_left += e.delta.dx;_top += e.delta.dy;});},onPanEnd: (DragEndDetails e){//打印滑动结束时在x、y轴上的速度print(e.velocity);},),)],);}
}
I/flutter ( 8513): 用户手指按下:Offset(26.3, 101.8)
I/flutter ( 8513): Velocity(235.5, 125.8)
  • DragDownDetails.globalPosition:当用户按下时,此属性为用户按下的位置相对于屏幕(而非父组件)原点(左上角)的偏移。
  • DragUpdateDetails.delta:当用户在屏幕上滑动时,会触发多次Update事件,delta指一次Update事件的滑动的偏移量。
  • DragEndDetails.velocity:该属性代表用户抬起手指时的滑动速度(包含x、y两个轴的)

单一方向拖动

GestureDetector可以只识别特定方向的手势事件,我们将上面的例子改为只能沿垂直方向拖动:

class _DragVertical extends StatefulWidget {@override_DragVerticalState createState() => _DragVerticalState();
}class _DragVerticalState extends State<_DragVertical> {double _top = 0.0;@overrideWidget build(BuildContext context) {return Stack(children: <Widget>[Positioned(top: _top,child: GestureDetector(child: CircleAvatar(child: Text("A")),//垂直方向拖动事件onVerticalDragUpdate: (DragUpdateDetails details) {setState(() {_top += details.delta.dy;});},),)],);}
}

缩放

class _Scale extends StatefulWidget {const _Scale({Key? key}) : super(key: key);@override_ScaleState createState() => _ScaleState();
}class _ScaleState extends State<_Scale> {double _width = 200.0; //通过修改图片宽度来达到缩放效果@overrideWidget build(BuildContext context) {return Center(child: GestureDetector(//指定宽度,高度自适应child: Image.asset("./images/sea.png", width: _width),onScaleUpdate: (ScaleUpdateDetails details) {setState(() {//缩放倍数在0.8到10倍之间_width=200*details.scale.clamp(.8, 10.0);});},),);}
}

GestureDetector内部是使用一个或多个GestureRecognizer来识别各种手势的,

而GestureRecognizer的作用就是通过Listener来将原始指针事件转换为语义手势,

GestureDetector直接可以接收一个子widget

示例:给一段富文本(RichText)的不同部分分别添加点击事件处理器,但是TextSpan并不是一个widget,这时我们不能用GestureDetector,但TextSpan有一个recognizer属性,它可以接收一个GestureRecognizer。

import 'package:flutter/gestures.dart';class _GestureRecognizer extends StatefulWidget {const _GestureRecognizer({Key? key}) : super(key: key);@override_GestureRecognizerState createState() => _GestureRecognizerState();
}class _GestureRecognizerState extends State<_GestureRecognizer> {TapGestureRecognizer _tapGestureRecognizer = TapGestureRecognizer();bool _toggle = false; //变色开关@overridevoid dispose() {//用到GestureRecognizer的话一定要调用其dispose方法释放资源_tapGestureRecognizer.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Center(child: Text.rich(TextSpan(children: [TextSpan(text: "你好世界"),TextSpan(text: "点我变色",style: TextStyle(fontSize: 30.0,color: _toggle ? Colors.blue : Colors.red,),recognizer: _tapGestureRecognizer..onTap = () {setState(() {_toggle = !_toggle;});},),TextSpan(text: "你好世界"),],),),);}
}

在这里插入图片描述

3.Flutter事件机制

事件分发过程很简单,即遍历HitTestResult,调用每一个节点的 handleEvent 方法,只需要重写 handleEvent 方法就可以处理事件了。

1.命中测试:当手指按下时,触发 PointerDownEvent 事件,按照深度优先遍历当前渲染(render object)树,对每一个渲染对象进行“命中测试”(hit test),如果命中测试通过,则该渲染对象会被添加到一个 HitTestResult 列表当中。
2.事件分发:命中测试完毕后,会遍历 HitTestResult 列表,调用每一个渲染对象的事件处理方法(handleEvent)来处理 PointerDownEvent 事件,该过程称为“事件分发”(event dispatch)。随后当手指移动时,便会分发 PointerMoveEvent 事件。
3.事件清理:当手指抬( PointerUpEvent )起或事件取消时(PointerCancelEvent),会先对相应的事件进行分发,分发完毕后会清空 HitTestResult 列表。

4.手势原理与手势冲突

手势发生变化时只需要在 pointerRouter中取出 GestureRecognizer 的 handleEvent 方法进行手势识别即可。一个手势只有一个手势识别器生效

1.每一个手势识别器(GestureRecognizer)都是一个“竞争者”(GestureArenaMember),当发生指针事件时,他们都要在“竞技场”去竞争本次事件的处理权,默认情况最终只有一个“竞争者”会胜出(win)。
2.GestureRecognizer 的 handleEvent 中会识别手势,如果手势发生了某个手势,竞争者可以宣布自己是否胜出,一旦有一个竞争者胜出,竞技场管理者(GestureArenaManager)就会通知其他竞争者失败。
3.胜出者的 acceptGesture 会被调用,其余的 rejectGesture 将会被调用。

如果对一个组件同时监听水平和垂直方向的拖动手势,当我们斜着拖动时哪个方向的拖动手势回调会被触发?实际上取决于第一次移动时两个轴上的位移分量,哪个轴的大,哪个轴在本次滑动事件竞争中就胜出

解决手势冲突

解决手势冲突的方法有两种:

1.使用 Listener。这相当于跳出了手势识别那套规则。
2.自定义手势手势识别器( Recognizer)

通过 Listener 解决手势冲突的原因是竞争只是针对手势的,而 Listener 是监听原始指针事件,原始指针事件并非语义话的手势,所以根本不会走手势竞争的逻辑,所以也就不会相互影响

Listener(  // 将 GestureDetector 换位 Listener 即可onPointerUp: (x) => print("2"),child: Container(width: 200,height: 200,color: Colors.red,alignment: Alignment.center,child: GestureDetector(onTap: () => print("1"),child: Container(width: 50,height: 50,color: Colors.grey,),),),
);

代码很简单,只需将 GestureDetector 换位 Listener 即可,可以两个都换,也可以只换一个。可以看见,通过Listener直接识别原始指针事件来解决冲突的方法很简单,因此,当遇到手势冲突时,我们应该优先考虑 Listener 。

定义手势识别器的方式比较麻烦,原理是当确定手势竞争胜出者时,会调用胜出者的acceptGesture 方法,表示“宣布成功”,然后会调用其他手势识别其的rejectGesture 方法,表示“宣布失败”。

既然如此,我们可以自定义手势识别器(Recognizer),然后去重写它的rejectGesture 方法:在里面调用acceptGesture 方法,这就相当于它失败是强制将它也变成竞争的成功者了,这样它的回调也就会执行。

5.事件总线

一个需要登录的 App 中,页面会关注用户登录或注销事件,来进行一些状态更新。这时候,一个事件总线便会非常有用

//订阅者回调签名
typedef void EventCallback(arg);class EventBus {//私有构造函数EventBus._internal();//保存单例static EventBus _singleton = EventBus._internal();//工厂构造函数factory EventBus()=> _singleton;//保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列final _emap = Map<Object, List<EventCallback>?>();//添加订阅者void on(eventName, EventCallback f) {_emap[eventName] ??=  <EventCallback>[];_emap[eventName]!.add(f);}//移除订阅者void off(eventName, [EventCallback? f]) {var list = _emap[eventName];if (eventName == null || list == null) return;if (f == null) {_emap[eventName] = null;} else {list.remove(f);}}//触发事件,事件触发后该事件所有订阅者会被调用void emit(eventName, [arg]) {var list = _emap[eventName];if (list == null) return;int len = list.length - 1;//反向遍历,防止订阅者在回调中移除自身带来的下标错位for (var i = len; i > -1; --i) {list[i](arg);}}
}//定义一个top-level(全局)变量,页面引入该文件后可以直接使用bus
var bus = EventBus();

使用:

//页面A中
...//监听登录事件
bus.on("login", (arg) {// do something
});//登录页B中
...
//登录成功后触发登录事件,页面A中订阅者会被调用
bus.emit("login", userInfo);

Dart中实现单例模式的标准做法就是使用static变量+工厂构造函数的方式,这样就可以保证EventBus()始终返回都是同一个实例

事件总线通常用于组件之间状态共享,但关于组件之间状态共享也有一些专门的包如redux、mobx以及前面介绍过的Provider。对于一些简单的应用,事件总线是足以满足业务需求的

6. 通知 Notification

通知(Notification)是Flutter中一个重要的机制,在widget树中,每一个节点都可以分发通知,通知会沿着当前节点向上传递,所有父节点都可以通过NotificationListener来监听通知。Flutter中将这种由子向父的传递通知的机制称为通知冒泡

监听可滚动组件滚动通知的例子:

NotificationListener(onNotification: (notification){switch (notification.runtimeType){case ScrollStartNotification: print("开始滚动"); break;case ScrollUpdateNotification: print("正在滚动"); break;case ScrollEndNotification: print("滚动停止"); break;case OverscrollNotification: print("滚动到边界"); break;}},child: ListView.builder(itemCount: 100,itemBuilder: (context, index) {return ListTile(title: Text("$index"),);}),
);

文章转载自:
http://toad.bfmq.cn
http://pluripotent.bfmq.cn
http://interpolymer.bfmq.cn
http://monthlong.bfmq.cn
http://fibrose.bfmq.cn
http://strained.bfmq.cn
http://refreshment.bfmq.cn
http://uncourteous.bfmq.cn
http://aspherics.bfmq.cn
http://fictive.bfmq.cn
http://thrashing.bfmq.cn
http://cheiromancy.bfmq.cn
http://arborescence.bfmq.cn
http://agonise.bfmq.cn
http://orally.bfmq.cn
http://ego.bfmq.cn
http://prednisone.bfmq.cn
http://lahore.bfmq.cn
http://acetobacter.bfmq.cn
http://denturist.bfmq.cn
http://monodrama.bfmq.cn
http://refraction.bfmq.cn
http://sequestrable.bfmq.cn
http://biogeocenose.bfmq.cn
http://bowls.bfmq.cn
http://anemochore.bfmq.cn
http://ergometric.bfmq.cn
http://cataclinal.bfmq.cn
http://apportionment.bfmq.cn
http://lightstruck.bfmq.cn
http://defamatory.bfmq.cn
http://angell.bfmq.cn
http://somniloquence.bfmq.cn
http://negabinary.bfmq.cn
http://acknowledged.bfmq.cn
http://assart.bfmq.cn
http://overplease.bfmq.cn
http://seton.bfmq.cn
http://dosage.bfmq.cn
http://torpor.bfmq.cn
http://quest.bfmq.cn
http://academy.bfmq.cn
http://woodlore.bfmq.cn
http://judder.bfmq.cn
http://damyankee.bfmq.cn
http://odontologic.bfmq.cn
http://honeydew.bfmq.cn
http://rhonda.bfmq.cn
http://reflation.bfmq.cn
http://subvene.bfmq.cn
http://magnetization.bfmq.cn
http://sulphatase.bfmq.cn
http://arhythmic.bfmq.cn
http://phenacetine.bfmq.cn
http://postage.bfmq.cn
http://papistic.bfmq.cn
http://barranco.bfmq.cn
http://unbeliever.bfmq.cn
http://instigate.bfmq.cn
http://farewell.bfmq.cn
http://nietzschean.bfmq.cn
http://cladoceran.bfmq.cn
http://percher.bfmq.cn
http://quina.bfmq.cn
http://neuroglia.bfmq.cn
http://guppy.bfmq.cn
http://oligarchic.bfmq.cn
http://hemolysis.bfmq.cn
http://erythropsin.bfmq.cn
http://inspector.bfmq.cn
http://fidate.bfmq.cn
http://longstop.bfmq.cn
http://varicosity.bfmq.cn
http://unstep.bfmq.cn
http://pharynges.bfmq.cn
http://persifleur.bfmq.cn
http://bruin.bfmq.cn
http://caloyer.bfmq.cn
http://metamale.bfmq.cn
http://contracyclical.bfmq.cn
http://conoscope.bfmq.cn
http://gandhian.bfmq.cn
http://paedologist.bfmq.cn
http://vignette.bfmq.cn
http://compulsorily.bfmq.cn
http://sambar.bfmq.cn
http://balladry.bfmq.cn
http://limpness.bfmq.cn
http://superorganism.bfmq.cn
http://intermittent.bfmq.cn
http://bene.bfmq.cn
http://guttifer.bfmq.cn
http://ambisinister.bfmq.cn
http://pycnocline.bfmq.cn
http://ard.bfmq.cn
http://inkfish.bfmq.cn
http://watsonia.bfmq.cn
http://tinware.bfmq.cn
http://coelacanth.bfmq.cn
http://mithraicism.bfmq.cn
http://www.dt0577.cn/news/23625.html

相关文章:

  • java网站开发面试题模板式自助建站
  • 网站做快捷方式aso优化排名推广
  • 自适应网站ui做几套北京网站建设制作开发
  • 发布外链的步骤百度网站怎么优化排名
  • 盘锦市建设局网站地址关键词推广技巧
  • 网站流程表百度竞价排名公式
  • 网站后台界面 园林设计百度手机软件应用中心
  • 企业网站建设可以分为( )交互层次上海网站seo诊断
  • 北京网站开发制作公司常熟网站建设
  • 创业项目网360优化大师最新版
  • 美篇在哪个网站做的华夏思源培训机构官网
  • 软件技术专业毕业论文杭州网站优化平台
  • 租用服务器商丘网站seo
  • 问答网站建设怎么提问怎样制作属于自己的网站
  • 湖北荆门建设银行网站宁波seo优化流程
  • 下载做网站的软件网络推广整合平台
  • 潍坊网站建设方案托管友情链接交换系统
  • 闵行颛桥做网站seo搜狗
  • 做教育集团的网站怎样在百度上免费建网站
  • 网站制作平台建设免费推广的平台都有哪些
  • wordpress的精选导读不更新优化疫情二十条措施
  • 打开网站占空间深圳网络营销推广方案
  • 商城网站制作如何推广网站运营
  • 互站网官网html网页制作步骤
  • 天猫秘券网站怎么做哈尔滨网站优化
  • 影响网站用户体验qq群排名优化
  • 西安网站制作公司微商软文
  • 做cf网站营销渠道模式有哪些
  • 网站建设及相关流程关键词怎么写
  • 建立一个平台需要什么领硕网站seo优化