CupertinoMagnifier

一个仿iOS风格的放大镜组件,主要用于文本选择或触摸点细节的局部放大显示

CupertinoMagnifier是Flutter中一个仿iOS风格的放大镜组件,主要用于文本选择或触摸点细节的局部放大显示。它模拟了iOS系统的原生放大镜效果,通过悬浮层展示指定区域的放大视图。

核心逻辑

  • 组件通过监听手势位置(如拖拽文本选择手柄)动态定位放大镜。
  • 基于MagnifierController控制放大镜的显示/隐藏和位置更新。
  • 内部使用LayerLink将放大镜与需要放大的内容区域关联,确保放大内容同步。

典型使用场景

  • 文本输入框(CupertinoTextField)中长按拖动选择文本时显示放大镜。
  • 自定义手势交互中需要高精度定位的场景(如地图应用中的坐标点放大)。
  • 配合TextSelectionToolbar实现iOS风格的文字操作界面。

示例

基础文本选择放大镜

import 'package:flutter/cupertino.dart';

class BasicMagnifierDemo extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        child: Center(
          child: CupertinoTextField(
            magnifierConfiguration: TextMagnifierConfiguration(
              magnifierBuilder: (context, controller, value) {
                return CupertinoMagnifier(
                  controller: controller,
                  child: Text(value.text), // 放大镜中显示的文字内容
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}

自定义手势控制的放大镜

import 'package:flutter/cupertino.dart';

class CustomMagnifierDemo extends StatefulWidget {
  
  _CustomMagnifierDemoState createState() => _CustomMagnifierDemoState();
}

class _CustomMagnifierDemoState extends State<CustomMagnifierDemo> {
  final MagnifierController _controller = MagnifierController();
  final LayerLink _layerLink = LayerLink();

  
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        child: Stack(
          children: [
            // 需要放大的内容区域
            CompositedTransformTarget(
              link: _layerLink,
              child: GestureDetector(
                onPanUpdate: (details) {
                  _controller.show(details.localPosition); // 根据手势更新位置
                },
                child: Container(color: CupertinoColors.activeBlue),
              ),
            ),
            // 放大镜组件
            Positioned(
              child: CupertinoMagnifier(
                controller: _controller,
                layerLink: _layerLink,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

适配暗色主题的放大镜

CupertinoMagnifier(
  controller: controller,
  color: CupertinoTheme.of(context).bgColor.withOpacity(0.9), // 根据主题调整颜色
  shadowColor: CupertinoColors.black.withOpacity(0.2),
)

注意点

  • 常见问题与解决方案:

    • 性能瓶颈: 频繁调用controller.show()可能导致帧率下降。建议使用throttledebounce限制调用频率。
    • 兼容性警告: 在非iOS平台使用时,需测试手势响应是否正常(Android可能需额外适配)。
    • 内容同步异常: 若放大镜与目标区域错位,检查LayerLink是否正确绑定到同一CompositedTransformTarget
  • 优化技巧:

    • 通过colorshadowColor属性自定义样式,使其更贴合应用主题。
    • 使用MagnifierControllerhide()方法在无需显示时及时隐藏,减少资源占用。
  • 最佳实践:

    • 优先与CupertinoTextField等官方组件配合使用,避免手动处理复杂手势逻辑。
    • Stack中确保放大镜位于视图顶层,防止被其他组件遮挡。

构造函数

const CupertinoMagnifier({
  Key? key,
  required MagnifierController controller, // 控制放大镜行为的核心控制器
  LayerLink? layerLink, // 关联放大内容区域的链接对象
  Color? color, // 放大镜背景色(默认透明灰)
  Color? shadowColor, // 阴影颜色(默认深灰)
  Widget? child, // 自定义放大镜内部显示的组件
})

属性

属性名属性类型说明
controllerMagnifierController必需。控制放大镜的显示、隐藏和位置更新。
layerLinkLayerLink?可选。绑定到目标内容的链接,确保放大内容同步。
colorColor?放大镜背景颜色,默认值为 CupertinoColors.tertiarySystemFill
shadowColorColor?放大镜阴影颜色,默认值为 CupertinoColors.systemGrey
childWidget?自定义放大镜内部显示的组件,如覆盖默认文本显示。

关键属性详解

  • controller: 必须通过MagnifierController()初始化,并通过show(Offset)方法传入手势位置坐标。这是放大镜动态响应的核心。
  • layerLink: 当需要放大非文本内容(如图片)时,此属性必需。需与CompositedTransformTarget配对使用,否则放大镜无法捕获目标区域。
  • color: 透明度过高可能导致放大内容不清晰,建议使用withOpacity(0.8~0.95)保持可读性。