flutter添加全局水印

文章介绍了如何在Flutter应用中使用DisableScreenshots插件来防止屏幕截图,包括初始化、添加水印和取消水印的方法,以及适用于Android平台的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果:
在这里插入图片描述

可以直接引用:disable_screenshots: ^0.2.0
但是有时候直接引用会报错,可以不引用插件直接把下面的源码工具类放在项目里面
工具类源码:


import 'dart:io';
import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';

class DisableScreenshots {
  DisableScreenshots.private(this._methodChannel, this._eventChannel);

  static   DisableScreenshots? _instance/* = DisableScreenshots.private()*/;

  factory DisableScreenshots() {
    if (_instance == null) {
      final MethodChannel methodChannel = const MethodChannel(
          "com.devlxx.DisableScreenshots/disableScreenshots");
      final EventChannel eventChannel =
      const EventChannel('com.devlxx.DisableScreenshots/observer');
      _instance = DisableScreenshots.private(methodChannel, eventChannel);
    }
    return _instance!;
  }

  

  final MethodChannel _methodChannel;
  final EventChannel _eventChannel;
  Stream<void>? _onScreenShots=null;

  OverlayEntry? _overlayEntry;

  void addWatermark(BuildContext context, String watermark,
      {int rowCount = 3, int columnCount = 10, TextStyle? textStyle}) async {
    if (_overlayEntry != null) {
      _overlayEntry!.remove();
    }
    OverlayState? overlayState = Overlay.of(context);
    _overlayEntry = OverlayEntry(
        builder: (context) => DisableScreenshotsWatarmark(
          rowCount: rowCount,
          columnCount: columnCount,
          text: watermark,
          textStyle: textStyle ??
              const TextStyle(
                  color: Color(0x08000000),
                  fontSize: 18,
                  decoration: TextDecoration.none),
        ));
    overlayState?.insert(_overlayEntry!);
    // return await _methodChannel.invokeMethod<void>("addWatermark", ['我是水印']);
  }

  void addCustomWatermark(BuildContext context, Widget widget) {
    if (_overlayEntry != null) {
      _overlayEntry!.remove();
    }
    OverlayState? overlayState = Overlay.of(context);
    _overlayEntry = OverlayEntry(builder: (context) => widget);
    overlayState?.insert(_overlayEntry!);
  }

  void removeWatermark() async {
    if (_overlayEntry != null) {
      _overlayEntry!.remove();
      _overlayEntry = null;
    }
  }

  Stream<void> get onScreenShots {
    if (_onScreenShots == null) {
      _onScreenShots = _eventChannel.receiveBroadcastStream();
    }
    return _onScreenShots!;
  }

  /// 只支持安卓
  Future<void> disableScreenshots(bool disable) async {
    if (Platform.isAndroid) {
      return await _methodChannel
          .invokeMethod("disableScreenshots", {"disable": disable});
    } else {
      print('仅Android平台支持禁用屏幕截图');
    }
  }
}

class DisableScreenshotsWatarmark extends StatelessWidget {
  final int rowCount;
  final int columnCount;
  final String text;
  final TextStyle textStyle;

  const DisableScreenshotsWatarmark({
    Key? key,
    required this.rowCount,
    required this.columnCount,
    required this.text,
    required this.textStyle,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return IgnorePointer(
      child: Container(
          child: Column(
            children: creatColumnWidgets(),
          )),
    );
  }

  List<Widget> creatRowWdiges() {
    List<Widget> list = [];
    for (var i = 0; i < rowCount; i++) {
      final widget = Expanded(
          child: Center(
              child: Transform.rotate(
                  angle: pi / 10, child: Text(text, style: textStyle))));
      list.add(widget);
    }
    return list;
  }

  List<Widget> creatColumnWidgets() {
    List<Widget> list = [];
    for (var i = 0; i < columnCount; i++) {
      final widget = Expanded(
          child: Row(
            children: creatRowWdiges(),
          ));
      list.add(widget);
    }
    return list;
  }
}


使用:

初始化

waterMarkerPlugin 要创建为全局的

  // 初始化水印插件
  static  DisableScreenshots waterMarkerPlugin = DisableScreenshots();

添加水印

//添加水印
 Params.waterMarkerPlugin.addWatermark(
          context,
          '默认水印',
          rowCount: 4,
          columnCount: 8);

取消水印

  //取消水印
    Params.waterMarkerPlugin.removeWatermark();
<think>我们正在处理一个关于在Flutter中实现图层功能的问题。用户希望实现图层的建立、修改和删除。在Flutter中,我们可以通过自定义绘制(CustomPaint)和图层管理(例如使用Stack和Positioned)来实现类似图层的功能。同时,我们也可以参考一些图形库(如flutter_canvas)来实现更高级的图层操作。 根据引用[4],我们知道在Flutter中,状态管理是非常重要的。因此,我们将使用StatefulWidget来管理图层的状态(包括图层的添加、修改和删除)。 设计思路: 1. 使用一个List<Layer>来存储所有的图层,每个图层包含其属性(如位置、大小、内容等)。 2. 使用CustomPaint或Stack来绘制多个图层(每个图层可以是一个Widget或者一个自定义绘制的对象)。 3. 提供方法来添加图层(建立)、修改图层的属性(修改)和从列表中移除图层(删除)。 步骤: 1. 定义图层的数据结构(Layer类)。 2. 创建管理图层的状态类(使用StatefulWidget的状态管理)。 3. 实现图层的绘制(通过遍历图层列表进行绘制)。 4. 实现图层操作的方法(添加、修改、删除)。 注意:引用[1]提到Flutter代码中括号嵌套的问题,因此我们将尽可能拆分组件,使代码清晰。 具体实现: 第一步:定义图层类 我们可以定义一个基类Layer,然后根据不同类型的图层(如形状、图片、文本等)派生出不同的子类。但为了简化,我们先实现一个通用的图层,包含一个自定义绘制的方法(如果使用CustomPaint)或者一个Widget(如果使用Stack)。 这里我们采用两种方式都可以,但考虑到图层可能包含复杂的交互和自定义绘制,我们使用CustomPaint来绘制自定义图形,而对于图片、文本等,我们可以使用常规的Widget。因此,我们选择使用Stack来叠图层,每个图层是一个Widget,并且可以自由控制位置和大小。 第二步:状态管理 我们将使用StatefulWidget,并在其状态类中维护一个图层列表(List<Widget>)。但是注意,每个图层需要能够被独立修改,所以每个图层应该是一个有唯一标识的对象,这样我们才能修改或删除它。 因此,我们定义: class Layer { final String id; // 唯一标识 Offset position; // 位置 Widget child; // 图层内容 // 其他属性,如大小、旋转等 } 第三步:实现图层操作 - 添加图层:生成一个新的Layer对象,入列表。 - 修改图层:根据id找到对应的图层,更新其属性。 - 删除图层:根据id从列表中移除。 第四步:绘制图层 使用Stack组件,将所有的图层按照顺序(列表顺序)绘制出来,每个图层使用Positioned来定位。 代码结构: 1. 定义Layer类: ```dart class Layer { final String id; Offset position; Widget child; Layer({ required this.id, required this.position, required this.child, }); } ``` 2. 创建图层管理Widget(StatefulWidget): ```dart class LayerManager extends StatefulWidget { const LayerManager({Key? key}) : super(key: key); @override _LayerManagerState createState() => _LayerManagerState(); } class _LayerManagerState extends State<LayerManager> { final List<Layer> _layers = []; void addLayer(Layer layer) { setState(() { _layers.add(layer); }); } void updateLayer(String id, Layer newLayer) { setState(() { final index = _layers.indexWhere((layer) => layer.id == id); if (index != -1) { _layers[index] = newLayer; } }); } void removeLayer(String id) { setState(() { _layers.removeWhere((layer) => layer.id == id); }); } @override Widget build(BuildContext context) { return Stack( children: _layers.map((layer) { return Positioned( left: layer.position.dx, top: layer.position.dy, child: layer.child, ); }).toList(), ); } } ``` 3. 使用示例: 在某个Widget中,我们可以通过_LayerManagerState的方法来操作图层。 但是,注意:我们无法直接获取_LayerManagerState,因此需要使用GlobalKey。 示例使用: ```dart class LayerExample extends StatefulWidget { const LayerExample({Key? key}) : super(key: key); @override _LayerExampleState createState() => _LayerExampleState(); } class _LayerExampleState extends State<LayerExample> { final GlobalKey<_LayerManagerState> _layerManagerKey = GlobalKey(); @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( onPressed: () { // 添加一个图层 _layerManagerKey.currentState?.addLayer( Layer( id: UniqueKey().toString(), position: Offset(100, 100), child: Container( width: 100, height: 100, color: Colors.red, ), ), ); }, child: Text('添加图层'), ), Expanded( child: LayerManager(key: _layerManagerKey), ), ], ); } } ``` 注意:这里使用GlobalKey来操作子组件的状态,在实际项目中,如果状态提升更合适,可以考虑将图层列表提升到父组件,然后通过回调传递操作。 另外,修改和删除操作类似,需要先获取图层的id,然后调用对应方法。 但是,上述实现中,Layer类中的child是Widget,这意味着我们可以添加任何Widget作为图层内容。同时,我们使用Positioned定位,因此图层可以重叠。 优化: - 为了更好的性能,我们可以使用IndexedStack或Overlay,但Overlay是全局的,而这里我们只需要在局部管理。 - 如果图层很多,可以考虑使用ListView.builder或PageView,但这里我们使用Stack,因为图层需要叠。 此外,引用[2]中提到了全局水印的实现,我们可以借鉴其思路,将图层管理作为底层,然后在其上叠其他内容。但是这里我们不需要全局,而是局部管理。 引用[3]提到了毛玻璃效果,如果我们需要在图层上实现特殊效果,可以借鉴。 总结: 以上实现了一个简单的图层管理功能,包括建立(addLayer)、修改(updateLayer)和删除(removeLayer)图层。每个图层可以是一个任意Widget,并且可以定位。 但是,如果我们需要更复杂的图形操作(如绘制路径、形状等),则可以使用CustomPaint作为图层的child,这样每个图层可以是一个自定义绘制。 例如,我们可以自定义一个绘制圆形的图层: ```dart class CircleLayer extends CustomPainter { final Color color; final double radius; CircleLayer({required this.color, required this.radius}); @override void paint(Canvas canvas, Size size) { final paint = Paint()..color = color; canvas.drawCircle(Offset.zero, radius, paint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; } ``` 然后,在添加图层时: ```dart _layerManagerKey.currentState?.addLayer( Layer( id: UniqueKey().toString(), position: Offset(100, 100), child: CustomPaint( painter: CircleLayer(color: Colors.blue, radius: 50), ), ), ); ``` 这样,我们就能够绘制自定义图形了。 注意:每个图层的位置由Positioned控制,而CustomPaint的绘制原点在Positioned的左上角。因此,在绘制圆形时,我们画在(0,0)点,那么实际位置就是Positioned的left和top。 最后,关于图层的修改,我们可以通过更新整个Layer对象来实现。例如,改变位置或改变绘制的属性(如颜色、半径等),需要重新创建一个CustomPaint,因为CustomPainter是不可变的。 因此,在更新图层时,我们需要根据新的属性创建一个新的child,然后替换整个Layer对象(因为Layer类中的child是Widget,而Widget是不可变的)。 以上就是在Flutter中实现图层功能的基本方法。 相关问题: 1. 如何实现图层的拖拽和缩放? 2. 如何实现图层的层级调整(置顶、置底)? 3. 如何将图层内容保存为图片?</think>在 Flutter 中实现图层功能可以通过自定义图层管理类和状态管理来实现。以下是一个完整的实现方案,包含图层建立、修改和删除功能: ### 一、图层数据结构设计 ```dart class CanvasLayer { final String id; String name; bool isVisible; double opacity; List<Widget> elements; // 图层中的元素 CanvasLayer({ required this.id, required this.name, this.isVisible = true, this.opacity = 1.0, this.elements = const [], }); // 复制图层(用于修改) CanvasLayer copyWith({ String? name, bool? isVisible, double? opacity, List<Widget>? elements, }) { return CanvasLayer( id: id, name: name ?? this.name, isVisible: isVisible ?? this.isVisible, opacity: opacity ?? this.opacity, elements: elements ?? this.elements, ); } } ``` ### 二、图层管理类实现 ```dart class LayerManager with ChangeNotifier { final List<CanvasLayer> _layers = []; int _currentLayerIndex = 0; List<CanvasLayer> get layers => _layers; CanvasLayer? get currentLayer => _layers.isNotEmpty ? _layers[_currentLayerIndex] : null; // 添加新图层 void addLayer(String name) { _layers.add(CanvasLayer( id: const Uuid().v4(), // 使用uuid生成唯一ID name: name, )); _currentLayerIndex = _layers.length - 1; notifyListeners(); } // 删除图层 void removeLayer(String layerId) { _layers.removeWhere((layer) => layer.id == layerId); if (_currentLayerIndex >= _layers.length) { _currentLayerIndex = _layers.length - 1; } notifyListeners(); } // 修改图层属性 void updateLayer(String layerId, { String? name, bool? isVisible, double? opacity, }) { final index = _layers.indexWhere((layer) => layer.id == layerId); if (index != -1) { _layers[index] = _layers[index].copyWith( name: name, isVisible: isVisible, opacity: opacity, ); notifyListeners(); } } // 添加元素到当前图层 void addElementToCurrent(Widget element) { if (currentLayer != null) { final newElements = [...currentLayer!.elements, element]; _layers[_currentLayerIndex] = currentLayer!.copyWith( elements: newElements, ); notifyListeners(); } } // 切换当前图层 void setCurrentLayer(String layerId) { final index = _layers.indexWhere((layer) => layer.id == layerId); if (index != -1) { _currentLayerIndex = index; notifyListeners(); } } } ``` ### 三、UI 实现(图层管理界面) ```dart class LayerManagementScreen extends StatelessWidget { @override Widget build(BuildContext context) { final layerManager = Provider.of<LayerManager>(context); return Scaffold( appBar: AppBar(title: const Text('图层管理')), body: Column( children: [ // 添加新图层按钮 ElevatedButton( onPressed: () => _showAddLayerDialog(context), child: const Text('新建图层'), ), // 图层列表 Expanded( child: ListView.builder( itemCount: layerManager.layers.length, itemBuilder: (context, index) { final layer = layerManager.layers[index]; return _buildLayerItem(layer, layerManager); }, ), ), ], ), ); } Widget _buildLayerItem(CanvasLayer layer, LayerManager manager) { return ListTile( title: Text(layer.name), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.edit), onPressed: () => _showEditLayerDialog(context, layer), ), IconButton( icon: const Icon(Icons.delete), onPressed: () => manager.removeLayer(layer.id), ), ], ), leading: Checkbox( value: layer.isVisible, onChanged: (value) => manager.updateLayer( layer.id, isVisible: value ), ), onTap: () => manager.setCurrentLayer(layer.id), ); } void _showAddLayerDialog(BuildContext context) { final layerManager = Provider.of<LayerManager>(context, listen: false); final controller = TextEditingController(); showDialog( context: context, builder: (context) => AlertDialog( title: const Text('新建图层'), content: TextField( controller: controller, decoration: const InputDecoration(labelText: '图层名称'), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { if (controller.text.isNotEmpty) { layerManager.addLayer(controller.text); Navigator.pop(context); } }, child: const Text('创建'), ), ], ), ); } void _showEditLayerDialog(BuildContext context, CanvasLayer layer) { final layerManager = Provider.of<LayerManager>(context, listen: false); final controller = TextEditingController(text: layer.name); showDialog( context: context, builder: (context) => AlertDialog( title: const Text('编辑图层'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField(controller: controller), const SizedBox(height: 16), Row( children: [ const Text('不透明度:'), Expanded( child: Slider( value: layer.opacity, onChanged: (value) => layerManager.updateLayer( layer.id, opacity: value ), ), ), ], ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { layerManager.updateLayer(layer.id, name: controller.text); Navigator.pop(context); }, child: const Text('保存'), ), ], ), ); } } ``` ### 四、主画布实现(使用图层) ```dart class MainCanvas extends StatelessWidget { @override Widget build(BuildContext context) { final layerManager = Provider.of<LayerManager>(context); return Consumer<LayerManager>( builder: (context, manager, child) { return Stack( children: [ // 背景 Container(color: Colors.white), // 所有可见图层 ...manager.layers.where((l) => l.isVisible).expand((layer) { return layer.elements.map((element) { return Opacity( opacity: layer.opacity, child: element, ); }); }), // 添加元素按钮 Positioned( bottom: 20, right: 20, child: FloatingActionButton( onPressed: () => _addRandomElement(context), child: const Icon(Icons.add), ), ), ], ); }, ); } void _addRandomElement(BuildContext context) { final layerManager = Provider.of<LayerManager>(context, listen: false); final random = Random(); final element = Positioned( left: random.nextDouble() * 300, top: random.nextDouble() * 500, child: Container( width: 50 + random.nextDouble() * 100, height: 50 + random.nextDouble() * 100, color: Color.fromRGBO( random.nextInt(256), random.nextInt(256), random.nextInt(256), 1.0, ), ), ); layerManager.addElementToCurrent(element); } } ``` ### 五、集成到应用 ```dart void main() { runApp( ChangeNotifierProvider( create: (context) => LayerManager(), child: MaterialApp( home: Scaffold( body: Stack( children: [ MainCanvas(), // 全局水印效果(引用[2]) WatermarkOverlay(), ], ), floatingActionButton: FloatingActionButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => LayerManagementScreen(), ), ); }, child: const Icon(Icons.layers), ), ), ), ), ); } // 全局水印组件(引用[2]) class WatermarkOverlay extends StatelessWidget { @override Widget build(BuildContext context) { return IgnorePointer( child: Container( foregroundDecoration: const BoxDecoration( image: DecorationImage( image: AssetImage('watermark.png'), repeat: ImageRepeat.repeat, opacity: 0.1, ), ), ), ); } } ``` ### 六、关键实现说明 1. **状态管理**: - 使用 `ChangeNotifierProvider` 管理图层状态(引用[4]) - 图层操作自动通知 UI 更新 2. **图层结构**: - 每个图层包含独立元素列表和属性 - 使用 UUID 确保图层唯一标识 3. **性能优化**: - 使用 `Consumer` 局部刷新 - 惰性载图层元素(`where` 过滤不可见图层) 4. **UI 交互**: - 对话框形式管理图层(避免嵌套过深,引用[1]) - 滑块控制图层不透明度 5. **元素管理**: - 元素作为 Widget 存储在图层中 - 支持任意 Flutter Widget 作为图层元素 ### 七、使用示例 ```dart // 添加新图层 layerManager.addLayer("背景层"); // 添加元素到当前图层 layerManager.addElementToCurrent( Positioned( left: 100, top: 100, child: Container(width: 200, height: 200, color: Colors.blue), ) ); // 修改图层属性 layerManager.updateLayer( layerId, name: "新名称", opacity: 0.7, isVisible: false ); // 删除图层 layerManager.removeLayer(layerId); ``` ### 八、高级功能扩展 1. **图层混合模式**: ```dart enum BlendMode { normal, multiply, screen, overlay } class CanvasLayer { BlendMode blendMode = BlendMode.normal; // ... } ``` 2. **图层分组**: ```dart class LayerGroup { List<CanvasLayer> layers = []; bool isCollapsed = false; // ... } ``` 3. **历史记录**: ```dart class LayerHistory { final List<LayerManager> states = []; void saveState(LayerManager manager) { states.add(manager.clone()); } // ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值