Package com.ultikits.ultitools.abstracts.gui.declarative


@Experimental package com.ultikits.ultitools.abstracts.gui.declarative
声明式 Inventory GUI 框架。

本框架基于 Flutter 的设计理念,提供声明式的 UI 构建方式。 核心理念:UI = f(state)

⚠ 当前状态(6.2.5)

本包及其子包标记为 @ApiStatus.Experimental,API 可能在任何版本发生不兼容变动。

状态驱动的重绘尚未实现。UI = f(state) 是本框架的设计目标,但渲染引擎的三个接缝 目前都还没接上:build(BuildContext) 只在 onOpen 中被调用一次; Element.update() 不置脏标记;State.setState 的信号沿 Element 树上溯到根节点后 静默终止,进不了调度器。因此下面「主要特性」中的 setState 触发局部重建 目前不生效, 依赖 setState 的导航子系统(Navigator.push / pop)同样惰性。 现阶段可靠可用的是静态页面:build 一次、渲染一次。

State-driven repaint is not implemented yet. UI = f(state) is the design goal, but all three rendering seams are still open: build(BuildContext) is called exactly once from onOpen; Element.update() never marks anything dirty; and the State.setState signal walks up the element tree and stops silently at the root without reaching the scheduler. The setState triggers a partial rebuild bullet below therefore does not hold today, and the navigation subsystem is inert for the same reason. What works today is the static page: build once, render once.

修复排期见 issue #200(6.3.0)。

主要特性:

  • Widget 树描述 UI 结构
  • Element 树管理 Widget 实例和生命周期
  • RenderNode 树进行高效的 diff 更新
  • 支持 StatelessWidget 和 StatefulWidget
  • setState 触发局部重建
  • 所有更新自动在主线程执行
  • 兼容 obliviate-invs 的 Gui 生命周期

快速开始:


 // 1. 创建你的 GUI 页面
 public class ShopPage extends DeclarativeGui {
     private final List<ItemStack> items;
     
     public ShopPage(Player player, List<ItemStack> items) {
         super(player, "shop", "Item Shop", 6);
         this.items = items;
     }
     
     @Override
     public Widget build(BuildContext context) {
         return Container.builder()
             .background(IconWrapper.builder(glassPane).name(" ").build())
             .children(
                 // 标题
                 TextButton.builder()
                     .text("§6§lItem Shop")
                     .slot(4)
                     .build(),
                 
                 // 物品网格
                 GridView.<ItemStack>builder()
                     .startSlot(10)
                     .columns(7)
                     .rows(4)
                     .items(items, item -> ItemDisplay.builder(item)
                         .onClick(() -> buyItem(item))
                         .build())
                     .build(),
                 
                 // 关闭按钮
                 TextButton.builder()
                     .text("§cClose")
                     .color("RED")
                     .slot(49)
                     .onClick(player::closeInventory)
                     .build()
             )
             .build();
     }
     
     private void buyItem(ItemStack item) {
         // 处理购买逻辑
     }
 }
 
 // 2. 打开 GUI
 new ShopPage(player, items).open();
 

StatefulWidget 示例:


 public class CounterPage extends DeclarativeGui {
     private int count = 0;
     
     public CounterPage(Player player) {
         super(player, "counter", "Counter", 3);
     }
     
     @Override
     public Widget build(BuildContext context) {
         return Container.builder()
             .child(TextButton.builder()
                 .text("Count: " + count)
                 .slot(13)
                 .onClick(() -> {
                     // 修改状态并触发重建
                     count++;
                     markNeedsBuild();
                 })
                 .build())
             .build();
     }
 }
 

包结构:

Since:
6.2.0
Version:
1.0.0
Author:
qianmo
See Also: