Flutter强制重绘插件repaint的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter强制重绘插件 repaint 的使用

repaint 是一个用于创建和管理画布的库,类似于 CustomPaint,但提供了更多功能。本文将介绍如何使用该插件,并提供完整的示例代码。

如何使用

处理鼠标事件

为了处理鼠标事件,可以通过重写 onPointerEvent 方法来实现:

@override
@mustCallSuper
void onPointerEvent(PointerEvent event) {
  switch (event.runtimeType) {
    case PointerDownEvent:
    case PointerUpEvent:
    case PointerCancelEvent:
    case PointerPanZoomStartEvent:
    case PointerPanZoomUpdateEvent:
    case PointerPanZoomEndEvent:
    case PointerScrollEvent:
    case PointerSignalEvent:
    case PointerHoverEvent:
      break;
    case PointerMoveEvent e:
      // 在鼠标拖动时移动 [_rect] 通过 [_offset]
      final rect = _rect.shift(_offset);
      if (!rect.contains(e.localPosition)) return;
      _offset += e.delta;
  }
}

处理键盘事件

使用 HardwareKeyboard 管理器

你可以使用 HardwareKeyboard 来处理键盘事件:

bool _onKeyEvent(KeyEvent event) {
  if (event.deviceType != KeyEventDeviceType.keyboard) return false;
  if (event is! KeyDownEvent) return false;

  // F1 - 执行某些操作
  switch (event.logicalKey) {
    case LogicalKeyboardKey.f1:
      doSomething();
      return true;
    default:
      return false;
  }
}

@override
void mount(_, __) {
  HardwareKeyboard.instance.addHandler(_onKeyEvent);
}

@override
void unmount() {
  HardwareKeyboard.instance.removeHandler(_onKeyEvent);
}

使用 Focus 小部件

你也可以通过包裹 RePaint 小部件并使用 Focus 来处理键盘事件:

final painter = RePainterImpl();

Widget build(BuildContext context) {
  return Focus(
    onKeyEvent: painter.onKeyEvent,
    child: RePaint(
      painter: painter,
    ),
  );
}

完整示例 Demo

下面是一个完整的示例,展示了如何使用 repaint 插件进行基本的绘图操作,并处理鼠标和键盘事件:

import 'package:flutter/material.dart';
import 'package:repaint/repaint.dart';

class MyPainter extends RePainterImpl {
  Offset _offset = Offset.zero;
  Rect _rect = Rect.fromLTWH(50, 50, 200, 100);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;

    canvas.drawRect(_rect.shift(_offset), paint);
  }

  @override
  bool shouldRepaint(covariant RePainter oldDelegate) {
    return true; // 强制重绘
  }

  @override
  void onPointerEvent(PointerEvent event) {
    switch (event.runtimeType) {
      case PointerDownEvent:
      case PointerUpEvent:
      case PointerCancelEvent:
      case PointerPanZoomStartEvent:
      case PointerPanZoomUpdateEvent:
      case PointerPanZoomEndEvent:
      case PointerScrollEvent:
      case PointerSignalEvent:
      case PointerHoverEvent:
        break;
      case PointerMoveEvent e:
        final rect = _rect.shift(_offset);
        if (!rect.contains(e.localPosition)) return;
        _offset += e.delta;
        markNeedsPaint(); // 标记需要重绘
    }
  }

  bool _onKeyEvent(KeyEvent event) {
    if (event.deviceType != KeyEventDeviceType.keyboard) return false;
    if (event is! KeyDownEvent) return false;

    switch (event.logicalKey) {
      case LogicalKeyboardKey.arrowLeft:
        _offset = Offset(_offset.dx - 10, _offset.dy);
        markNeedsPaint();
        return true;
      case LogicalKeyboardKey.arrowRight:
        _offset = Offset(_offset.dx + 10, _offset.dy);
        markNeedsPaint();
        return true;
      case LogicalKeyboardKey.arrowUp:
        _offset = Offset(_offset.dx, _offset.dy - 10);
        markNeedsPaint();
        return true;
      case LogicalKeyboardKey.arrowDown:
        _offset = Offset(_offset.dx, _offset.dy + 10);
        markNeedsPaint();
        return true;
      default:
        return false;
    }
  }

  @override
  void mount(_, __) {
    HardwareKeyboard.instance.addHandler(_onKeyEvent);
  }

  @override
  void unmount() {
    HardwareKeyboard.instance.removeHandler(_onKeyEvent);
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final painter = MyPainter();

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Repaint Example')),
        body: Center(
          child: Focus(
            onKeyEvent: painter.onKeyEvent,
            child: Repaint(
              painter: painter,
              size: Size.infinite,
            ),
          ),
        ),
      ),
    );
  }
}

这个示例展示了如何使用 repaint 插件进行自定义绘制,并通过鼠标和键盘事件来更新绘制内容。希望这些信息对你有所帮助!


更多关于Flutter强制重绘插件repaint的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter强制重绘插件repaint的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,RepaintBoundary 小部件和 RepaintBoundary 类的 markNeedsPaint 方法结合使用,可以实现强制重绘。虽然 Flutter 并没有一个直接名为 repaint 的插件,但你可以通过编程方式触发重绘。

以下是一个示例代码,展示如何使用 RepaintBoundarymarkNeedsPaint 来强制重绘一个小部件:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Repaint Boundary Example'),
        ),
        body: Center(
          child: RepaintBoundaryExample(),
        ),
      ),
    );
  }
}

class RepaintBoundaryExample extends StatefulWidget {
  @override
  _RepaintBoundaryExampleState createState() => _RepaintBoundaryExampleState();
}

class _RepaintBoundaryExampleState extends State<RepaintBoundaryExample> {
  GlobalKey _repaintBoundaryKey = GlobalKey();

  void _forceRepaint() {
    final RenderRepaintBoundary boundary =
        _repaintBoundaryKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
    if (boundary != null) {
      boundary.markNeedsPaint();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        RepaintBoundary(
          key: _repaintBoundaryKey,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            child: Center(
              child: Text(
                'Repaint Me',
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: _forceRepaint,
          child: Text('Force Repaint'),
        ),
      ],
    );
  }
}

代码说明:

  1. RepaintBoundary 小部件

    • RepaintBoundary 是一个小部件,它用于在渲染树中创建一个边界,该边界内的内容在需要时可以被单独重绘。
    • 使用 GlobalKey 来获取 RepaintBoundary 的渲染对象。
  2. _forceRepaint 方法

    • 这个方法通过 GlobalKey 获取 RepaintBoundaryRenderRepaintBoundary 对象。
    • 调用 markNeedsPaint 方法强制重绘 RepaintBoundary 内的内容。
  3. UI 结构

    • 一个 Container 被包裹在 RepaintBoundary 中,该 Container 有一个蓝色的背景和一些文本。
    • 一个 ElevatedButton 用于触发 _forceRepaint 方法。

当你点击按钮时,RepaintBoundary 内的内容将被强制重绘,即使其内容没有改变。这在某些需要动画或动态更新UI但不想重新构建整个小部件树的场景中非常有用。

回到顶部