Question:
对于这样一个segementScrollView(Android的称法),图片/视频是作为一个flutterView被集成到原生中,当用户在屏幕进行拖拽或轻扫动作时(pan or swipe gesture),flutterView本身listView的上下滑动属性完全失效,此时操作的就像是在操作一个segementScrollView。可以左右滑动,但图片/视频listView本身不滑动,这明显不符合我们的期望。
segementView.png
Solution:
步骤1. 禁止segementScrollView上的滑动属性
当我禁止segementScrollView.scrollEnabbled = No后,左右不可滑动,上下滑动正常。因为上下滑动其实用的是flutterView的listView的滑动属性。看上去当禁止segementScrollView的滑动属性后,flutterView就可以接受到用户的触摸事件了。
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
NSInteger index = scrollView.contentOffset.x/ScreenWidth;
if (self.segmentControl.selectedSegmentIndex != index) {
self.segmentControl.selectedSegmentIndex = index;
}
//户型信息和图片/视频都是flutterView,因此我们需要将其scrollEnabled置为NO
if(self.segmentControl.selectedSegmentIndex == 1 || self.segmentControl.selectedSegmentIndex == 2){
self.segmentScrollView.scrollEnabled = NO;
}else{
self.segmentScrollView.scrollEnabled = YES;
}
}
drawingBoard.gif
步骤2:利用flutterView的pan手势得到左右偏移量
这时候我们发现虽然上下滑动flutterView的listView就正常了,但现在左右不可以滑动了。在网上找了很多资料,自己也做了很多尝试,发现我们可以这样做:
既然现在flutterView的手势是可以工作的,那我们可以利用flutterview的pan手势进行左右偏移的时候,实时记录其偏移位置,并将这偏移位置告诉iOS原生,这里就涉及到了flutterView与原生的交互部分了。
//flutter部分代码
Widget buildBuildingInfoContainer() {
return GestureDetector(
//手势滚动过程中
onPanUpdate: (d) {
print(
"onPanUpdate----direction=${d.delta.direction},dx=${d.delta.dx},dy=${d.delta.dy},distance=${d.localPosition.distance}");
movedX += d.delta.dx;
movedY += d.delta.dy;
//调用原生的方法,传递offsetX值以及状态ID
MethodChannelUtil.flutterInvokeNative(
MethodName.houseTypeCellScrolled, {
"status": 6,
"statusDesc": "移动",
"offsetX": movedX - originalX,
"offsetY": movedY - originalY
});
},
//手势开始拖拽
onPanStart: (d) {
print(
"onPanStart----dx=${d.localPosition.dx},dy=${d.localPosition.dy},distance=${d.localPosition.distance}");
//调用原生的方法,传递offsetX值以及状态ID
MethodChannelUtil.flutterInvokeNative(
MethodName.houseTypeCellScrolled, {
"status": 5,
"statusDesc": "开始",
"startX": originalX,
"startY": originalY
});
},
//手势拖动结束
onPanEnd: (DragEndDetails details) {
print("onPanEnd");
double offsetX = movedX - originalX;
double offsetY = movedY - originalY;
print("offsetX=$offsetX offsetY=$offsetY");
//调用原生的方法,传递offsetX值以及状态ID
MethodChannelUtil.flutterInvokeNative(
MethodName.houseTypeCellScrolled, {
"status": 7,
"statusDesc": "结束",
"offsetX": offsetX,
"offsetY": offsetY
});
},
child: Container(
),
}
步骤3:原生接受到flutter模块的callBack,作出相应处理
原生模块可以接受到flutter模块的callBack,并得到偏移量的值,以及相应的status值。得到偏移量就很简单了,跟我们在iOS模块里设置scrollView偏移量没有两样。
self.videoPhotoFlutterViewController.callBack = ^(NSString * _Nonnull jsonStr) {
NSLog(@"OC----%@---",jsonStr);
NSDictionary *dict = jsonStr.mj_JSONObject;
NSInteger value = [[dict objectForKey:@"status"] integerValue];
CGFloat offsetX = [[dict objectForKey:@"offsetX"] doubleValue];
CGFloat offsetY = [[dict objectForKey:@"offsetY"] doubleValue];
//移动中
if(value == 6){
startX = weakself.segmentScrollView.contentOffset.x;
CGFloat startY = weakself.segmentScrollView.contentOffset.y;
startX += -offsetX;
[weakself.segmentScrollView setContentOffset:CGPointMake(startX, 0)];
NSLog(@"startX=%f",startX);
}
//停止移动
if(value == 7){
if(startX>ScreenWidth*1.5 && startX< ScreenWidth*2 + ScreenWidth*0.5){
[weakself.segmentScrollView setContentOffset:CGPointMake(ScreenWidth*2,0) animated:true];
}
if (startX >= ScreenWidth*2 + ScreenWidth*0.5) {
[weakself.segmentScrollView setContentOffset:CGPointMake(UIScreen.mainScreen.bounds.size.width*3,0) animated:true];
}
if (startX <= ScreenWidth*1.5){
[weakself.segmentScrollView setContentOffset:CGPointMake(ScreenWidth,0) animated:true];
}
}
};
最终效果与总结
drawingBoard2.gif
现在从效果上来,可以总结以下几点:
- 在iOS系统的segmentViewController中,上方是一个自定义的segmentTitleView,下方是一个左右滑动的scrollView。这个segmentItem每一个item都是独立的ViewController,其中当然也包括我们的flutterViewController。
- 一开始的时候,左右滑动是没有问题的,但就是flutterView里的listView不能正常滑动,因为我们现在所有的手势都在iOS层处理了,并不会传递给flutterView,flutterView的手势不起作用。因此我们需要设置segmentScrollView.scrollEnabled = NO去disable掉原生层面的手势,这样flutterView层面上的手势自动生效。
- segmentScrollView的滑动属性被disable掉之后,左右滑动不能work了。现在我们需要在flutterView的pan手势去计算得出其手势偏移量,将此偏移量传递给原生,然后由原生去设置segmentScrollView的contentOffset做偏移。
这就是设计的基本思路。有更好的方案,欢迎提出讨论👏👏