前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter 像素编辑器#02 | 配置编辑

Flutter 像素编辑器#02 | 配置编辑

作者头像
张风捷特烈
发布2024-04-12 08:38:22
1050
发布2024-04-12 08:38:22
举报

本系列,将通过 Flutter 实现一个全平台的像素编辑器应用。源码见开源项目 【pix_editor】

?


上一篇完成了 Flutter 像素编辑器的点击交互,绘制像素。本篇继续完善像素编辑器,划分布局区域,并运行修改项目和画笔的配置。如下所示,是 Flutter 像素编辑器的第二版:

?


1. Flutter 像素编辑器布局结构

在桌面端中,第二版将应用划分为五个区域:

  • 顶部菜单栏 MenuToolBar :放置菜单以及操作按钮。
  • 左侧编辑工具 ToolBar : 放置编辑按钮。
  • 右侧操作面板 OperationArea : 放置配置操作的内容。
  • 底部信息栏 BottomBar : 展示信息。
  • 中间绘制区 EditorArea :交互绘制像素的区域。
image.png
image.png

通过行列布局,结合 Expanded 组件,可以是中间的 EditorArea 绘制区大小自适应窗口。

代码语言:javascript
复制
class PixEditorPage extends StatelessWidget {
  const PixEditorPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      backgroundColor: Colors.white,
      body: Column(
        children: [
          MenuToolBar(),
          Expanded(
              child: Row(
            children: [
              ToolBar(),
              Expanded(child: Column( children: [Expanded(child: EditorArea()), BottomBar()] )),
              OperationArea()
            ],
          )),
        ],
      ),
    );
  }
}

目前 BottomBar、MenuToolBar、ToolBar 三个区域只是简单展示一下,具体功能后续完善。本篇主要着重介绍 OperationArea 操作区,如何影响 EditorArea 绘图区。


2、数据变化的业务逻辑

OperationArea 操作区在编辑时,绘图区的内容需要实时变化。比如下面修改网格的数量,输入过程中绘图区的个数会相对改变:

96.gif
96.gif

所以需要数据的变化可以通知画板进行更新。这里定义 ProjectConfigLogic 类维护配置状态数据,混入 ChangeNotifier 拥有通知监听的能力。其中主要维护 PixEditorConfig 配置数据,并提供一些方法,来修改某个维度的数据。数据变化后通过 notifyListeners 通知更新:

代码语言:javascript
复制
class ProjectConfigLogic with ChangeNotifier {

  late TextEditingController rowCtrl = TextEditingController(text: config.row.toString());
  late TextEditingController columnCtrl = TextEditingController(text: config.column.toString());

  @override
  void dispose() {
    rowCtrl.dispose();
    columnCtrl.dispose();
    super.dispose();
  }

  PixEditorConfig _config = PixEditorConfig(
    column: 5,
    row: 5,
    name: "新建文件",
    backgroundColor: const Color(0xfff0f0f0),
    gridColor: Colors.white,
    showGrid: true,
  );

  PixEditorConfig get config => _config;

  set config(PixEditorConfig config){
    _config = config;
    notifyListeners();
  }

  void updateRow(int row){
    rowCtrl.text = row.toString();
    config = _config.copyWith(row: row);
  }
  void updateBackgroundColor(Color color){
    config = _config.copyWith(backgroundColor: color);
  }
  void updateGridColor(Color color) {
    config = _config.copyWith(gridColor: color);
  }

  void updateColumn(int column){
    columnCtrl.text = column.toString();
    config = _config.copyWith(column: column);
  }

  void toggleShowGrid(){
    config = _config.copyWith(showGrid: !_config.showGrid);
  }
}

3、项目配置的状态数据管理

接下来就需要访问 ProjectConfigLogic 的数据进行界面构建,并触发其方法,修改数据触发更新。这里拿是否展示网格的这条功能需求,介绍一下如何处理:

image.png
image.png

目前功能并不是很复杂,使用 Flutter 内置的 InheritedNotifier 来共享 ProjectConfigLogic 即可。后面功能复杂之后,再考虑使用状态管理的库,来维护 ProjectConfigLogic 的功能。如下所示,定义 ProjectConfigScope 向子树提供状态数据:

代码语言:javascript
复制
class ProjectConfigScope extends InheritedNotifier<ProjectConfigLogic> {
  const ProjectConfigScope({
    required super.notifier,
    required super.child,
    super.key,
  });

  static ProjectConfigLogic of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<ProjectConfigScope>()!.notifier!;

  static ProjectConfigLogic read(BuildContext context) =>
      context.getInheritedWidgetOfExactType<ProjectConfigScope>()!.notifier!;
}

然后再需要共享数据组件们的上层嵌套 ProjectConfigScope,来达到向子树共享数据的目的:

ps:之前在 《 Flutter 组件集录 | InheritedNotifier 内置状态管理组件》 一文中介绍过 InheritedNotifier 的使用。

image.png
image.png

这样,下层的组件可以通过 ProjectConfigScope.of(context) 根据上下文得到 ProjectConfigLogic 业务逻辑对象。对于是否显示网格来说 Checkbox 的 value 可以访问 configLogic 中的数据;点击事件 onChanged 中,通过 configLogic 对象触发 toggleShowGrid 方法,修改是否展示网格的配置数据,并触发更新:

代码语言:javascript
复制
ProjectConfigLogic configLogic = ProjectConfigScope.of(context);

Row(
  children: [
    Text("显示网格", style: TextStyle(fontSize: 12)),
    const SizedBox(width: 8),
    Container(
      width: 20,
      height: 20,
      child: Checkbox(
        value: configLogic.config.showGrid,
        onChanged: (bool? value) {
          configLogic.toggleShowGrid();
        },
      ),
    )
  ],
),

其他的配置项数据的修改同理。


4、绘制信息的状态数据管理

绘制信息中目前增加了画笔的颜色,我们也可以通过业务逻辑层,来封装绘制方面的状态数据。如下定义 PixPaintLogic 来维护像素点列表 _pixCells,以及画笔颜色 _paintColor。这样命中像素点数据变化逻辑,就可以写在 PixPaintLogic 中。

代码语言:javascript
复制
class PixPaintLogic with ChangeNotifier {
  final List<PixCell> _pixCells = [];

  List<PixCell> get pixCells => _pixCells;

  Color get paintColor => _paintColor;

  set paintColor(Color value){
    _paintColor = value;
    notifyListeners();
  }

  Color _paintColor = const Color(0xff5ec8f8);

  // 命中像素点
  void hitPix(int x,int y) {
    bool hasPix = _pixCells.where((e) => e.position == (x, y)).isNotEmpty;
      if (hasPix) {
      _pixCells.removeWhere((e) => e.position == (x, y));
    } else {
      _pixCells.add(PixCell(color: _paintColor, position: (x,y)));
    }
    notifyListeners();
  }
}

同理,提供 PixPaintScope 向子树共享 PixPaintLogic 业务逻辑对象:

image.png
image.png
代码语言:javascript
复制
class PixPaintScope extends InheritedNotifier<PixPaintLogic> {
  const PixPaintScope({
    required super.notifier,
    required super.child,
    super.key,
  });

  static PixPaintLogic of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<PixPaintScope>()!.notifier!;

  static PixPaintLogic read(BuildContext context) =>
      context.getInheritedWidgetOfExactType<PixPaintScope>()!.notifier!;
}

此时剩下最后一件事,如何在两个业务逻辑对象更新时,通知画板进行重新绘制呢? CustomPainter 可以指定 repaint 参数,监听可监听对象,当其进行通知时,会触发画板的重绘。所以只要将两个可监听的,业务逻辑对象传入画板中即可:

image.png
image.png

在共享区域的子树,有上下文的地方,就可以得到业务逻辑对象。这里可以通过 read 方法,让绘制区不建立依赖关系,这样更新时 EditorArea 不会重新构建,仅通知画板进行更新:

image.png
image.png

5、性能方面

目前 100*100 的网格中,需要绘制 10000 个方格,此时 windows 中的帧率远远低于 120 FPS。没有任何性能问题,后续随着功能的增加,会多多注意性能方面的变化,那本文就到这里,谢谢观看 ~

image.png
image.png
image.png
image.png
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Flutter 像素编辑器布局结构
  • 2、数据变化的业务逻辑
  • 3、项目配置的状态数据管理
  • 4、绘制信息的状态数据管理
  • 5、性能方面
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com