Peek & Pop

基于 iOS 同名功能的 Flutter Peek & Pop 实现。

终于,v1.0.0 版本发布了!比以往更加流畅、更加优化、更加美观。高度可定制,非常易于使用。

强烈建议阅读文档并在真实设备上运行示例项目,以充分理解和检查全部功能。

作为 iOS Peek & Pop 功能的粉丝,我也决定为 Flutter 实现它。

该包已在 iOS 上测试过,但在 Android 上尚未测试,因为我无法访问具有 Force Press 功能的 Android 设备。关于帮助
将不胜感激。

对于不支持 Force Press 的设备,该包附带了长按适配功能,*但是*该包的长按版本
仍在开发中,尚未完全测试,因此请将其视为开发预览。

(长按版本已暂时移除。将很快重新添加。)

这个包的强大之处在于我称之为“手势识别重路由”。通常,当一个带有 GestureDetector 或类似组件的新小部件
被推送到用于检测 Force Press 的初始小部件之上,或者当 Navigator 用于弹出新页面时,用户必须重新开始手势
才能让 Flutter 继续更新它。该包修复了这个问题,正如文档中所解释的

//This function is called by the instantiated [PeekAndPopChild] once it is ready to be included in the Peek & Pop process. Perhaps the most
//essential functionality of this package also takes places in this function: The gesture recognition is rerouted from the [PeekAndPopDetector]
//to the instantiated [PeekAndPopChild]. This is important for avoiding the necessity of having the user stop and restart their Force Press.
//Instead, the [PeekAndPopController] does this automatically so that the existing Force Press can continue to update even when if
//[PeekAndPopDetector] is blocked by the view which is often the case especially when using PlatformViews.

安装

很简单。别担心。

如果您不想使用 PlatformViews,可以跳过安装说明。

旧的安装说明已移除。如果您(出于某种原因)想使用 v0.1.9 之前的版本,请参阅该版本的 README 以获取
相应的安装说明。

为了正确显示 PlatformViews,此包需要最新的 Flutter master
分支。*也许*它也能在其他版本上工作,但使用 webview_flutter 进行的测试
似乎只能在最新的 Flutter master 分支上正常显示,该分支改进了 PlatformViews,
允许更好的功能,如正确的缩放和正确的裁剪。

如果您不想使用 PlatformViews,可以跳过此步骤。

要使用最新的 Flutter master 分支,请运行以下命令。

注意:不要忘记添加io.flutter.embedded_views_previewYES到您的 Info.plist。有关更多信息,请参阅
webview_flutter

$ git clone -b master https://github.com/flutter/flutter.git
$ flutter channel master
$ flutter upgrade
$ flutter doctor
$ ./flutter/bin/flutter --version

如何使用

也很简单。

首先,正如文档中所解释的

//I noticed that a fullscreen blur effect via the [BackdropFilter] widget is not good to use while running the animations required for the Peek &
//Pop process as it causes a noticeable drop in the framerate- especially for devices with high resolutions. During a mostly static view, the
//drop is acceptable. However, once the animations start running, this drop causes a visual disturbance. To prevent this, a new optimised blur
//effect algorithm is implemented. Now, the [BackdropFilter] widget is only used until the animations are about to start. At that moment, it is
//replaced by a static image. Therefore, to capture this image, your root CupertinoApp/MaterialApp MUST be wrapped in a [RepaintBoundary] widget
//which uses the [background] key. As a result, the Peek & Pop process is now up to 4x more fluent.

TL;DR:将您的根 CupertinoApp/MaterialApp 包装在 RepaintBoundary 小部件中,并使用“misc.dart”中的 background GlobalKey。

这是新优化的模糊效果算法所必需的。

import 'package:peek_and_pop/misc.dart' as PeekAndPopMisc;

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      key: PeekAndPopMisc.background,
      child: MaterialApp(
        title: 'Peek & Pop Demo',
        home: MyHomePage(title: 'Peek & Pop Demo')
      )
    );
  }
}

如果您想使用“ScaleUp”或“Scale Down”功能,请将您希望在 Peek & Pop 过程中放大或缩小的组件包装在
“misc.dart”中的 scaleUpWrapper 和 scaleDownWrapper 函数中。

@override
Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(title: Text(widget.title)),
  body: PeekAndPopMisc.scaleDownWrapper(
        ...,
        0.04,
        ),
    );    
}

然后,创建一个 PeekAndPopController,例如

PeekAndPopController(
  uiChild(),            //Widget uiChild
  false,                //bool uiChildUseCache
  peekAndPopBuilder,    //PeekAndPopBuilder peekAndPopBuilder
  false,                //bool peekAndPopBuilderUseCache
 {Key key,
  quickActionsBuilder           : quickActionsBuilder,
  sigma                         : 10,
  backdropColor                 : Colors.black,
  alpha                         : 126,
  overlayBuilder                : overlayBuilder,
  useOverlap                    : true,
  customOverlapRect,
  useAlignment,                 : false,
  useIndicator                  : true,
  indicatorScaleUpCoefficient   : 0.01,
  willPeekAndPopComplete        : _willPeekAndPopComplete,
  willPushPeekAndPop            : _willPushPeekAndPop,
  willUpdatePeekAndPop          : _willUpdatePeekAndPop,
  willCancelPeekAndPop          : _willCancelPeekAndPop,
  willFinishPeekAndPop          : _willFinishPeekAndPop,
  willClosePeekAndPop           : _willClosePeekAndPop,
  onPeekAndPopComplete          : _onPeekAndPopComplete,
  onPushPeekAndPop              : _onPushPeekAndPop,
  onUpdatePeekAndPop            : _onUpdatePeekAndPop,
  onCancelPeekAndPop            : _onCancelPeekAndPop,
  onFinishPeekAndPop            : _onFinishPeekAndPop,
  onClosePeekAndPop             : _onFinishPeekAndPop,
  onPressStart                  : _onPressStart,
  onPressUpdate                 : _onPressUpdate,
  onPressEnd                    : _onPressEnd,
  treshold                      : 0.5,
  startPressure                 : 0.125,
  peakPressure                  : 1.0,
  peekScale                     : 0.5,
  peekCoefficient               : 0.05,
  popTransition})
  
Widget uiChild() {}

Widget peekAndPopBuilder(BuildContext context, PeekAndPopControllerState _peekAndPopController);

QuickActionsData quickActionsBuilder(PeekAndPopControllerState _peekAndPopController);

Widget overlayBuiler();

bool _willPeekAndPopComplete(PeekAndPopControllerState _peekAndPopController);
bool _willPushPeekAndPop(PeekAndPopControllerState _peekAndPopController);
bool _willUpdatePeekAndPop(PeekAndPopControllerState _peekAndPopController);
bool _willCancelPeekAndPop(PeekAndPopControllerState _peekAndPopController);
bool _willFinishPeekAndPop(PeekAndPopControllerState _peekAndPopController);
bool _willClosePeekAndPop(PeekAndPopControllerState _peekAndPopController);

void _onPeekAndPopComplete(PeekAndPopControllerState _peekAndPopController);
void _onPushPeekAndPop(PeekAndPopControllerState _peekAndPopController);
void _onUpdatePeekAndPop(PeekAndPopControllerState _peekAndPopController);
void _onCancelPeekAndPop(PeekAndPopControllerState _peekAndPopController);
void _onFinishPeekAndPop(PeekAndPopControllerState _peekAndPopController);
void _onClosePeekAndPop(PeekAndPopControllerState _peekAndPopController);

void _onPressStart(dynamic dragDetails);
void _onPressUpdate(dynamic dragDetails);
void _onPressEnd(dynamic dragDetails);
 

进一步说明

有关所有参数和方法的完整说明,请参阅文档

  • 如果您的 [uiChild] 在 Peek & Pop 过程中不发生变化,请将 [uiChildUseCache] 设置为 true。
  • 如果您的 [peekAndPopBuilder] 在 Peek & Pop 过程中不发生变化,请将 [peekAndPopBuilderUseCache] 设置为 true。
  • [overlayBuilder] 是一个可选的第二视图,将在 Peek & Pop 过程中显示。整个小部件将在其他所有内容之后构建。
  • 对于所有 [PeekAndPopProcessNotifier] 回调,如 [willPeekAndPopComplete],您可以返回 false 以阻止默认操作。
  • 所有 [PeekAndPopProcessNotifier] 和 [PeekAndPopProcessCallback] 回调将返回一个对创建的 [PeekAndPopController] 状态的引用。
    您可以保存此实例以供将来使用。
  • [pageTransition] 是在直接打开视图或关闭视图时使用的过渡。默认提供了一个 [SlideTransition]。
  • 使用 [PeekAndPopControllerState] 的 [void closePeekAndPop()] 方法关闭 Peek & Pop 过程。不要直接调用 [Navigator.of(context).pop()]。
    直接调用。
  • 使用 [PeekAndPopControllerState] 的 [stage] 变量获取 Peek & Pop 过程阶段的枚举。如果您只想知道 Peek & Pop 过程
    何时将完成或已完成,您也可以使用 [willBeDone] 或 [isDone] 变量。
  • 我注意到,当 [AppBar] 或 [CupertinoNavigationBar] 构建为完全透明时,它们的高度未包含在 [Scaffold]
    或 [CupertinoPageScaffold] 的布局中。因此,从具有透明头的 Peek 阶段移动到具有非透明头的 Pop 阶段
    会导致视觉冲突。使用此 [PeekAndPopChildState] 的 [Size get headerSize] 和 [double getHeaderOffset(HeaderOffset headerOffset)] 方法来
    解决此问题。

GitHub

https://github.com/aliyigitbireroglu/flutter-peek-and-pop