# 让它响应式

> Relative、Gap、LAY_FILL、把 Screen.minSize 作为断点，以及用 onReposition() 切换布局排列。

Source: https://crossfly.dev/zh/docs/learn/making-it-responsive — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 10. 让它响应式

> **你将学到：** 让应用适配任何屏幕，**不使用一个固定像素**。
> **前置要求：** [持久化数据](/docs/learn/persisting-data)。

## 完整示例（复制、粘贴即可运行）
自适应应用：`onReposition()` 按方向切换**布局排列**（横屏两列，竖屏一列），不重建状态，
使用 `Relative`/`Gap` 和 `Screen`。原样即可编译。
```java
package com.exemplo;

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

public class MainWindow extends Window
{
   private final Component painel = new Component();
   private final Component listaBox = new Component();
   private final Component detalheBox = new Component();

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

      listaBox.setLayout(new VerticalLayout());
      listaBox.add(LAY_AUTO, new Label("Lista"));

      detalheBox.setLayout(new VerticalLayout());
      detalheBox.add(LAY_AUTO, new Label("Detalhe"));

      boolean largo = Screen.minSize >= 600;   // breakpoint：较短边（旋转时稳定）
      add(LAY_AUTO, new Label(largo ? "Tablet/desktop" : "Telefone"));

      add(LAY_FILL, painel);
      onReposition();                           // 初始排列
   }

   @Override
   protected void onReposition() throws Exception
   {
      painel.removeAll();
      if (Screen.isLandscape) {                 // 2 列：列表 | 详情
         painel.setLayout(new HorizontalLayout());
         painel.add(0.4f, listaBox);
         painel.add(0.6f, detalheBox);
      } else {                                  // 1 列
         painel.setLayout(new VerticalLayout());
         painel.add(LAY_FILL, listaBox);
      }
      painel.setValidLayout(false);
   }
}
```
> 下面的代码片段只展示**核心部分**（放入 `onShow()` 内部的内容）。要运行它们，请放进上面的 `MainWindow` 骨架中。

## 这些工具
```java
Relative.ofFont(1.5f);                     // 随字体/DPI 缩放
Relative.ofScreen(0.8f, ScreenSize.MIN);   // 较短边的比例（适配 portrait/landscape）
Gap.ofFont(0.5f);                          // 可缩放的间距
add(LAY_FILL, comp);                       // 每个轴一个弹性区域
```

## 用 `Screen.minSize` 设置断点
使用**较短的一边** —— 设备旋转时它保持稳定：
```java
boolean largo = Screen.minSize >= 600;   // 平板/桌面
```

## 按方向切换布局排列 —— `onReposition()`
当**结构**本身需要改变（竖屏一列，横屏两列）时，重写 `onReposition()`
（在 resize 时被调用）—— **不重建状态**：
```java
@Override protected void onReposition() throws Exception {
   painel.removeAll();
   if (Screen.isLandscape) {                    // 2 列：列表 | 详情
      painel.setLayout(new HorizontalLayout());
      painel.add(0.4f, listaBox);
      painel.add(0.6f, detalheBox);
   } else {                                      // 1 列
      painel.setLayout(new VerticalLayout());
      painel.add(LAY_FILL, listaBox);
   }
}
```

## 本步骤构建的内容
应用变得**自适应** —— 竖屏用手机布局，横屏用平板/桌面布局 —— 且不使用固定像素。

## 回顾
`Relative`/`Gap`/`LAY_FILL` = 自动响应式；`Screen.minSize` = 断点；`onReposition()`
在保留状态的同时切换**布局排列**。

## 下一步
→ [测试你的应用](/docs/learn/testing-your-app)

## 另请参阅
- [响应式（最佳实践）](/docs/best-practices/responsividade) · 概念：[布局与 Relative 模型](/docs/concepts/the-layout-and-relative-model)
