【问题标题】:Xamarin Forms Maps - how to refresh/update the map - CustomMap RendererXamarin Forms Maps - 如何刷新/更新地图 - CustomMap Renderer
【发布时间】:2016-08-21 02:05:45
【问题描述】:

如果您正在搜索完整的折线、图钉、图块、UIOptions(以及即将推出的 3D 效果)渲染/实现,您应该在我在 XamarinByEmixam23/..../Map 上创建的公共 github 上搜索一下。


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

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

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

我按照本教程制作地图:Working with maps

要自定义它,我遵循了这个教程:Highlight a Route on a Map

所以,在这些教程之后(我做了同样的事情,没有改变),我尝试了 2 个 RouteCoordinates,它给了我一条直线......然后我做了一个完美的算法。

方向图

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; }
    }
}

ResponseHttpParser

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;
    }
}

我只是得到一些私人计算的距离和持续时间,并得到我放入列表中的每一步;

当一切都完成后,我使用回调将我们带回控制器(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);
        }
    }
}

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

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

我像你一样更新了 CustomMap

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>();
    }
}

CustomMapRenderer (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 中,我按照您的解释对 callbackDirections 进行了更改(我希望我做得很好)

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 绑定方面的专家,所以如果我忘记了什么,很抱歉:/

编辑 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 上用了一种不同的方式来实现这个绑定,但它也说这种方式已被弃用SEE HERE...我还看到了一些关于绑定的教程,上面说他们把一些代码放入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>

我没有使用 ItemSource="{PolylineBindable}"

【问题讨论】:

    标签: xamarin maps refresh xamarin.forms updates


    【解决方案1】:

    示例中的自定义渲染器不适用于动态更新路径。它仅适用于在第一次初始化地图/绘制路径之前已知路径的所有点的情况。因此,您遇到了这种竞争条件,因为您正在从 Web 服务加载路线。

    所以你必须做一些改变:

    RouteCoordinates 必须是 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 移动到UpdatePolyLine
    • OnMapReadyOnElementPropertyChanged 拨打UpdatePolyLine
    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;
    

    待办事项

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

    注意

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

    【讨论】:

    • 感谢您的回答!请看看我的编辑 1 :)
    • 请仔细阅读我的回答(待办事项上方的部分)。我说,你必须改变将职位添加到列表中的方式。如果您调用customMap.RouteCoordinates.Add(...),渲染器不会注意到您必须分配列表,因为设置器会触发OnElementPropertyChanged。这可以理解吗?
    • 我想我当时不明白。我复制/粘贴你的代码,但它不起作用。之后,我无法完全复制/粘贴您的代码,因为在设置数据部分,我必须更改一些内容。现在您说我可能没有仔细阅读您的答案,也许我只是不明白,不是因为您的示例不好,而是因为我没有您的水平;)但是,我在代码中看到public static readonly BindableProperty RouteCoordinatesProperty = BindableProperty.Create&lt;CustomMap, List&lt;Position&gt;&gt;(p =&gt; p.RouteCoordinates, new List&lt;Position&gt;()); 已弃用.. EDIT 2
    • 嗨,我想知道,自上次以来,您能否给我一个答复? :/ 我还是被屏蔽了.. 我试了很多次,很烦:(
    • 我给你的肯定是有效的。我用棉花糖在 Nexus 5 上试过。所以我只能想象加载数据和地图初始化之间的某种竞争条件。
    【解决方案2】:

    因此,经过大量搜索,当然还有@Sven-Michael Stübe 的回答,您可以拥有适用于每个平台“Android、iOS、WinPhone”的正确地图。按照我的代码,然后按照@Sven-Michael Stübe 的回答对其进行编辑。

    一旦你完成了所有工作,它就可以工作(比如@Sven-Michael Stübe),但它也不能工作(比如我)。如果不行,请尝试更改以下代码:

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

    通过

    public static readonly BindableProperty RouteCoordinatesProperty =
        BindableProperty.Create(nameof(RouteCoordinates), typeof(List<Position>), typeof(CustomMap), new List<Position>(), BindingMode.TwoWay);
    

    See the documentation for more information about it. (Deprecated implementation)

    然后代码工作!

    PS:最后的折线可能有一些问题,它没有按照正确的道路,我正在努力。

    PS2:我还将制作一个视频来解释如何编写您的 customMap 以不必安装 NuGet 包,以便能够在最后编辑所有内容! (第一个是法语,第二个是英文,这个帖子会在视频制作时编辑)

    再次感谢@Sven-Michael Stübe!也感谢他的回答:)

    【讨论】:

      【解决方案3】:

      在这些答案的基础上,这是我为使其在 iOS 上运行所做的工作。这与 Xamarin 示例不同,即使在加载地图后也可以更改路线。

      首先,根据@Sven-Michael Stübe 的自定义地图类以及来自@Emixam23 的更新:

      public class CustomMap : Map
      {
          public static readonly BindableProperty RouteCoordinatesProperty =
              BindableProperty.Create(nameof(RouteCoordinates), typeof(List<Position>), typeof(CustomMap), new List<Position>(), BindingMode.TwoWay);
      
          public List<Position> RouteCoordinates
          {
              get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
              set { SetValue(RouteCoordinatesProperty, value); }
          }
      
          public CustomMap()
          {
              RouteCoordinates = new List<Position>();
          }
      }
      

      接下来,iOS 自定义渲染器:

      [assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
      namespace KZNTR.iOS
      {
          public class CustomMapRenderer : MapRenderer
          {
              MKPolylineRenderer polylineRenderer;
              CustomMap map;
      
              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)
                  {
                      map = (CustomMap)sender;
                      UpdatePolyLine();
                  }
              }
      
              [Foundation.Export("mapView:rendererForOverlay:")]
              MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlay)
              {
                  if (polylineRenderer == null)
                  {
                      var o = ObjCRuntime.Runtime.GetNSObject(overlay.Handle) as MKPolyline;
      
                      polylineRenderer = new MKPolylineRenderer(o);
                      //polylineRenderer = new MKPolylineRenderer(overlay as MKPolyline);
                      polylineRenderer.FillColor = UIColor.Blue;
                      polylineRenderer.StrokeColor = UIColor.Red;
                      polylineRenderer.LineWidth = 3;
                      polylineRenderer.Alpha = 0.4f;
                  }
                  return polylineRenderer;
              }
      
              private void UpdatePolyLine()
              {
      
                  var nativeMap = Control as MKMapView;
      
                  nativeMap.OverlayRenderer = GetOverlayRenderer;
      
                  CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[map.RouteCoordinates.Count];
      
                  int index = 0;
                  foreach (var position in map.RouteCoordinates)
                  {
                      coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
                      index++;
                  }
      
                  var routeOverlay = MKPolyline.FromCoordinates(coords);
                  nativeMap.AddOverlay(routeOverlay);
              }
          }
      }
      

      最后,在地图上添加一条折线:

                  Device.BeginInvokeOnMainThread(() =>
                  {
                      customMap.RouteCoordinates.Clear();
      
                      var plist = new List<Position>(customMap.RouteCoordinates);
      
                      foreach (var point in track.TrackPoints)
                      {
                          plist.Add(new Position(double.Parse(point.Latitude, CultureInfo.InvariantCulture), double.Parse(point.Longitude, CultureInfo.InvariantCulture)));
                      }
      
                      customMap.RouteCoordinates = plist;
      
                      var firstpoint = (from pt in track.TrackPoints select pt).FirstOrDefault();
                      customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(double.Parse(firstpoint.Latitude, CultureInfo.InvariantCulture), double.Parse(firstpoint.Longitude, CultureInfo.InvariantCulture)), Distance.FromMiles(3.0)));
      
                  });
      

      不确定这是最好的方法还是最有效的方法,我对渲染器了解不多,但它似乎确实有效。

      【讨论】:

      • 这是否允许在人走路或跑步时渲染地图我的意思是更新地图你在 2018 年对此有何更好的方法
      【解决方案4】:

      我关注了 Xamarin Docs 上提供的 tutorial,它对我有用,基于 @Sven-Michael Stübe answer 进行了一些更改

      我从 WebService 加载坐标,然后创建一个单独的列表,然后将新列表设置为自定义地图上的 RouteCoordinates 属性。

      在 Android 渲染器上进行了一些更改

      我正在使用 MVVM。

      CustomMap 类

      public static readonly BindableProperty RouteCoordinatesProperty =
              BindableProperty.Create(nameof(RouteCoordinates), typeof(List<Position>), typeof(CustomMap), new List<Position>(), BindingMode.TwoWay);
      
      public List<Position> RouteCoordinates
      {
          get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
          set { SetValue(RouteCoordinatesProperty, value); }
      }
      
      public CustomMap()
      {
          RouteCoordinates = new List<Position>();
      }
      

      ViewModel(代码隐藏,在您的情况下):

      private async void LoadCoordinates(string oidAula, CustomMap mapa)
      {
          IsBusy = true;
      
          var percurso = await ComunicacaoServidor.GetPercurso(oidAula); // Get coordinates from WebService
          var pontos = percurso.Select(p => new Position(p.Latitude, p.Longitude)).ToList(); // Create coordinates list from webservice result
      
          var latitudeMedia = percurso[percurso.Count / 2].Latitude;
          var longitudeMedia = percurso[percurso.Count / 2].Longitude;
      
          mapa.RouteCoordinates = pontos;
          mapa.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(latitudeMedia, longitudeMedia), Distance.FromMiles(1.0)));
      
          IsBusy = false;
      }
      

      XAML:

      <maps:CustomMap
              AbsoluteLayout.LayoutFlags  = "All"
              AbsoluteLayout.LayoutBounds = "0, 0, 1, 1"
              VerticalOptions             = "FillAndExpand"
              HorizontalOptions           = "FillAndExpand"
              x:Name                      = "PercursoMapa" />
      

      Android 渲染器

      public class CustomMapRenderer : MapRenderer
      {
          bool isDrawn;
      
          protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
          {
              base.OnElementChanged(e);
      
              if (e.OldElement != null)
              {
                  // Unsubscribe
              }
      
              if (e.NewElement != null)
                  Control.GetMapAsync(this);
          }
      
          protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
          {
              base.OnElementPropertyChanged(sender, e);
      
              if ((e.PropertyName == "RouteCoordinates" || e.PropertyName == "VisibleRegion") && !isDrawn)
              {
                  var polylineOptions = new PolylineOptions();
                  polylineOptions.InvokeColor(0x66FF0000);
      
                  var coordinates = ((CustomMap)Element).RouteCoordinates;
      
                  foreach (var position in coordinates)
                      polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
      
                  NativeMap.AddPolyline(polylineOptions);
                  isDrawn = coordinates.Count > 0;
              }
          }
      }
      

      此示例有超过 3600 个位置点,并且折线在设备上正确显示:

      Screenshot

      【讨论】:

      • 我编辑了问题,但是感谢MVVM的实现,手下还是不错的!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 2020-08-19
      • 2019-01-17
      • 2017-06-05
      相关资源
      最近更新 更多