天天看點

Flutter 仿掘金微信圖檔滑動退出頁面效果

1.增加onSlidingPage回調,可以在滑動頁面的時候設定頁面上面的其他元素的狀态

2.增加中文文檔

這個需求在做extended_image的時候就有上帝客戶提過了,一直都沒有時間去考慮實作。最近思考了一下,把效果給實作了。

Flutter 仿掘金微信圖檔滑動退出頁面效果

首先開啟滑動退出頁面效果

ExtendedImage

parameter description default
enableSlideOutPage 是否開啟滑動退出頁面效果 false

把你的頁面用ExtendedImageSlidePage包一下

注意:onSlidingPage回調,你可以使用它來設定滑動頁面的時候,頁面上其他元素的狀态。但是注意别直接使用setState來重新整理,因為這樣會導緻ExtendedImage的狀态重置掉,你應該隻通知需要重新整理的Widgets進行重新整理

return ExtendedImageSlidePage(
      child: result,
      slideAxis: SlideAxis.both,
      slideType: SlideType.onlyImage,
      onSlidingPage: (state) {
        ///you can change other widgets' state on page as you want
        ///base on offset/isSliding etc
        //var offset= state.offset;
        var showSwiper = !state.isSliding;
        if (showSwiper != _showSwiper) {
          // do not setState directly here, the image state will change,
          // you should only notify the widgets which are needed to change
          // setState(() {
          // _showSwiper = showSwiper;
          // });

          _showSwiper = showSwiper;
          rebuildSwiper.add(_showSwiper);
        }
      },
    );
           

ExtendedImageGesturePage的參數

parameter description default
child 需要包裹的頁面 -
slidePageBackgroundHandler 在滑動頁面的時候根據Offset自定義整個頁面的背景色 defaultSlidePageBackgroundHandler
slideScaleHandler 在滑動頁面的時候根據Offset自定義整個頁面的縮放值 defaultSlideScaleHandler
slideEndHandler 滑動頁面結束的時候計算是否需要pop頁面 defaultSlideEndHandler
slideAxis 滑動頁面的方向(both,horizontal,vertical),掘金是vertical,微信是Both both
resetPageDuration 滑動結束,如果不pop頁面,整個頁面回彈動畫的時間 milliseconds: 500
slideType 滑動整個頁面還是隻是圖檔(wholePage/onlyImage) SlideType.onlyImage
onSlidingPage 滑動頁面的回調,你可以在這裡改變頁面上其他元素的狀态 -

下面是預設實作,你也可以根據你的喜好,來定義屬于自己方式

Color defaultSlidePageBackgroundHandler(
    {Offset offset, Size pageSize, Color color, SlideAxis pageGestureAxis}) {
  double opacity = 0.0;
  if (pageGestureAxis == SlideAxis.both) {
    opacity = offset.distance /
        (Offset(pageSize.width, pageSize.height).distance / 2.0);
  } else if (pageGestureAxis == SlideAxis.horizontal) {
    opacity = offset.dx.abs() / (pageSize.width / 2.0);
  } else if (pageGestureAxis == SlideAxis.vertical) {
    opacity = offset.dy.abs() / (pageSize.height / 2.0);
  }
  return color.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
}

bool defaultSlideEndHandler(
    {Offset offset, Size pageSize, SlideAxis pageGestureAxis}) {
  if (pageGestureAxis == SlideAxis.both) {
    return offset.distance >
        Offset(pageSize.width, pageSize.height).distance / 3.5;
  } else if (pageGestureAxis == SlideAxis.horizontal) {
    return offset.dx.abs() > pageSize.width / 3.5;
  } else if (pageGestureAxis == SlideAxis.vertical) {
    return offset.dy.abs() > pageSize.height / 3.5;
  }
  return true;
}

double defaultSlideScaleHandler(
    {Offset offset, Size pageSize, SlideAxis pageGestureAxis}) {
  double scale = 0.0;
  if (pageGestureAxis == SlideAxis.both) {
    scale = offset.distance / Offset(pageSize.width, pageSize.height).distance;
  } else if (pageGestureAxis == SlideAxis.horizontal) {
    scale = offset.dx.abs() / (pageSize.width / 2.0);
  } else if (pageGestureAxis == SlideAxis.vertical) {
    scale = offset.dy.abs() / (pageSize.height / 2.0);
  }
  return max(1.0 - scale, 0.8);
}
           

確定你的頁面是透明背景的

如果你設定 slideType =SlideType.onlyImage, 請確定的你頁面是透明的,畢竟沒法操控你頁面上的顔色

Push一個透明的頁面

這裡我把官方的MaterialPageRoute 和CupertinoPageRoute拷貝出來了, 改為TransparentMaterialPageRoute/TransparentCupertinoPageRoute,因為它們的opaque不能設定為false

Navigator.push(
    context,
    Platform.isAndroid
        ? TransparentMaterialPageRoute(builder: (_) => page)
        : TransparentCupertinoPageRoute(builder: (_) => page),
  );
           

嗯應該還算使用簡單吧?群裡的小夥伴吐槽表情包太多,不讓放,藍瘦香菇。

實作中的一些坑

1.手勢跟縮放拖拽以及PageView之前的關系和沖突

開始我的思路是想在ExtendedImageSlidePage 注冊手勢監聽事件,然後ExtendedImageGesture裡面當條件滿足(達到邊界/無法拖拽)的時候通知 ExtendedImageSlidePage 開始滑動頁面手勢了,可以阻止ExtendedImageSlidePage的child的hittest。

但是在實際中發現,在ExtendedImageGesture手勢未完成之前(手指擡起),ExtendedImageSlidePage 也是擷取不到任何手勢,而且IgnorePointer 也是不會生效的

後面幹脆直接把手勢接收都放ExtendedImageGesture裡面了,直接通知ExtendedImageSlidePage進行translate和scale

2.透明頁面

TransparentMaterialPageRoute/TransparentCupertinoPageRoute 因為需要整個頁面是透明的,是以重寫了官方的。

但是在pop頁面的時候還是有不滿意的地方,比如ios上面有個從左到右Shadow,安卓上面整個頁面也有Shadow。

最後

如果你看到了這裡,覺得文章寫得不錯就給個贊呗!歡迎大家評論讨論!如果你覺得那裡值得改進的,請給我留言。一定會認真查詢,修正不足,定期免費分享技術幹貨。謝謝!

Flutter 仿掘金微信圖檔滑動退出頁面效果

繼續閱讀