iOS集成Flutter-手勢沖突問題解決

Question:

對于這樣一個segementScrollView(Android的稱法),圖片/視頻是作為一個flutterView被集成到原生中,當用戶在屏幕進行拖拽或輕掃動作時(pan or swipe gesture),flutterView本身listView的上下滑動屬性完全失效,此時操作的就像是在操作一個segementScrollView??梢宰笥一瑒?,但圖片/視頻listView本身不滑動,這明顯不符合我們的期望。


segementView.png

Solution:

步驟1. 禁止segementScrollView上的滑動屬性

當我禁止segementScrollView.scrollEnabbled = No后,左右不可滑動,上下滑動正常。因為上下滑動其實用的是flutterView的listView的滑動屬性??瓷先ギ斀箂egementScrollView的滑動屬性后,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手勢得到左右偏移量

這時候我們發(fā)現(xiàn)雖然上下滑動flutterView的listView就正常了,但現(xiàn)在左右不可以滑動了。在網上找了很多資料,自己也做了很多嘗試,發(fā)現(xiàn)我們可以這樣做:
既然現(xiàn)在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值以及狀態(tài)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值以及狀態(tài)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值以及狀態(tài)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

現(xiàn)在從效果上來,可以總結以下幾點:

  1. 在iOS系統(tǒng)的segmentViewController中,上方是一個自定義的segmentTitleView,下方是一個左右滑動的scrollView。這個segmentItem每一個item都是獨立的ViewController,其中當然也包括我們的flutterViewController。
  2. 一開始的時候,左右滑動是沒有問題的,但就是flutterView里的listView不能正常滑動,因為我們現(xiàn)在所有的手勢都在iOS層處理了,并不會傳遞給flutterView,flutterView的手勢不起作用。因此我們需要設置segmentScrollView.scrollEnabled = NO去disable掉原生層面的手勢,這樣flutterView層面上的手勢自動生效。
  3. segmentScrollView的滑動屬性被disable掉之后,左右滑動不能work了。現(xiàn)在我們需要在flutterView的pan手勢去計算得出其手勢偏移量,將此偏移量傳遞給原生,然后由原生去設置segmentScrollView的contentOffset做偏移。
    這就是設計的基本思路。有更好的方案,歡迎提出討論????
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容