|
前言 业务场景为,在摄像机的播放画面上,按下手指左右上下滑动,摄像机跟随滑动。由于播放页面使用了photo_view提供了画面图片的放大缩小和拖拽功能,导致和嵌套的要实现监听滑动的GestureDetector存在冲突的问题。最终实现的解决方案为,在photo_vew默认状态下,让GestureDetector接收手指滑动事件,摄像机跟随旋转;在photo_vew放大状态下,GestureDetector不接收事件,让photo_vew处理放大图片的拖拽。比较好的解决了用户的使用场景问题问题描述 onPanDown实现首先,正常思路肯定是直接在Photoview的外部包裹GestureDetector,然后重写onPanDown,onPanUpdate方法,如下body:GestureDetector(onPanDowne){print('fuxiao:按下$e');},onPanStarte){print('fuxiao:开始$e');},onPanCancel){print('fuxiao:取消');},onPanEnde){print('fuxiao:结束');},onPanUpdatee){print('fuxiao:更新$e');},child:Container(constraints:BoxConstraints.expand(height:MediaQuery.of(context).size.height,),//child:Container(//color:Colors.blue,//width:400,//height:400,//)childhotoView(imageProvider:imageProvider,loadingBuilder:loadingBuilder,backgroundDecoration:backgroundDecoration,minScale:minScale,maxScale:maxScale,initialScale:initialScale,basePosition:basePosition,filterQuality:filterQuality,disableGestures:disableGestures,errorBuilder:errorBuilder,),),),结果存在两个问题1、onPanUpdate第一次滑动不触发,而触发onPanCancel方法,猜想是PhotoView处理事件导致的,上层树的事件取消,通过将上面注释代码打开验证,确实是PhotoView导致的问题2、由于重写onPanDown方法,导致PhotoView,双指缩放画面功能失效两个功能都不能正常工作,尝试解决这个问题,在网上浏览资料发现,GestureDetector并没有提供,双指的按下检测方法。所以希望通过双指按下PhotoView处理事件,单指按下外层GestureDetector处理事件的方法行不通。onHorizontalDragUpdate 实现通过查看GestureDetector构造方法发现,提供了水平和竖直方向的检测方法水平拖拽onHorizontalDragStart 水平移动开始onHorizontalDragUpdate 水平方向移动onHorizontalDragEnd 水平移动结束垂直拖拽onVerticalDragStart 垂直移动开始onVerticalDragUpdate 垂直移动onVerticalDragEnd 垂直移动结束通过重写上述方法,实际打印log发现,onHorizontalDragUpdate和onVerticalDragUpdate在单手移动屏幕时总会优先调用,代码如下body:GestureDetector(behavior:HitTestBehavior.opaque,onHorizontalDragUpdatee){print('fuxiao:水平$e');},onVerticalDragUpdatee){print('fuxiao:垂直$e');},child:Container(constraints:BoxConstraints.expand(height:MediaQuery.of(context).size.height,),childhotoView(imageProvider:imageProvider,loadingBuilder:loadingBuilder,backgroundDecoration:backgroundDecoration,minScale:minScale,maxScale:maxScale,initialScale:initialScale,basePosition:basePosition,filterQuality:filterQuality,disableGestures:disableGestures,errorBuilder:errorBuilder,),),),手指在屏幕上滑动,打印logI/flutter(5191):fuxiao:水平DragUpdateDetails(Offset(1.1,0.0))I/flutter(5191):fuxiao:水平DragUpdateDetails(Offset(1.1,0.0))I/flutter(5191):fuxiao:水平DragUpdateDetails(Offset(1.8,0.0))I/flutter(5191):fuxiao:垂直DragUpdateDetails(Offset(0.0,-2.5))I/flutter(5191):fuxiao:垂直DragUpdateDetails(Offset(0.0,-2.9))I/flutter(5191):fuxiao:垂直DragUpdateDetails(Offset(0.0,-2.5))并且,删除了onPanDown的重写方法,PhotoView双指放大缩小的功能也正常了,这样我们的需求基本上已经可以实现了,只不过还有一点小小的优化:PhotoView在画面放大状态下,左右滑动是移动画面,而不是回调onHorizontalDragUpdate方法跟相册中预览图片的效果是相似的。而如果重写onHorizontalDragUpdate,会导致画面移动失效可以看到,放大以后,按下水平手指,水平滑动画面没有跟随移动,事件被上层消费了解决的思路就是,当PhotoView放大或缩小状态时,禁止onHorizontalDragUpdate的调用冲突解决 可以猜想,PhotoView应该提供了缩放状态的监听,查看PhotoView的构造方法PhotoView({Keykey,requiredthis.imageProvider,this.loadingBuilder,this.backgroundDecoration,this.gaplessPlayback=false,this.heroAttributes,///缩放状态监听this.scaleStateChangedCallback,this.enableRotation=false,this.controller,this.scaleStateController,this.maxScale,this.minScale,this.initialScale,this.basePosition,this.scaleStateCycle,this.onTapUp,this.onTapDown,this.onScaleEnd,this.customSize,this.gestureDetectorBehavior,this.tightMode,this.filterQuality,this.disableGestures,this.errorBuilder,this.enablePanAlways,}):child=null,childSize=null,super(key:key);///A[Function]tobecalledwheneverthescaleStatechanges,thishappenswhentheuserdoubletapsthecontentoustarttopinch-in.finalValueChanged
scaleStateChangedCallback;///Awaytorepresentthestepofthe"doubletapgesturecycle"inwhichPhotoViewis.enumPhotoViewScaleState{initial,covering,originalSize,zoomedIn,zoomedOut,}这样就拿到了,PhotoView画面状态变化回调,只需要做一个处理,当state为initial时,才允许GestureDetector监听滑动事件,其他情况,走PhotoView的拖拽结论 最终代码如下这里直接贴上photo_view中example里的common_example_wrapper.dart代码import'package:flutter/material.dart';import'package:photo_view/photo_view.dart';classCommonExampleRouteWrapperextendsStatefulWidget{constCommonExampleRouteWrapper({this.imageProvider,this.loadingBuilder,this.backgroundDecoration,this.minScale,this.maxScale,this.initialScale,this.basePosition=Alignment.center,this.filterQuality=FilterQuality.none,this.disableGestures,this.errorBuilder,this.scaleChangedListener});finalImageProviderimageProvider;finalLoadingBuilderloadingBuilder;finalBoxDecorationbackgroundDecoration;finaldynamicminScale;finaldynamicmaxScale;finaldynamicinitialScale;finalAlignmentbasePosition;finalFilterQualityfilterQuality;finalbooldisableGestures;finalImageErrorWidgetBuildererrorBuilder;finalValueChanged
scaleChangedListener;@override_CommonExampleRouteWrapperStatecreateState()=>_CommonExampleRouteWrapperState();}class_CommonExampleRouteWrapperStateextendsState{ValueChanged
_scaleChangedListener;boolcanZoomControl=true;GestureDragUpdateCallbackupdateCallback;@overridevoidinitState(){updateCallback=(e){print('fuxiao:滑动:$e');};if(widget.scaleChangedListener==null){_scaleChangedListener=(PhotoViewScaleStatestatue){print('fuxiao:状态:$statue');switch(statue){casePhotoViewScaleState.initial:canZoomControl=true;break;default:canZoomControl=false;break;}setState((){});};}else{_scaleChangedListener=widget.scaleChangedListener;}super.initState();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:GestureDetector(onHorizontalDragUpdate:canZoomControlupdateCallback:null,onVerticalDragUpdate:canZoomControlupdateCallback:null,child:Container(constraints:BoxConstraints.expand(height:MediaQuery.of(context).size.height,),childhotoView(imageProvider:widget.imageProvider,loadingBuilder:widget.loadingBuilder,backgroundDecoration:widget.backgroundDecoration,scaleStateChangedCallback:_scaleChangedListener,minScale:widget.minScale,maxScale:widget.maxScale,initialScale:widget.initialScale,basePosition:widget.basePosition,filterQuality:widget.filterQuality,disableGestures:widget.disableGestures,errorBuilder:widget.errorBuilder,),),),);}}最终效果如下最终方案总结 本文主要分析解决了,photo_view嵌套GestureDetector滑动监听的冲突问题,暂时先记录问题的解决,原理有时间再写一篇分析。大家如果有遇到相同情况,并且有更好的解决方案,欢迎在评论区交流分享,感谢~
|
|