Flutter 组件集录 | RawMagnifier 组件 - 拿起你的八倍镜
1. 前言
今天看 Flutter 源码,偶然发现 Magnifier
组件,这单词不就是 放大镜
嘛! 再结合新版 Flutter 中输入文本的放大镜效果,直觉告诉我这玩意应该可以放大任何组件。如下所示,背景是一张图片,使用 RawMagnifier
实现了点击拖拽局部放大的效果,看起来还是蛮酷的:
另外,也可以自定义放大镜的形状,如下的五角星:
该组件已收录入 FlutterUnit ,可以在应用中查看相关源码:
桌面端 | 移动端 |
---|---|
![]() | ![]() |
2. RawMagnifier 组件的简单使用
下面来简单使用一下:案例中通过 Stack 将 Image 和 RawMagnifier 叠放在一起,并且居中对齐。可以看到 RawMagnifier
组件的展示内容是对应图片位置的局部放大图。是不是用起来非常简单,就能实现很酷的效果:
class MagnifierExampleApp extends StatelessWidget{
final Size magnifierSize = const Size(120, 120);
const MagnifierExampleApp({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Image.asset('assets/images/sabar_bar.webp'),
_buildMagnifier(),
],
),
),
);
}
Widget _buildMagnifier(){
return RawMagnifier(
decoration: const MagnifierDecoration(
shape: CircleBorder(
side: BorderSide(color: Colors.blue, width: 2),
),
),
size: magnifierSize,
magnificationScale: 3,
);
}
}
强调一点,它可以放大和其叠放的 任何组件
,比如其下放置一个文本组件,展示 张风捷特烈
:
3. RawMagnifier 组件的构造函数
了解了简单使用,下面瞄一眼 RawMagnifier 组件源码中定义的入参,它继承自 StatelessWidget
,看起来并不是很复杂。
属性名 | 类型 | 介绍 | 默认值 |
---|---|---|---|
child | Widget? | 子组件 | null |
decoration | MagnifierDecoration | 装饰对象 | MagnifierDecoration() |
magnificationScale | double | 放大倍数 | 1 |
size | Size | 放大镜尺寸 | required |
focalPointOffset | Size | 中心偏移量 | Offset |
其中尺寸和放大倍数非常好理解,如下 size 改成 150*150
、放大倍数 magnificationScale 改成 8 倍 :
focalPointOffset 表示放大中心的偏移量,如下所示偏移量设为 Offset(-10,0)
, 效果上来看局部区域显示的靠左一点的内容 :
decoration 是一个比较重要的属性,类型为 MagnifierDecoration 。可以配置装饰效果:从源码来看,可以定义放大镜的透明度、阴影和形状:
如下所示,0.9 的透明度可以看出一点底部的图案,去掉了边线。添加阴影:
Widget _buildMagnifier(){
return RawMagnifier(
decoration: MagnifierDecoration(
opacity: 0.9,
shadows: [
BoxShadow(
offset: Offset(1,1),
blurRadius: 4,
spreadRadius: 6,
color: Colors.black.withOpacity(0.1)
)
],
shape: CircleBorder(),
),
size: magnifierSize,
focalPointOffset: Offset(-10, 0),
magnificationScale: 3,
);
}
除此之外, MagnifierDecoration 还有一个 shape 属性,类型为 ShapeBorder
,可以设置放大镜的形状。在 《【Flutter高级玩法-shape】Path在手,天下我有》 一文中详细介绍了该类型的使用。比如下面自定义一个五角星的形状:
class _StarShapeBorder extends ShapeBorder {
final Path _path = Path();
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
@override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
return Path();
}
@override
Path getOuterPath(Rect rect, {TextDirection? textDirection}) =>
nStarPath(5, rect.height / 2, rect.height / 2 * 0.5,
dx: rect.width / 2, dy: rect.height / 2);
@override
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
Paint paint = Paint()..style=PaintingStyle.stroke..color=Colors.blue..strokeWidth =2;
canvas.drawPath(getOuterPath(rect), paint);
}
Path nStarPath(int num, double R, double r, {dx = 0, dy = 0}) {
double perRad = 2 * pi / num;
double radA = perRad / 2 / 2;
double radB = 2 * pi / (num - 1) / 2 - radA / 2 + radA;
_path.moveTo(cos(radA) * R + dx, -sin(radA) * R + dy);
for (int i = 0; i < num; i++) {
_path.lineTo(
cos(radA + perRad * i) * R + dx, -sin(radA + perRad * i) * R + dy);
_path.lineTo(
cos(radB + perRad * i) * r + dx, -sin(radB + perRad * i) * r + dy);
}
_path.close();
return _path;
}
@override
ShapeBorder scale(double t) => this;
}
4. 手势交互
上面就是 RawMagnifier 组件的使用方式,那如何实现按下展示放大镜、拖拽更新位置、抬起取消呢?答案很简单:监听手势事件。首先,由于需要在手势交互中更新位置和显示信息,所以需要 StatefulWidget
进行处理;然后添加如下两个状态数据用于表示放大镜位置和是否显示:
Offset _dragGesturePosition = Offset.zero;
bool _show = false;
然后通过 GestureDetector 组件监听拖拽事件、通过 Positioned 组件控制放大镜的位置:
最后在手势交互中更新两个状态数据即可:
void _onPanDown(DragDownDetails details) {
_dragGesturePosition = details.localPosition-Offset(magnifierSize.width/2,magnifierSize.height/2);
_show = true;
setState(() {
});
}
void _onPanEnd(DragEndDetails details) {
setState(() => _show = false);
}
void _onPanUpdate(DragUpdateDetails details) {
_dragGesturePosition = details.localPosition-Offset(magnifierSize.width/2,magnifierSize.height/2);
setState(() {
});
}
void _onPanCancel() {
setState(() => _show = false);
}
5. Magnifier 组件
总的来说 RawMagnifier 的使用方式还是比较简单的,表现效果却非常炫酷。另外,基于 RawMagnifier 组件,官方还提供了一个 Magnifier
组件便于使用,从源码中可以看出它在构造函数在给了默认的参数:
从构建逻辑中可以看出 Magnifier 组件只是借用了 RawMagnifier 组件,提供一个圆角矩形的装饰形状而言,没有什么非常特别的。
至于 RawMagnifier 内部的实现原理,有机会再单独分析一下。那本文就到这里,谢谢观看~
转载自:https://juejin.cn/post/7246409673564438587