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

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

RelativeLayout

通过锚点为每个子组件定位——相对于容器或相对于另一个组件。它独有的强项是将 A 锚定到 B(头像角上的徽标、图标右侧的标签)。

🔴 · 包: dev.crossfly.ui.layout · 继承自: Layout

何时使用

  • 将一个组件锚定到另一个组件(AFTER、BEFORE、END_OF、CENTER_OF)。
  • 精细的叠加与组合(徽标、印章、定位的标签)。

何时不要使用

  • “顶部/内容/底部填满剩余空间”的骨架 → 优先使用配合 LAY_FILL 的 VerticalLayout(更简单;参见下方关于 FILL/FIT 的说明)。

add(...) — 签名与语义

public RelativeLayout add(Component alvo, RelPos x, RelPos y, RelSize larg, RelSize alt);
// + 重载:  (..., Component ref)   (..., Gap outgap)   (..., Component ref, Gap outgap)

没有 ref 时,锚点相对于上一个添加的组件。

RelPos(位置,位于 UIConstants):START、CENTER、END、AFTER、BEFORE、CENTER_OF、 END_OF、SAMEPOS、AUTOPOS、AUTOPOSCENTERED、KEEPPOS。

RelSize(尺寸):AUTOSIZE、FILL、FIT、SAMESIZE、KEEPSIZE。

完整示例(复制、粘贴并运行)

package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*;

/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();

      // 头像 + 头像角上的徽标 + 旁边的名字
      RelativeLayout rl = new RelativeLayout();
      Label avatar = new Label("👤");
      avatar.getStyle().autoWidth(Relative.ofFont(3f)).autoHeight(Relative.ofFont(3f));
      Label badge = new Label("9");
      Label nome  = new Label("Ana Silva");

      rl.add(avatar, RelPos.START,  RelPos.START,     RelSize.AUTOSIZE, RelSize.AUTOSIZE);
      rl.add(badge,  RelPos.END_OF, RelPos.START,     RelSize.AUTOSIZE, RelSize.AUTOSIZE, avatar); // 头像的角
      rl.add(nome,   RelPos.AFTER,  RelPos.CENTER_OF, RelSize.AUTOSIZE, RelSize.AUTOSIZE, avatar); // 头像之后

      Component cabecalho = new Component();
      cabecalho.setLayout(rl);

      setLayout(new VerticalLayout(Position.START, Position.START));
      add(LAY_AUTO, cabecalho);
      add(LAY_FILL, new Component());
   }
}

下面的片段只展示核心部分(放进 onShow() 里的内容)。要运行它们,请将其放入上面的 MainWindow 骨架中。

基本用法

// 头像 + 头像角上的徽标 + 旁边的名字
RelativeLayout rl = new RelativeLayout();
ImageView avatar = new ImageView(/* 照片 */);
avatar.getStyle().autoWidth(Relative.ofFont(3f)).autoHeight(Relative.ofFont(3f));
Label badge = new Label("9");
Label nome  = new Label("Ana Silva");

rl.add(avatar, RelPos.START,  RelPos.START,     RelSize.AUTOSIZE, RelSize.AUTOSIZE);
rl.add(badge,  RelPos.END_OF, RelPos.START,     RelSize.AUTOSIZE, RelSize.AUTOSIZE, avatar); // 头像的角
rl.add(nome,   RelPos.AFTER,  RelPos.CENTER_OF, RelSize.AUTOSIZE, RelSize.AUTOSIZE, avatar); // 头像之后

Component cabecalho = new Component();
cabecalho.setLayout(rl);

有用的锚定模式

  • B 在 A 右侧并对齐: add(b, RelPos.AFTER, RelPos.CENTER_OF, RelSize.AUTOSIZE, RelSize.AUTOSIZE, a)。
  • 与 A 相同尺寸: RelSize.SAMESIZE。
  • 居中卡片: add(card, RelPos.CENTER, RelPos.CENTER, RelSize.AUTOSIZE, RelSize.AUTOSIZE)。
  • 按规则设定边距: 将 Gap.ofFont(0.5f) 作为最后一个参数传入(它会成为该规则的 outgap)。

⚠️ RelSize 的确切语义(不要混淆)

  • FILL = 父容器的全部宽度/高度减去边距——忽略参照物(不是“A 旁边剩下的空间”)。
  • FIT = 从父容器的角到参照物的边(例如:填充到 A 的左侧/顶部)。
  • 要实现“某个子组件吸收其他组件旁边的剩余空间” → 使用配合 LAY_FILL 的 HorizontalLayout/VerticalLayout,而不是 RelativeLayout。

常见错误

  • 期望 FILL 是“A 旁边剩下的空间”(它其实是整个父容器)。
  • 引用的循环(A 依赖 B,而 B 又依赖 A)——务必锚定到之前已经添加的组件。

另请参阅

这个页面有帮助吗?