Xamarin Forms 地图 - 如何刷新/更新地图 - CustomMap 渲染器

2024-05-22

如果您正在寻找完整的折线、图钉、图块、UIOptions(以及很快的 3D 效果)渲染/实现,您应该在我在 GitHub 上创建的公共 github 上进行搜索XamarinByEmixam23/..../地图 https://github.com/Emixam23/XamarinByEmixam23/tree/master/Detailed%20Part/Controls/Map.


我搜索了很多,但仍然遇到同样的问题:

如何更新、刷新或重新加载 Xamarin.Forms.Maps?

在类定义(类 CustomMap : Map)中,没有更新地图的方法。也许 MVVM 逻辑可以解决这个问题,但我在网上找不到它。

我按照这个地图教程进行操作:使用地图 https://developer.xamarin.com/guides/xamarin-forms/working-with/maps/

为了自定义它,我遵循了本教程:在地图上突出显示路线 https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/maps/map-overlay/polyline/

所以,在这些教程之后(我做了同样的事情,没有改变),我尝试使用 2 个路线坐标,这给了我一条直线......然后我制作了一个完美运行的算法。

方向图

public class DirectionMap
{
    public Distance distance { get; set; }
    public Duration duration { get; set; }
    public Address address_start { get; set; }
    public Address address_end { get; set; }
    public List<Step> steps { get; set; }

    public class Distance
    {
        public string text { get; set; }
        public int value { get; set; }
    }
    public class Duration
    {
        public string text { get; set; }
        public int value { get; set; }
    }
    public class Address
    {
        public string text { get; set; }
        public Position position { get; set; }
    }
    public class Step
    {
        public Position start { get; set; }
        public Position end { get; set; }
    }
}

响应Http解析器

public static void parseDirectionGoogleMapsResponse(HttpStatusCode httpStatusCode, JObject json, Action<DirectionMap, string> callback)
{
    switch (httpStatusCode)
    {
        case HttpStatusCode.OK:

            DirectionMap directionMap = null;
            string strException = null;

            try
            {
                directionMap = new DirectionMap()
                {
                    distance = new DirectionMap.Distance()
                    {
                        text = (json["routes"][0]["legs"][0]["distance"]["text"]).ToString(),
                        value = Int32.Parse((json["routes"][0]["legs"][0]["distance"]["value"]).ToString())
                    },
                    duration = new DirectionMap.Duration()
                    {
                        text = (json["routes"][0]["legs"][0]["duration"]["text"]).ToString(),
                        value = Int32.Parse((json["routes"][0]["legs"][0]["duration"]["value"]).ToString())
                    },
                    address_start = new DirectionMap.Address()
                    {
                        text = (json["routes"][0]["legs"][0]["start_address"]).ToString(),
                        position = new Position(Double.Parse((json["routes"][0]["legs"][0]["start_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["start_location"]["lng"]).ToString()))
                    },
                    address_end = new DirectionMap.Address()
                    {
                        text = (json["routes"][0]["legs"][0]["end_address"]).ToString(),
                        position = new Position(Double.Parse((json["routes"][0]["legs"][0]["end_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["end_location"]["lng"]).ToString()))
                    }
                };

                bool finished = false;
                directionMap.steps = new List<Step>();
                int index = 0;

                while (!finished)
                {
                    try
                    {
                        Step step = new Step()
                        {
                            start = new Position(Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["start_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["start_location"]["lng"]).ToString())),
                            end = new Position(Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["end_location"]["lat"]).ToString()), Double.Parse((json["routes"][0]["legs"][0]["steps"][index]["end_location"]["lng"]).ToString()))
                        };
                        directionMap.steps.Add(step);
                        index++;
                    }
                    catch (Exception e)
                    {
                        finished = true;
                    }
                }
            }
            catch (Exception e)
            {
                directionMap = null;
                strException = e.ToString();
            }
            finally
            {
                callback(directionMap, strException);
            }
            break;
        default:
            switch (httpStatusCode)
            {

            }
            callback(null, json.ToString());
            break;
    }
}

我只是获取一些私人计算的距离和持续时间,并获取放入 List 中的每一步;

一切完成后,我使用回调将我们带回控制器(MapPage.xaml.cs XAML 表单页面(Xamarin Portable))

现在,一切都变得奇怪了。就像地图没有意识到所做的更改一样

public partial class MapPage : ContentPage
{
    public MapPage()
    {
        InitializeComponent();
        setupMap();
        setupMapCustom();
    }

    public void setupMapCustom()
    {
        customMap.RouteCoordinates.Add(new Position(37.785559, -122.396728));
        customMap.RouteCoordinates.Add(new Position(37.780624, -122.390541));
        customMap.RouteCoordinates.Add(new Position(37.777113, -122.394983));
        customMap.RouteCoordinates.Add(new Position(37.776831, -122.394627));

        customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Xamarin.Forms.Maps.Distance.FromMiles(1.0)));
    }       

    public async void setupMap()
    {
        customMap.MapType = MapType.Satellite;

        string origin = "72100 Le Mans";
        string destination = "75000 Paris";

        HttpRequest.getDirections(origin, destination, callbackDirections);

        customMap.RouteCoordinates.Add(await MapUtilities.GetMapPointOfStreetAddress(origin));
        Position position = await MapUtilities.GetMapPointOfStreetAddress(destination);
        //customMap.RouteCoordinates.Add(position);

        var pin = new Pin
        {
            Type = PinType.Place,
            Position = position,
            Label = "Destination !!",
        };
        customMap.Pins.Add(pin);
    }

    private async void callbackDirections(Object obj, string str)
    {
        if (obj != null)
        {
            DirectionMap directionMap = obj as DirectionMap;

            foreach (Step step in directionMap.steps)
            {
                customMap.RouteCoordinates.Add(step.start);
                System.Diagnostics.Debug.WriteLine("add step");
            }

            customMap.RouteCoordinates.Add(directionMap.address_end.position);
            System.Diagnostics.Debug.WriteLine("add last step");
        }
        else
        {
            System.Diagnostics.Debug.WriteLine(str);
        }
    }
}

我运行我的应用程序,一切正常,直到速度很快,因为我的算法等花费了时间,回调来得太晚了,然后我需要刷新、重新加载或更新我的地图...无论如何,我需要更新我的地图未来的地图,所以...如果有人可以提供帮助,欢迎这个!

EDIT 1我看了你的答案(非常感谢!;))但它不起作用:/

我更新了自定义地图正如你所做的那样

public class CustomMap : Map
{
    public static readonly BindableProperty RouteCoordinatesProperty =
    BindableProperty.Create<CustomMap, List<Position>>(p => p.RouteCoordinates, new List<Position>());

    public List<Position> RouteCoordinates
    {
        get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
        set { SetValue(RouteCoordinatesProperty, value); }
    }

    public CustomMap()
    {
        RouteCoordinates = new List<Position>();
    }
}

同样适用于自定义地图渲染器 (Droid)

public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
{
    GoogleMap map;
    Polyline polyline;

    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            // Unsubscribe
        }

        if (e.NewElement != null)
        {
            ((MapView)Control).GetMapAsync(this);
        }
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        if (this.Element == null || this.Control == null)
            return;

        if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
        {
            UpdatePolyLine();
        }
    }

    private void UpdatePolyLine()
    {
        if (polyline != null)
        {
            polyline.Remove();
            polyline.Dispose();
        }

        var polylineOptions = new PolylineOptions();
        polylineOptions.InvokeColor(0x66FF0000);

        foreach (var position in ((CustomMap)this.Element).RouteCoordinates)
        {
            polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
        }

        polyline = map.AddPolyline(polylineOptions);
    }

    public void OnMapReady(GoogleMap googleMap)
    {
        map = googleMap;
        UpdatePolyLine();
    }
}

因此,对于最后的更改,在我的 MapPage.xaml.cs 中,我按照您的解释对回调方向进行了更改(我希望我做得很好)

private async void callbackDirections(Object obj, string str)
    {
        if (obj != null)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                DirectionMap directionMap = obj as DirectionMap;
                var list = new List<Position>(customMap.RouteCoordinates);

                foreach (Step step in directionMap.steps)
                {
                    list.Add(directionMap.address_end.position);
                    System.Diagnostics.Debug.WriteLine("add step");
                }

                System.Diagnostics.Debug.WriteLine("last step");
                customMap.RouteCoordinates = list;
                System.Diagnostics.Debug.WriteLine("finished?");
            });
        }
        else
        {
            System.Diagnostics.Debug.WriteLine(str);
        }
    }

地图仍然不显示折线:/我只做了这些更改,我没有更改以前的代码中的任何其他内容。

我没有告诉你,但我不是 MVVM 绑定方面的专家,所以如果我忘记了什么,我很抱歉:/

EDIT 2因此,在您回答并阅读、阅读和重新阅读您的答案之后,MapPage.xaml.cs 中有我的“测试代码”

public MapPage()
    {
        InitializeComponent();
        //HttpRequest.getDirections(origin, destination, callbackDirections);

        Device.BeginInvokeOnMainThread(() =>
        {
            customMap.RouteCoordinates = new List<Position>
            {
                new Position (37.797534, -122.401827),
                new Position (37.776831, -122.394627)
            };
        });

        //setupMap();
        //setupMapCustom();
    }

因为它(对我来说)不起作用,所以我查看了我的代码,然后我看到了public static readonly BindableProperty RouteCoordinatesProperty = BindableProperty.Create<CustomMap, List<Position>>( p => p.RouteCoordinates, new List<Position>());已弃用..

所以我对此很红post https://forums.xamarin.com/discussion/59503/xamarin-forms-2-1-0-pre5-released/p3实现此绑定的另一种方式,但它也表示这种方式已被弃用SEE HERE https://developer.xamarin.com/api/member/Xamarin.Forms.BindableProperty.Create%7BTDeclarer,TPropertyType%7D/p/System.Linq.Expressions.Expression%7BSystem.Func%7BTDeclarer,TPropertyType%7D%7D/TPropertyType/Xamarin.Forms.BindingMode/Xamarin.Forms.BindableProperty+ValidateValueDelegate%7BTPropertyType%7D/Xamarin.Forms.BindableProperty+BindingPropertyChangedDelegate%7BTPropertyType%7D/Xamarin.Forms.BindableProperty+BindingPropertyChangingDelegate%7BTPropertyType%7D/Xamarin.Forms.BindableProperty+CoerceValueDelegate%7BTPropertyType%7D/Xamarin.Forms.BindableProperty+CreateDefaultValueDelegate%7BTDeclarer,TPropertyType%7D/...我还看到了一些关于绑定的教程,其中说他们将一些代码放入他们的xaml中,让我记住你我的

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     xmlns:local="clr-namespace:NAMESPACE;assembly=NAMESPACE"
     x:Class="NAMESPACE.Controlers.MapPage">
         <ContentPage.Content>
             <local:CustomMap x:Name="customMap"/>
         </ContentPage.Content>
</ContentPage>

我没有使用 ItemSsource="{Polyline Bindable}" 之类的东西


该示例中的自定义渲染器不适用于动态更新路径。它只是针对在初始化地图/第一次绘制路径之前已知路径的所有点的情况实现的。所以你遇到了这种竞争条件,因为你正在从网络服务加载方向。

所以你必须做一些改变:

RouteCoords 必须是 BindableProperty

public class CustomMap : Map
{
    public static readonly BindableProperty RouteCoordinatesProperty =
        BindableProperty.Create<CustomMap, List<Position>>(p => p.RouteCoordinates, new List<Position>());

    public List<Position> RouteCoordinates
    {
        get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
        set { SetValue(RouteCoordinatesProperty, value); }
    }

    public CustomMap ()
    {
        RouteCoordinates = new List<Position>();
    }
}

每当坐标发生变化时更新折线

  • 将折线的创建从OnMapReady to UpdatePolyLine
  • call UpdatePolyLine from OnMapReady and OnElementPropertyChanged
public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
{
    GoogleMap map;
    Polyline polyline;

    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            // Unsubscribe
        }

        if (e.NewElement != null)
        {
            ((MapView)Control).GetMapAsync(this);
        }
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        if (this.Element == null || this.Control == null)
            return;

        if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
        {
            UpdatePolyLine();
        }
    }

    private void UpdatePolyLine()
    {
        if (polyline != null)
        {
            polyline.Remove();
            polyline.Dispose();
        }               

        var polylineOptions = new PolylineOptions();
        polylineOptions.InvokeColor(0x66FF0000);

        foreach (var position in ((CustomMap)this.Element).RouteCoordinates)
        {
            polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
        }

        polyline = map.AddPolyline(polylineOptions);
    }

    public void OnMapReady(GoogleMap googleMap)
    {
        map = googleMap;
        UpdatePolyLine();
    }
}

设定数据

更新位置会发生一些变化。您不必将位置添加到现有列表中,而是必须(创建一个新列表)并将其设置为RouteCoordinates。您可以使用Device.BeginInvokeOnMainThread确保操作在 UI 线程上执行。否则折线将不会更新。

Device.BeginInvokeOnMainThread(() =>
{
    customMap.RouteCoordinates = new List<Position>
    {
        new Position (37.797534, -122.401827),
        new Position (37.776831, -122.394627)
    };
}) 

在你的情况下,它是这样的

var list = new List<Position>(customMap.RouteCoordinates);
list.Add(directionMap.address_end.position);
customMap.RouteCoordinates = list;

Todo

在 iOS 上,您现在必须实现类似的行为(例如UpdatePolyLine)

Note

这可能不是性能最好的实现,因为您重新绘制所有内容而不是添加一个点。但没关系只要你没有性能问题:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Xamarin Forms 地图 - 如何刷新/更新地图 - CustomMap 渲染器 的相关文章

  • Xamarin.Android JmDNS 绑定问题

    我开始研究 Xamarin Android 的 JmDNS 绑定 我设法构建了绑定 但无法从代码中引用它 https github com ytn3rd monodroid bindings tree master JmDNS https
  • 我可以防止将 Leaflet 地图平移到世界边缘之外吗?

    有没有办法限制平移到世界边缘之外 在这幅画中 棕色是世界 灰色是虚空 我想让它不可能像这样平移 Leaflet 允许您控制地图抵抗被拖出边界的程度maxBoundsViscosity选项 值 0 到 1 将其设置为最大值会完全禁用拖动出界
  • 如何将屏幕截图转换为二进制?

    我正在开发一个 Xamarin Forms 项目 在该项目中我想将我的屏幕截图 PNG 转换为二进制并将其上传到服务器 现在服务器部分需要一个API 我将由已经完成它的人交给我 我只需要实现它 在我完成这个任务之后 到目前为止 我已经成功地
  • 以 xamarin 形式获取设备的经纬度位置

    我的应用程序中有一个扫描仪 当我扫描任何二维码时 我需要获取设备的当前位置 经纬度 我不知道如何获取位置 所以我现在没有任何代码 建议我一些在扫描完成二维码时获取位置的方法 地理定位器插件示例 var locator CrossGeoloc
  • 为什么 Visual Studio (Xamarin) 中的 Android 资源文件不允许有重音符号?

    我有一个 Visual Studio Xamarin Android 项目 其文件名称中包含重音字符 di rio png 该文件位于 Assets 文件夹中 并标记为 Android Asset 不幸的是 当我构建项目时 出现编译错误 C
  • 无法再在模拟器或设备上调试

    直到今天早上 我才能在物理设备和模拟器上调试我的 Xamarin iOS 应用程序 我认为这与最近的iOS更新有关 当我尝试部署到我的物理设备 iPad 时 我现在收到以下消息 错误 HE0003 无法加载框架 IBFoundation 路
  • 如何隐藏或删除由xaml创建的特定tableSection(Xamarin.forms)?

    我正在使用 Xamarin form 制作应用程序 我创建了包含 xaml 三个部分的 tableview 我想隐藏或删除最后一部分 整个部分 带有sectionTitle 但不幸的是 Xamarin xaml 不支持条件处理 仅当元素具有
  • 启动注册期间无法加载程序集“System.Buffers”

    我的 Xamarin 表单应用程序大约 5 分钟前运行 然后突然停止工作 应用程序启动后立即关闭 下面显示了 Visual Studio 输出中的消息显示 Assembly Loader probing location System Bu
  • Xamarin、Autofac、NavigationService 和 BeginLifetimeScope

    关于带有 autofac 的生命周期范围以及何时在 xamarin 应用程序中使用它们的初学者问题 正如这篇文章中提到的 https nblumhardt com 2011 01 an autofac lifetime primer htt
  • Django:登录用户并在同一页面上刷新而不定义模板?

    我正在尝试使用引导下拉登录表单来让用户登录 我可以对我的用户名和密码进行硬编码并进行身份验证 但我试图在不进入登录屏幕的情况下让用户登录 这是我的代码 模板 我使用操作来调用 logUserIn url 以便表单可以发布到该视图 ul cl
  • 如何获取存储在MySQL中的经纬度位置并在Android地图应用程序中使用它

    我试图获取存储在 MySQL 中的纬度和经度位置 我想将这些值用于我的 Android 地图应用程序 这是我的代码 Java脚本 Button direction Button findViewById R id btnDir direct
  • 在 Xamarin.Forms 上的图像顶部叠加标签、列表和按钮

    我想制作一个页面 其中有一张图片 基本上页面上的其他所有内容都位于图像之上 与此类似的东西 XAML 代码如下
  • Xamarin.Forms:绑定到 XAML 中属性背后的代码

    在 Xamarin Forms 中 我想将属性后面的代码绑定到 XAML 中的标签 我找到了很多关于这个主题的答案和网页 但它们都涵盖了更复杂的场景 这是我的 XAML 页面
  • 当变量更新时动态刷新模板的一部分golang

    在Golang中 当变量更新时可以刷新模板的一部分吗 例如 我们可以在 Angular js 中找到这一点 基本上在我的代码中 我通过 ajax 中的邮政编码查找地址 它显示我找到的该邮政编码的用户列表 Here is a sample o
  • GetAsync 请求返回空内容

    我想知道为什么当我在邮递员中尝试它有数据返回时它返回 null 这是我的代码 public async Task
  • PHP - 按后退按钮时 Session_Destroy

    这是我的问题 我有一个名为login php 的登录页面 不包含HTML 代码 当用户正确输入其凭据时 他会被重定向到特定页面 在本例中我们将使用 test php 该页面上的唯一链接会注销当前会话 并将用户返回到index html 我的
  • 在 MonoDroid 中设置 textview 的文本时,“jobject”不能为 IntPtr.Zero

    我将 MvvmCross 与 MonoDroid 一起使用 在视图模型中的计时器中 我每分钟调用RaisePropertyChanged MinutesRemaining MinutesRemaining是一个整数 指定当前条目结束之前的持
  • Xamarin.Forms 绘图[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在为客户构建一个 Xamarin Forms 项目 我们需要一个图形库它将处理实时流式传输的数据连
  • Xamarin.iOS 目标 iOS 6 SDK

    我们已升级到 XCode 5 和 Xamarin iOS 7 x 但有一个应用程序尚未准备好支持 iOS 7 有没有办法以 iOS 6 0 SDK 为目标 并编译应用程序 使其具有旧的 iOS 6 键盘等 我们尝试更改 iOS Build
  • SQLite创建连接时出现异常

    我在创建连接时收到 SQLite 异常 这在我安装 VS2015 RTM 之前有效 客户端 PCL databaseConnection DependencyService Get

随机推荐