跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用

本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。

一切都是 Component

这是让框架其余部分“豁然开朗”的核心理念。在 CrossFly 中,不存在“widget”与“container” 两套层级。只有一个基类型 —— Component —— 而任何 Component 一旦获得一个 Layout, 就在那一刻变成了容器。

container = Component + Layout

Component painel = new Component();       // 一个「空」的 Component
painel.setLayout(new VerticalLayout());   // 现在它组织子项 → 是一个容器
painel.add(LAY_AUTO, new Label("Título"));
painel.add(LAY_FILL, new ListView<>(...));

Button 是一个 Component。Label 是一个 Component。Window(屏幕)是一个全屏的 Component。不存在特殊的 Container 类 —— “容纳能力”就只是拥有一个 Layout。 这意味着你始终用同样的方式组合界面,从一个按钮到整个应用皆是如此。

为什么基类要这样设计

Component 必须能扩展到成千上万个实例而不撑爆内存。两个关键决策:

  • 用位域(cbits)代替几十个 boolean。 诸如 enabled、visible、focused、 pressed、是否有布局、是否有聚焦样式…… 这些状态是同一个 long 整数中的若干位,而非独立字段。 成千上万个组件 × 几十个布尔标志将造成巨大浪费;一个位域用单个字段就解决了问题。
  • _惰性_属性映射(property(k, v))。 可选的东西(回调、自定义皮肤、背景 图、备用样式)不是固定字段 —— 它们存在于一个按需创建的映射中。一个简单的 Label 不必为一个永远不会用到的“背景图”字段付出代价。
// property(...) 是表示可选值的惯用「数据袋」:
comp.property("meuFlag", true);
boolean f = comp.property("meuFlag");   // 取回(从未设置则为 null)

样式遵循同样的理念:它们是按需从 Skin 创建的,而非在一开始就为每个组件 实例化。

单一父级层级

每个 Component 最多有一个父级。组合树是严格分层的:将 一个组件添加到某个容器会把它从任何先前的父级中移除。这让布局和事件 传播保持可预测(每个组件恰好属于一个位置)。

由此推导出的结论

  • 组合一切的方式只有一种: 学会搭建一个面板 = 学会搭建一个屏幕。
  • 布局是可插拔的: 同一个容器只需更换 Layout 就能改变排布方式(这是 响应式的基础 —— 参见 Layout 与 Relative 模型)。
  • 每个组件成本低: 位域 + 惰性属性正是让大型列表可行的原因。

参见

这个页面有帮助吗?