赞
踩
highlight: an-old-hope
CompositedTransformTarget 合成变换目标 CompositedTransformFollower 合成变换伴随者
这两个组件已加入 FlutterUnit, 可更新查看,顺便 star ~。
| CompositedTransformTarget | CompositedTransformFollower | | ---- | ---- | | |
|
Slider
组件开始说起其实之前这两个组件我一直都不知道它们是干嘛用的,直到有一天我在看 Slider
的源码时发现了他俩。我们都知道,当 Slider
组件设置了 label
和 divisions
时,在拖动的过程中会弹出 Overlay
提示框。
当我们使用 Transform
将 Slider
进行旋转变换,可以发现Overlay
浮层也进行了相应的旋转变换。如果在不知道 CompositedTransformTarget
和 CompositedTransformFollower
组件之前,也许你会以为这个变换是在 Slider 源码中算出来作用在 Overlay
浮层上,其实不然。
dart Transform( transform: Matrix4.rotationZ(-15/180*pi), alignment: Alignment.center, child: Slider( ... ), ),
CompositedTransformFollower
是伴随者,可以看成跟屁虫
。在 Slider 组件中 Overlay
对应的组件的外层包裹了 CompositedTransformFollower
,表示其身份是一个伴随者。
在 Slider
核心构建组件 _SliderRenderObjectWidget
的外层包裹了 CompositedTransformTarget
。标志着其为被跟随的目标
。两者通过 _layerLink
订立连接的契约,从而达到 变换与共
的效果。
用这两个组件有什么好处呢?其实很明显。在不知道这两个组件之前,我们是如何确定 Overlay
的位置呢?一个字:算
。通过 Positioned
组件和组件位置信息得到确切位置,对于一些静态的Overlay
框,也许可行。但是如果伴随滑动
,旋转
、缩放
时,那必须通过计算来更新 Overlay
的位置,这显然是非常麻烦的。
Slider
作为框架的源码组件,是比较复杂的,不是所有人都有耐心一点点分享。为了方便演示这两者的使用,我特意准备了几个精简的演示案例。
现在要实现如下效果:点击时,在组件的左上角显示一个 Overlay
提示信息,再点击则隐藏。如果先不看下面的实现,你可能会想到使用 Positioned
组件,通过RenderBox
算出组件的左上角的 绝对坐标
来放置 Overlay
。这样算起来是比较麻烦的,而且有些人估计也不知道怎么算。
整体逻辑很简单,测试demo中目标组件是Image
,上层包裹了 CompositedTransformTarget
。在点击时,执行 _toggleOverlay
方法来切换 Overlay
的显隐情况。
```dart class TipBox extends StatefulWidget { TipBox({Key key}) : super(key: key); @override _TipBoxState createState() => _TipBoxState(); }
class _TipBoxState extends State { final LayerLink layerLink = LayerLink(); OverlayEntry _overlayEntry; bool show = false;
@override Widget build(BuildContext context) { return GestureDetector( onTap: toggleOverlay, child: CompositedTransformTarget( link: layerLink, child: Image.asset( "assets/images/iconhead.webp", width: 80, height: 80, ), ), ); }
void _toggleOverlay() { if (!show) { _showOverlay(); } else { _hideOverlay(); } show = !show; }
void showOverlay() { _overlayEntry = _createOverlayEntry(); Overlay.of(context).insert(overlayEntry); }
void _hideOverlay() { _overlayEntry?.remove(); } } ```
伴随组件是浮窗内容
,上层包裹了 CompositedTransformFollower
。由于默认清空下 OverlayEntry
的约束条件会强行撑满全屏,可以使用 UnconstrainedBox
来解除约束。通过两个组件的伴随,实现了在不通过计算的情况下,使 Overlay
停留在目标组件的左上角。
dart OverlayEntry _createOverlayEntry() => OverlayEntry( builder: (BuildContext context) => UnconstrainedBox( child: CompositedTransformFollower( link: layerLink, child: Material( child: Container( alignment: Alignment.center, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(5)), padding: const EdgeInsets.all(10), width: 50, child: const Text("toly",style: TextStyle(color: Colors.white),)), ), ), ), );
可能有人会问,可以控制 Overlay
停留的位置吗,实现偏移或者对齐。对于伴随者
可以设置 offset(偏移)
、targetAnchor(目标锚点)
、followerAnchor(伴随者锚点)
来控制停留的位置。
比如下面,通过设置对齐方式
和偏移
可以实现:Overlay
置于对应组件的左侧。
dart followerAnchor: Alignment.centerLeft, targetAnchor: Alignment.centerRight, offset: Offset(5,0),
也可以放置在对应组件上方,其实有了对齐方式,你想放在哪都行。由于是相对位置,就省去了很多不必要的计算。
dart followerAnchor: Alignment.bottomCenter, targetAnchor: Alignment.topCenter, offset: Offset(0,-5),
结合我的 Wrapper
组件(wrapper: ^1.0.1
),这样就可以很轻松实现点击弹出浮框的效果。
dart OverlayEntry _createOverlayEntry() => OverlayEntry( builder: (BuildContext context) => UnconstrainedBox( child: CompositedTransformFollower( link: layerLink, followerAnchor: Alignment.bottomCenter, targetAnchor: Alignment.topCenter, offset: Offset(0,-5), child: Material( child: Container( width: 150, child: Wrapper( color: Colors.white, spineType: SpineType.bottom, elevation: 1, offset:70, shadowColor: Colors.grey.withAlpha(88), child: Text("张风捷特烈 " * 5), ), ), ), ), ));
通过设置对其方位,很容易控制位置。如果通过传统的 Positioned
组件,想换个位置,还需要一通计算。用着两个哥们,就非常方便。
像这种图标点击的 Overlay
提示栏,使用着两个哥们就很好定位。
如果说有杠精说:不用这俩,我就喜欢算,怎么啦。
但变换一致性的保存是之前很难办到的。这里我将滑动也是为一种变换,滑动本质上也是一种平移变换
。
旋转:
dart Transform( transform: Matrix4.rotationZ(-15/180*pi), alignment: Alignment.center, child: TipBox(), ),
缩放:
dart Transform( transform: Matrix4.diagonal3Values(0.5,0.5,1), alignment: Alignment.center, child: TipBox(), ),
斜切:
dart Transform( transform: Matrix4.skewX(15/180*pi), alignment: Alignment.center, child: TipBox(), ),
平移:
dart Transform( transform: Matrix4.translationValues(150,0,0), alignment: Alignment.center, child: TipBox(), ),
很明显,CompositedTransformFollower 会伴随 CompositedTransformTarget 进行变换,这样无论在滑动、缩放、旋转等操作中,两者都会保持相对的绑定关系,无需计算,皆大欢喜。
先给个答案,并非。如下,在 Stack
中,两个普通的组件也可以保持绑定关系
。但话说回来,这样做并没有什么意义。普通组件间的对其布局很完善,Flex
、Wrap
都可以,并不需要这两个哥们插一脚。而 Overlay
作为一个 孤魂野鬼
,需要有个绳把它拴着。
```dart class TipBox extends StatelessWidget{ final LayerLink layerLink = LayerLink();
@override Widget build(BuildContext context) { return Stack( children: [ CompositedTransformTarget( link: layerLink, child: Image.asset( "assets/images/icon_head.webp", width: 50, height: 50, ), ),
- CompositedTransformFollower(
- link: layerLink,
- followerAnchor: Alignment.topLeft,
- targetAnchor: Alignment.topRight,
- offset: Offset(5,0),
- child: Material(
- child: Container(
- width: 150,
- child: Wrapper(
- color: Color(0xff95EC69),
- spineType: SpineType.left,
- elevation: 1,
- offset:20,
- shadowColor: Colors.grey.withAlpha(88),
- child: Text("张风捷特烈 " * 5),
- ),
- ),
- ),
- ),
- ],
- );

} } ```
那本文就到这里,谢谢观看~
@张风捷特烈 2021.04.02 未允禁转
我的公众号:编程之王
联系我--邮箱:1981462002@qq.com -- 微信:zdl1994328
~ END ~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。