重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
描述了屏幕上指针(触摸、鼠标、触控笔)的位置和移动。
成都创新互联专注于企业网络营销推广、网站重做改版、贡嘎网站定制设计、自适应品牌网站建设、H5响应式网站、成都商城网站开发、集团公司官网建设、成都外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为贡嘎等各大城市提供网站开发制作服务。
Flutter中可以使用Listener(功能性组件)来监听原始触摸事件
例1
例2
例3
忽略PointerEvent
手势: 描述由一个或多个指针移动组成的语义动作,如拖动、缩放、双击等。
Material大多数widget已经对tap或手势做出了响应。 例如 IconButton和 FlatButton 响应单击,ListView响应滑动事件触发滚动。
用于手势识别的功能性组件,通过它可以来识别各种手势。
例(单击)
例(添加Material触摸水波效果 InkWell组件)
例(滑动关闭 Dismissable组件)
例(单击、双击、长按)
例(滑动)
例(扫动---单一方向)
例(缩放)
GestureRecognizer是一个抽象类。
一种手势的识别器对应一个GestureRecognizer的子类。
例
由于手势竞争最终只有一个胜出者,所以,当有多个手势识别器时,可能会产生冲突。
例
例
在APP中经常会需要一个广播机制,用以跨页面通知。比如一个需要登录的APP中,页面会关注用户登录或注销事件,来进行一些状态更新。
这时候,一个事件总线便会非常有用,事件总线通常实现了订阅者模式,订阅者模式包含发布者和订阅者两种角色,可以通过事件总线来触发事件和监听事件。
对于一些简单的应用,事件总线是足以满足业务需求的,如果决定使用状态管理包的话,一定要想清楚APP是否真的有必要使用它,防止“化简为繁”、过度设计。
例
在widget树中,每一个节点都可以分发通知,通知会沿着当前节点向上传递,所有父节点都可以通过NotificationListener来监听通知。
Flutter中将这种由子向父的传递通知的机制称为通知冒泡(Notification Bubbling)。
通知冒泡和用户触摸事件冒泡是相似的,但有一点不同:通知冒泡可以中止,但用户触摸事件不行。
通知冒泡和Web开发中浏览器事件冒泡原理是相似的,都是事件从出发源逐层向上传递,可以在上层节点任意位置来监听通知/事件,也可以终止冒泡过程,终止冒泡后,通知将不会再向上传递。
Flutter的UI框架实现中,除了在可滚动组件在滚动过程中会发出ScrollNotification之外,还有一些其它的通知,如SizeChangedLayoutNotification、KeepAliveNotification 、LayoutChangedNotification等,Flutter正是通过这种通知机制来使父元素可以在一些特定时机来做一些事情。
例
例
例
阻止冒泡
通知冒泡原理
在移动端,各个平台或 UI 系统的原始指针事件模型基本都是一致,即:一次完整的事件分为三个阶段:手指按下、手指移动、和手指抬起,而更高级别的手势(如点击、双击、拖动等)都是基于这些原始事件的。
Flutter 中可以使用 Listener widget 来监听原始触摸事件,它也是一个功能性 widget。
Listener 的常见属性
用法如下:
加载更多需要对 ListView 进行监听,所以需要进行监听器的设置,在 State 中进行监听器的初始化。
2、使用上述的 Listener 来监听,通过 Listener 的 onPointerMove(手指在屏幕上滑动)来监听滑动的距离,当滑动到底部时加载更多数据
对于滚动的视图,我们经常需要监听它的一些滚动事件,在监听到的时候去做对应的一些事情。
比如视图滚动到底部时,我们可能希望做上拉加载更多;
比如滚动到一定位置时显示一个回到顶部的按钮,点击回到顶部的按钮,回到顶部;
比如监听滚动什么时候开始,什么时候结束;
在Flutter中监听滚动相关的内容由两部分组成:ScrollController和ScrollNotification。
ScrollController
在Flutter中,Widget并不是最终渲染到屏幕上的元素(真正渲染的是RenderObject),因此通常这种监听事件以及相关的信息并不能直接从Widget中获取,而是必须通过对应的Widget的Controller来实现。
ListView、GridView的组件控制器是ScrollController,我们可以通过它来获取视图的滚动信息,并且可以调用里面的方法来更新视图的滚动位置。
另外,通常情况下,我们会根据滚动的位置来改变一些Widget的状态信息,所以ScrollController通常会和StatefulWidget一起来使用,并且会在其中控制它的初始化、监听、销毁等事件。
我们来做一个案例,当滚动到1000位置的时候,显示一个回到顶部的按钮:
jumpTo(double offset)、animateTo(double offset,...):这两个方法用于跳转到指定的位置,它们不同之处在于,后者在跳转时会执行一个动画,而前者不会。
ScrollController间接继承自Listenable,我们可以根据ScrollController来监听滚动事件。
Flutter的 StatefulWidget StatelessWidget 生命周期中没有组件出现或者消失的回调,主要是要靠路由的监听
最近一个项目要实现可以无限循环的PageView,主要思路是在初始化pageview的list的时候在开始和结尾多加一个结尾和开头的widget,当滑动到开头和结尾的时候手动进行页面的切换,详细可以搜索pageview无限轮播。
这种方法有一个要点就是要维护两个索引,一个是内部list的索引,一个是外部显示的索引,由于list的容量是比显示的数量多2的,所以如果要在外部进行一些比如指示器或者计时器功能要进行和页面同步显示或者切换页面操作时,需要将显示的索引转换成list的索引。
不过网上说的都是一些比较简单的实现,看到比较多的就是当滑动到要手动切换的时候进行一个时延,这样可以避免直接切换页面造成的卡顿和跳动现象。但是存在一个问题,如果要同时实现一个跟随页面切换的指示器,就会出现当页面切换过去之后指示器才会跟着过去,因为页面切换的时候执行了时延,而时延之后才会真正改变索引,此时才会setstate,之后指示器才能响应到索引的切换,但是如果在时延之前就切换的话又会出现指示器先行的情况。因此这种方法其实是存在一些问题的。
所以解决这个问题的关键在于如何进行页面切换的判断。这里可以有两种思路实现,第一种是实现viewpage的onpagechanged方法,在里面进行逻辑的判断,然后用controller来进行页面跳转,不过这种方法存在当controller跳转的时候又会回调onpagechanged,所以就会出现多次对索引不必要操作,而且如果有比如计时器等额外的功能的话可能不方便将页面逻辑分开,而且依旧无法解决指示器延迟问题,同时也很难进行细粒度的操作。
第二种方法我们就要去看pageview的源码了,从源码的角度来解决问题才是正确的方法。首先我们点进去pageview的源码
看到这里其实已经有一些思路了,我们之前难点在于重写了onpagechanged方法导致问题无法很好的解决,现在我们找到了onpagechanged调用的地方,只要找办法避免掉就可以实现了。
当然这里我们要说到NotificationListener,以及flutter对应的冒泡事件传输机制,这里大家可以去看看这篇 文章 。
我来总结一下,其实就是flutter对于notification这个组件,有一中事件规则叫冒泡传递,底层的notification如果在它的 onNotification写的逻辑中返回是false以及它不是根结点,就会去向上遍历寻找它的祖先notification组件,知道遇到root节点或者某一个返回true,则事件传递结束。
而且在onNotification中可以对多种事件进行监听和处理,所以我们可以把对viewpage页面跳转对索引处理的逻辑写在这里,而且我们可以分别处理比如滑动开始的start事件和结束的end事件,分别进行细粒度的逻辑的处理,这样就可以在外部进行操作和别的功能实现了。
因此不仅无限轮播事件可以通过这种方法来解决,如果有其他的操作也可以这样进行处理,而且因为我们没有传入onpagechanged方法,所以不存在多次调用的问题,pageview那里判断onpagechanged是null方法就不会进去了,会直接我们写在pageview外面的notification的逻辑。
最后的结构大概这样
对于初学flutter的朋友来说,要知道,flutter的UI万物皆Widget。
flutter所写的页面的结构可以被看成套娃,一层套一层,一层套一层,一层套一层。。。。。。
Flutter Widget采用现代响应式框架构建,这是从 React 中获得的灵感,中心思想是用widget构建你的UI。 Widget描述了他们的视图在给定其当前配置和状态时应该看起来像什么。当widget的状态发生变化时,widget会重新构建UI,Flutter会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。
Text : 该 widget 可让创建一个带格式的文本。
Row 、 Column : 这些具有弹性空间的布局类Widget可让您在水平( Row )和垂直( Column )方向上创建灵活的布局。
Stack :取代线性布局 (和Android中的LinearLayout相似),Stack允许子 widget 堆叠, 你可以使用 Positioned 来定位他们相对于 Stack 的上下左右四条边的位置。
Container : Container 可让您创建矩形视觉元素。 您可以为 Container 装饰一个 BoxDecoration , 如 background、一个边框、或者一个阴影。 Container 也可以具有边距(margins)、填充(padding)和应用于其大小的约束(constraints)。另外, Container 可以使用矩阵在三维空间中对其进行变换。
具体的演示见我另外的博客
有一部分Widget都有一个 child 属性,用于容纳唯一的子Widget。
例如:Container、Center、Padding、Align等Widget。
还有一部分Widget允许存在多个子Widget,用 children 作为属性。
例如:Row、Column、Stack等Widget。
在StatefulWidget调用createState之后,框架将新的状态插入树种,然后调用状态对象的initState。子类化State可以重写initState,以完成仅需要一次执行的工作。当然在initState的实现中需要调用super.initState
当一个状态对象不再需要时,框架调用状态对象的dispose。也可以通过覆盖dispose方法来执行清理工作。
OVER~