# LocationView

> 以文本形式显示 GPS 坐标（纬度、经度、定位时间、速度、方向），并周期性更新。

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

# LocationView

`LocationView` 是一个以文本形式**显示** GPS 数据的组件：纬度和经度（以度/分/秒表示，带 N/S 和 E/W 后缀）、定位时间、速度、方向和卫星数量。它周期性地从一个 `Location`（GPS 源 —— COM 端口/蓝牙/红外，或原生 API）读取数据，并更新在 `VerticalLayout` 中堆叠的五个 `Label`。

它**不绘制地图** —— 只显示数字。若要将地图居中到设备位置，请使用 `Map`（参见第 25 章）。

> 🟡 · **包：** `dev.crossfly.ui` · **继承自：** `Component` · **数据源：** `dev.crossfly.device.Location`

## 何时使用
- 以文本显示设备当前坐标（诊断、HUD、GPS 状态屏）。
- 需要自动周期性读取位置，而无需编写定时器循环。

## 何时不要使用
- 渲染地图或以可视方式标记位置 → 使用 `Map`（第 25 章）。
- 只在代码中读取一次位置，不涉及 UI → 直接使用 `Location` 类。

## 外观
五行文本（纬度、经度、定位、速度、方向），左对齐，位于一个 `VerticalLayout` 中。在没有数据时显示 "Location Initialising"；无信号时显示可本地化的字符串 `LAT_LOW_SIGNAL` / `LON_LOW_SIGNAL`。

## 完整示例（复制、粘贴并运行）
`LocationView` 是一个普通组件：用 `add(LAY_AUTO, ...)` 直接放入屏幕。构造函数声明了 `throws IOException`，已由 `onShow() throws Exception` 覆盖。定时器在 `onAdd` 中启动、在 `onRemove` 中停止 —— 无需手动管理。

```java
package com.exemplo;

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

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

      add(LAY_AUTO, new Label("Coordenadas do GPS:"));

      LocationView gps = new LocationView(1000);   // 每 1 秒读取一次；throws IOException
      gps.onAction(c -> {}); // 每次周期性读取时触发（可选）
      add(LAY_AUTO, gps);
      // 定时器在 onAdd 中启动，在 onRemove 中自动停止。
   }
}
```

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

## 基本用法
```java
LocationView gps = new LocationView(1000);   // 每 1 秒读取一次；throws IOException
container.add(LAY_AUTO, gps);
// 离开界面时，onRemove 已停止定时器；或调用 gps.stop()。
```

## 构造函数
| 构造函数 | 描述 |
|---|---|
| `LocationView()` | 读取间隔 2000 毫秒，`location = null`。`throws IOException`。 |
| `LocationView(int readInterval)` | 自定义间隔（毫秒；有效最小值 100），`location = null`。`throws IOException`。 |
| `LocationView(Location location, int readInterval)` | 显式指定 GPS 源 + 间隔。`throws IOException`。 |

## 属性与自定义
| 方法 / 字段 | 类型 | 作用 |
|---|---|---|
| `location` | `Location`（字段） | GPS 数据源；可在构造函数中传入或保持 `null`。 |
| `stop()` | `void` | 停止定时器并调用 `location.stop()`。`throws IOException`。 |
| `retrieveGPSData()` | `void` | 读取位置并更新标签（由定时器调用）。 |
| `getAutoHeight()` | `int` | 首选高度 = `font.scaledHeight() * 5 + ingap.height()`。 |
| `LocationView.LAT_LOW_SIGNAL` | 静态 `String` | 无法获取纬度时显示的文本（可本地化）。 |
| `LocationView.LON_LOW_SIGNAL` | 静态 `String` | 无法获取经度时显示的文本（可本地化）。 |

## 回调与事件
| 回调 | 触发时机 |
|---|---|
| `onAction(Action)` | 每次周期性读取时（`retrieveGPSData()` 调用 `runActions()`），无论是否有信号。可作为更新通知点使用。 |

## 状态
- **初始化中**：在首次定位之前，显示 "Location Initialising"。
- **有信号**：以度/分/秒显示纬度/经度，显示定位时间（12/24 小时格式来自 `LocaleFormats.is24Hour`），当 `!= Location.INVALID` 时显示速度/方向，当 `> 0` 时显示卫星数。
- **无信号**：在最后一行显示 `LAT_LOW_SIGNAL` / `LON_LOW_SIGNAL` 及失败原因。
- **生命周期**：定时器在 `onAdd` 中启动，在 `onRemove` 中停止（或通过 `stop()`），并释放资源。

### 显式 GPS 源 + 对每次更新做出响应
```java
Location fonte = /* 从平台获取 / dev.crossfly.device */;
LocationView gps = new LocationView(fonte, 1000);
gps.onAction(c -> atualizarStatusBarra());  // 每次读取时触发
container.add(LAY_AUTO, gps);

// 定位低信号消息：
LocationView.LAT_LOW_SIGNAL = "lat: sem sinal";
LocationView.LON_LOW_SIGNAL = "lon: sem sinal";
```

## 最佳实践
- 让生命周期来管理定时器：添加组件即启动它，移除它即停止。仅在需要提前释放 `Location` 时才显式调用 `stop()`。
- 根据需要调整 `readInterval` —— 更短的间隔更耗电；有效最小值为 100 毫秒。

## 常见错误
- 忘记构造函数的 `throws IOException`。
- 期望出现地图：`LocationView` 只显示文本；如需可视化请使用 `Map`。
- 在没有时区的情况下假设本地时间：定位时间通过 `TimeZone.getDefault().getRawOffset()` 按时区偏移进行调整。

## 另请参阅
- 领域指南：[`ui/`](/docs/ui) · 实用配方：[`cookbook/`](/docs/cookbook)
- 概念（i18n、locale 格式）：[`concepts/`](/docs/concepts)
- 相关组件：[`webcontainer`](/docs/ui/widgets/webcontainer)
