UWP MapControl使用LocalMapTileDataSource时如何动态设置瓦片自定义透明度
解决方案
方法1:基于像素缓冲区修改的自定义透明度控制
这个方法支持灵活控制每一张瓦片的透明度,逻辑如下:
- 保留现有瓦片坐标转QuadKey的逻辑,不要直接赋值
Uri,改为先加载本地瓦片图片,对像素的Alpha通道做全局乘法后赋值给e.Request.PixelBuffer - 可以额外定义一个全局变量比如
_tileOpacity,范围0~1,动态修改这个值之后,新加载的瓦片都会自动应用新的透明度,已经加载的瓦片可以调用tileSource.Invalidate()刷新即可全局生效
修改后的示例代码如下:
// 全局透明度变量,可动态修改,范围0-1 private double _tileOpacity = 0.6; private void AddLocalMapTileDataSource() { MapZoomLevelRange range; range.Min = 8; range.Max = 16; var dataSource = new LocalMapTileDataSource(); dataSource.UriRequested += async (s, e) => { var deferral = e.Request.GetDeferral(); try { var qk = TileSystem.TileXYToQuadKey(e.X, e.Y, e.ZoomLevel); // 加载本地瓦片文件 var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Tiles/{qk}.png")); using (var stream = await file.OpenAsync(FileAccessMode.Read)) { // 解码图片 var decoder = await BitmapDecoder.CreateAsync(stream); var pixelData = await decoder.GetPixelDataAsync(); var pixels = pixelData.DetachPixelData(); // 遍历像素修改Alpha通道,RGBA格式下每4个字节第一个是B,第二个G,第三个R,第四个A for (int i = 3; i < pixels.Length; i += 4) { pixels[i] = (byte)(pixels[i] * _tileOpacity); } // 编码回像素缓冲区赋值给请求 using (var ms = new InMemoryRandomAccessStream()) { var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, ms); encoder.SetPixelData( BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, decoder.OrientedPixelWidth, decoder.OrientedPixelHeight, decoder.DpiX, decoder.DpiY, pixels ); await encoder.FlushAsync(); ms.Seek(0); var reader = new DataReader(ms.GetInputStreamAt(0)); var bytes = new byte[ms.Size]; await reader.LoadAsync((uint)ms.Size); reader.ReadBytes(bytes); e.Request.PixelBuffer = bytes.AsBuffer(); } } } catch { // 瓦片不存在时可以留空或者设置占位图 e.Request.Uri = null; } finally { deferral.Complete(); } }; var tileSource = new MapTileSource(dataSource) { ZoomLevelRange = range }; myMap.TileSources.Add(tileSource); tileSource.Layer = MapTileLayer.AreaOverlay; tileSource.IsTransparencyEnabled = true; tileSource.TilePixelSize = 256; } // 动态调整透明度的调用示例 private void UpdateTileOpacity(double newOpacity) { _tileOpacity = Math.Clamp(newOpacity, 0, 1); // 刷新所有已加载瓦片应用新透明度 foreach (var source in myMap.TileSources) { source.Invalidate(); } }
方法2:基于Composition API的全局瓦片层透明度控制
如果你只需要统一调整整个瓦片层的透明度,不需要单独控制单张瓦片,这个方法性能更好,修改完全实时,不需要刷新瓦片:
private void SetTileLayerOpacity(double opacity) { // 获取MapControl的可视化层 var visual = ElementCompositionPreview.GetElementVisual(myMap); var compositor = visual.Compositor; // 找到瓦片层的子视觉对象,AreaOverlay层对应的就是你添加的自定义瓦片 foreach (var child in visual.Children) { if (child.Comment?.Contains("MapTileLayer_AreaOverlay") == true) { child.Opacity = (float)opacity; break; } } }
注意:这个方法依赖Windows 10 1809及以上版本的SDK,适配系统版本低于该版本时建议使用方法1
内容的提问来源于stack exchange,提问作者NoWar
相关产品推荐
相关产品推荐

