# 响应式设计

> 如何让任何布局都能适应屏幕尺寸、像素密度和系统字体大小的变化。

Source: https://crossfly.dev/zh/docs/ui/layouts/responsiveness — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 所有布局中的响应式设计

CrossFly 使用**逻辑像素**，并在旋转/调整尺寸时重新计算布局。如果你遵循下面的原则，**屏幕会自行重新适配**——无需编写 resize 代码。

> 这是实用摘要。带有**每种**布局示例以及端到端屏幕示例的完整指南，是第 36 章——布局与响应式设计最佳实践。

## 5 条原则
1. **绝不使用固定像素定位。** 使用分数、`Relative` 以及 `LAY_FILL`/`LAY_AUTO` / `RelSize.FILL`。
2. **让布局来测量。** `LAY_AUTO`、`RelSize.AUTOSIZE` 和 `Relative.AUTO` 会报告自然尺寸。
3. **间距也要缩放。** 通过 `Gap.ofFont(...)` / `Gap.ofScreen(...)` 设置内边距（`ingap`）和外边距（`outgap`）。
4. **一个"弹性"区域。** 将**一个**组件标记为 `LAY_FILL`（Vertical/Horizontal）以吸收剩余空间。
5. **Resize 是自动的**——只要你使用了上述各项。只有手动定位（`setBounds`）才需要代码。

## 核心工具：`Relative`
| 形式 | 结果 |
|---|---|
| `Relative.ofFont(1.5f)` | 1.5 × 字体高度（随字体/DPI 缩放） |
| `Relative.ofScreen(0.8f)` | 屏幕尺寸的 80% |
| `Relative.ofScreen(0.5f, ScreenSize.MIN)` | **较小**边的 50%（适配竖屏/横屏） |
| `Relative.FULL` / `AUTO` / `CENTER` | 填满父容器 / 内容尺寸 / 居中 |

## 完整示例（复制、粘贴并运行）
```java
package com.exemplo;

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

/** 可执行的主界面。将 launcher 指向此类（classname）并运行：gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   private Component painel;      // 每次 resize/旋转都会重新排列
   private Component lista;
   private Component detalhe;

   @Override
   public void onShow() throws Exception
   {
      super.onShow();

      lista   = new Label("Lista");
      detalhe = new Label("Detalhe");

      painel = new Component();
      setLayout(new VerticalLayout(Position.START, Position.START));
      add(LAY_FILL, painel);
      // onReposition() 在首次布局及每次 resize/旋转时被调用：
      // 它根据方向选择面板的布局方式。
   }

   @Override
   protected void onReposition() throws Exception
   {
      painel.removeAll();
      if (Screen.isLandscape) {
         painel.setLayout(new HorizontalLayout());
         painel.add(0.5f, lista); painel.add(0.5f, detalhe);
      } else {
         painel.setLayout(new VerticalLayout());
         painel.add(LAY_FILL, lista); painel.add(LAY_AUTO, detalhe);
      }
   }
}
```

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

## 当排布应随方向而改变时
覆盖 `Window.onReposition()`（在重新布局之前调用）并重新选择布局：
```java
@Override protected void onReposition() throws Exception {
   painel.removeAll();
   if (Screen.isLandscape) {
      painel.setLayout(new HorizontalLayout());
      painel.add(0.5f, lista); painel.add(0.5f, detalhe);
   } else {
      painel.setLayout(new VerticalLayout());
      painel.add(LAY_FILL, lista); painel.add(LAY_AUTO, detalhe);
   }
}
```
**断点：** 使用 `Screen.minSize`（较小边在不同方向间是稳定的），例如：`tablet = Screen.minSize >= 600`。

## 另请参阅
- [布局目录](/docs/ui/layouts) · 原语：`Relative`/`Gap`
