第08章 - 小部件系统
第08章:小部件(Widget)系统
8.1 小部件概述
8.1.1 什么是小部件
小部件(Widget)是叠加在地图上的 UI 元素,用于提供导航控制、信息显示等功能。它们独立于地图内容,始终显示在最上层。
┌─────────────────────────────────────────────────────────────────┐
│ 地图视图 │
│ ┌───┐ ┌───────┐ │
│ │ + │ 缩放按钮 │ 比例尺 │ │
│ │ - │ └───────┘ │
│ └───┘ │
│ │
│ 地图内容 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 日志信息区域 │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
8.1.2 IWidget 接口
public interface IWidget
{
// 标识
string Name { get; }
// 位置和布局
HorizontalAlignment HorizontalAlignment { get; set; }
VerticalAlignment VerticalAlignment { get; set; }
float MarginX { get; set; }
float MarginY { get; set; }
// 状态
bool Enabled { get; set; }
// 交互
bool OnPointerPressed(Navigator navigator, WidgetEventArgs e);
bool OnPointerMoved(Navigator navigator, WidgetEventArgs e);
bool OnPointerReleased(Navigator navigator, WidgetEventArgs e);
bool OnTapped(Navigator navigator, WidgetEventArgs e);
}
8.1.3 内置小部件类型
| 小部件 | 功能 |
|---|---|
| ZoomInOutWidget | 缩放控制按钮 |
| ScaleBarWidget | 比例尺显示 |
| LoggingWidget | 日志显示 |
| PerformanceWidget | 性能信息显示 |
| MouseCoordinatesWidget | 鼠标坐标显示 |
| HyperlinkWidget | 超链接 |
| ButtonWidget | 可点击按钮 |
| TextBoxWidget | 文本框 |
8.2 ZoomInOutWidget - 缩放控制
8.2.1 基本使用
var zoomWidget = new ZoomInOutWidget
{
// 位置
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
MarginX = 20,
MarginY = 20,
// 布局
Orientation = Orientation.Vertical, // 垂直排列
// 样式
BackColor = Color.White,
Opacity = 0.9f
};
map.Widgets.Add(zoomWidget);
8.2.2 自定义缩放按钮
var customZoomWidget = new ZoomInOutWidget
{
// 使用自定义图标
PlusText = "+",
MinusText = "-",
// 大小
Size = 40,
// 边距
MarginX = 15,
MarginY = 100,
// 样式
BackColor = new Color(50, 50, 50),
TextColor = Color.White
};
8.3 ScaleBarWidget - 比例尺
8.3.1 基本使用
var scaleBarWidget = new ScaleBarWidget(map)
{
// 位置
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Bottom,
MarginX = 20,
MarginY = 20,
// 文本对齐
TextAlignment = Alignment.Center,
// 颜色
TextColor = Color.Black,
Halo = Color.White,
// 最大宽度
MaxWidth = 150
};
map.Widgets.Add(scaleBarWidget);
8.3.2 配置比例尺样式
var styledScaleBar = new ScaleBarWidget(map)
{
// 单位制
UnitConverter = MetricUnitConverter.Instance, // 公制单位
// 或
// UnitConverter = ImperialUnitConverter.Instance, // 英制单位
// 样式
ScaleBarMode = ScaleBarMode.Single, // 单条或双条
TickLength = 5,
// 颜色
TextColor = Color.Black,
Halo = Color.White,
StrokeWidth = 2,
StrokeWidthHalo = 4
};
8.4 LoggingWidget - 日志显示
8.4.1 配置日志小部件
// LoggingWidget 默认已添加到 Map
// 可以配置其显示行为
// 控制是否显示日志(全局设置)
LoggingWidget.ShowLoggingInMap = ActiveMode.Yes; // 始终显示
LoggingWidget.ShowLoggingInMap = ActiveMode.No; // 从不显示
LoggingWidget.ShowLoggingInMap = ActiveMode.OnlyInDebugMode; // 仅调试时显示(默认)
8.4.2 自定义日志处理
// 订阅 Mapsui 日志事件
Mapsui.Logging.Logger.LogDelegate += (level, message, ex) =>
{
var logMessage = $"[{level}] {message}";
if (ex != null)
{
logMessage += $" - {ex.Message}";
}
// 输出到控制台
Console.WriteLine(logMessage);
// 或转发到您的日志框架
// _logger.Log(ConvertLevel(level), ex, message);
};
8.5 PerformanceWidget - 性能信息
8.5.1 显示性能信息
var performanceWidget = new PerformanceWidget
{
// 位置
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
MarginX = 10,
MarginY = 10,
// 样式
BackColor = new Color(0, 0, 0, 180),
TextColor = Color.White
};
map.Widgets.Add(performanceWidget);
8.5.2 性能监控
// PerformanceWidget 显示的信息包括:
// - FPS(每秒帧数)
// - 渲染时间
// - 要素数量
// - 瓦片数量
// 点击性能小部件可以重置统计数据
8.6 MouseCoordinatesWidget - 坐标显示
8.6.1 显示鼠标坐标
var coordinatesWidget = new MouseCoordinatesWidget(map)
{
// 位置
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Bottom,
MarginX = 10,
MarginY = 10,
// 样式
BackColor = Color.White,
TextColor = Color.Black
};
map.Widgets.Add(coordinatesWidget);
8.6.2 自定义坐标格式
// 创建自定义坐标格式化器
var formattedCoordinatesWidget = new MouseCoordinatesWidget(map)
{
// 使用自定义格式化
CoordinateFormatter = (x, y) =>
{
// 转换为经纬度
var lonLat = SphericalMercator.ToLonLat(x, y);
return $"经度: {lonLat.X:F6}° 纬度: {lonLat.Y:F6}°";
}
};
8.7 ButtonWidget - 按钮小部件
8.7.1 创建自定义按钮
var buttonWidget = new ButtonWidget
{
// 文本
Text = "定位",
// 位置
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
MarginX = 20,
MarginY = 80,
// 大小
Width = 60,
Height = 30,
// 样式
BackColor = Color.White,
TextColor = Color.Black
};
// 点击事件
buttonWidget.Tapped += (sender, args) =>
{
// 处理点击
map.Navigator.CenterOn(116.4, 39.9);
args.Handled = true;
};
map.Widgets.Add(buttonWidget);
8.7.2 带图标的按钮
var iconButtonWidget = new ButtonWidget
{
// 使用图像
ImageSource = "embedded://MyApp.Resources.locate.png",
// 位置和大小
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
MarginX = 20,
MarginY = 80,
Width = 40,
Height = 40,
// 圆角
CornerRadius = 20,
// 样式
BackColor = Color.White
};
iconButtonWidget.Tapped += (sender, args) =>
{
// 定位到当前位置
LocateCurrentPosition();
args.Handled = true;
};
8.8 HyperlinkWidget - 超链接
8.8.1 添加超链接
var hyperlinkWidget = new HyperlinkWidget
{
// 文本和链接
Text = "© OpenStreetMap",
Url = "https://www.openstreetmap.org/copyright",
// 位置
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Bottom,
MarginX = 10,
MarginY = 10,
// 样式
TextColor = Color.Blue,
BackColor = new Color(255, 255, 255, 200)
};
map.Widgets.Add(hyperlinkWidget);
8.9 TextBoxWidget - 文本框
8.9.1 显示信息文本
var textBoxWidget = new TextBoxWidget
{
// 位置
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top,
MarginY = 10,
// 文本
Text = "欢迎使用 Mapsui 地图",
// 样式
BackColor = new Color(0, 0, 0, 180),
TextColor = Color.White,
CornerRadius = 5,
Padding = 10
};
map.Widgets.Add(textBoxWidget);
8.9.2 动态更新文本
public class InfoDisplayManager
{
private readonly TextBoxWidget _infoWidget;
public InfoDisplayManager(Map map)
{
_infoWidget = new TextBoxWidget
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Bottom,
MarginY = 50,
BackColor = new Color(0, 0, 0, 200),
TextColor = Color.White,
Enabled = false // 初始隐藏
};
map.Widgets.Add(_infoWidget);
}
public void ShowInfo(string message, int durationMs = 3000)
{
_infoWidget.Text = message;
_infoWidget.Enabled = true;
// 自动隐藏
Task.Delay(durationMs).ContinueWith(_ =>
{
_infoWidget.Enabled = false;
});
}
}
8.10 自定义小部件
8.10.1 继承 BaseWidget
public class CompassWidget : BaseWidget
{
private readonly Map _map;
private double _rotation;
public override string Name => "Compass";
public float Size { get; set; } = 50;
public CompassWidget(Map map)
{
_map = map;
HorizontalAlignment = HorizontalAlignment.Right;
VerticalAlignment = VerticalAlignment.Top;
MarginX = 20;
MarginY = 150;
}
public void UpdateRotation(double rotation)
{
_rotation = rotation;
}
public override bool OnTapped(Navigator navigator, WidgetEventArgs e)
{
// 点击时重置旋转
navigator.RotateTo(0);
return true;
}
}
// 需要同时创建渲染器
public class CompassWidgetRenderer : IWidgetRenderer
{
public void Draw(SKCanvas canvas, IWidget widget, float scale)
{
if (widget is CompassWidget compass)
{
var size = compass.Size * scale;
var center = new SKPoint(size / 2, size / 2);
// 绘制指南针背景
using var bgPaint = new SKPaint
{
Color = SKColors.White,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawCircle(center, size / 2, bgPaint);
// 绘制指针
using var arrowPaint = new SKPaint
{
Color = SKColors.Red,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
// 绘制北向指针
var path = new SKPath();
path.MoveTo(center.X, center.Y - size / 3);
path.LineTo(center.X - size / 8, center.Y);
path.LineTo(center.X + size / 8, center.Y);
path.Close();
canvas.Save();
canvas.RotateDegrees((float)compass._rotation, center.X, center.Y);
canvas.DrawPath(path, arrowPaint);
canvas.Restore();
}
}
}
8.10.2 注册自定义渲染器
// 在应用启动时注册
WidgetRenderer.DefaultWidgetRenderers[typeof(CompassWidget)] = new CompassWidgetRenderer();
8.11 小部件布局管理
8.11.1 布局系统
// 小部件使用对齐和边距进行定位
// HorizontalAlignment: Left, Center, Right
// VerticalAlignment: Top, Center, Bottom
// MarginX, MarginY: 距离边缘的距离
// 左上角
widget.HorizontalAlignment = HorizontalAlignment.Left;
widget.VerticalAlignment = VerticalAlignment.Top;
widget.MarginX = 10;
widget.MarginY = 10;
// 右下角
widget.HorizontalAlignment = HorizontalAlignment.Right;
widget.VerticalAlignment = VerticalAlignment.Bottom;
widget.MarginX = 10;
widget.MarginY = 10;
// 中央底部
widget.HorizontalAlignment = HorizontalAlignment.Center;
widget.VerticalAlignment = VerticalAlignment.Bottom;
widget.MarginY = 20;
8.11.2 小部件组管理
public class WidgetManager
{
private readonly Map _map;
public WidgetManager(Map map)
{
_map = map;
}
public void SetupDefaultWidgets()
{
// 缩放控制 - 右上角
_map.Widgets.Add(new ZoomInOutWidget
{
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
MarginX = 20,
MarginY = 20
});
// 比例尺 - 左下角
_map.Widgets.Add(new ScaleBarWidget(_map)
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Bottom,
MarginX = 20,
MarginY = 20
});
// 版权信息 - 右下角
_map.Widgets.Add(new HyperlinkWidget
{
Text = "© OpenStreetMap",
Url = "https://www.openstreetmap.org/copyright",
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Bottom,
MarginX = 10,
MarginY = 10
});
}
public void HideAllWidgets()
{
foreach (var widget in _map.Widgets)
{
widget.Enabled = false;
}
}
public void ShowAllWidgets()
{
foreach (var widget in _map.Widgets)
{
widget.Enabled = true;
}
}
}
8.12 本章小结
本章详细介绍了 Mapsui 的小部件系统:
- 小部件概述:IWidget 接口和内置小部件类型
- ZoomInOutWidget:缩放控制按钮
- ScaleBarWidget:比例尺显示
- LoggingWidget:日志信息显示
- PerformanceWidget:性能监控
- MouseCoordinatesWidget:鼠标坐标显示
- ButtonWidget:自定义按钮
- HyperlinkWidget:超链接
- TextBoxWidget:文本显示
- 自定义小部件:实现自定义小部件和渲染器
- 布局管理:小部件定位和组织
在下一章中,我们将学习事件处理与用户交互。
8.13 思考与练习
- 创建一个图层切换小部件,允许用户切换底图。
- 实现一个显示当前缩放级别的小部件。
- 创建一个指南针小部件,随地图旋转而旋转。
- 实现一个简单的图例小部件。
- 设计一个工具栏小部件,包含多个功能按钮。

浙公网安备 33010602011771号