Přizpůsobení bodu na mapě

Download Sample Stažení ukázky

Tento článek ukazuje, jak vytvořit vlastní renderer pro ovládací prvek Mapa, který zobrazuje nativní mapu s přizpůsobeným špendlíkem a přizpůsobeným zobrazením dat připnutí na jednotlivých platformách.

Každé Xamarin.Forms zobrazení má doprovodný renderer pro každou platformu, která vytvoří instanci nativního ovládacího prvku. Když aplikace Map v iOSu Xamarin.Forms vykresluje aplikaci, MapRenderer vytvoří se instance třídy, která následně vytvoří instanci nativního MKMapView ovládacího prvku. Na platformě Android třída MapRenderer vytvoří instanci nativního MapView ovládacího prvku. V Univerzální platforma Windows (UPW) třída MapRenderer vytvoří instanci nativní MapControl. Další informace o rendereru a nativních tříd ovládacích prvcích, které Xamarin.Forms řídí mapování, naleznete v tématu Renderer Základní třídy a nativní ovládací prvky.

Následující diagram znázorňuje vztah mezi Map a odpovídajícími nativními ovládacími prvky, které ho implementují:

Relationship Between the Map Control and the Implementing Native Controls

Proces vykreslování lze použít k implementaci přizpůsobení specifických pro platformu vytvořením vlastního rendereru pro každou platformu Map . Postup je následující:

  1. VytvořteXamarin.Forms vlastní mapu.
  2. Využití vlastní mapy z Xamarin.Forms.
  3. Vytvořte vlastní renderer pro mapu na každé platformě.

Každá položka se teď bude probírat a implementovat CustomMap renderer, který zobrazí nativní mapu s přizpůsobeným špendlíkem a přizpůsobeným zobrazením dat připnutí na jednotlivých platformách.

Poznámka:

Xamarin.Forms.Maps před použitím musí být inicializován a nakonfigurován. Další informace najdete na webu Maps Control.

Vytvoření vlastní mapy

Vlastní ovládací prvek mapy lze vytvořit podtřídou Map třídy, jak je znázorněno v následujícím příkladu kódu:

public class CustomMap : Map
{
    public List<CustomPin> CustomPins { get; set; }
}

Ovládací CustomMap prvek se vytvoří v projektu knihovny .NET Standard a definuje rozhraní API pro vlastní mapu. Vlastní mapa zveřejňuje CustomPins vlastnost, která představuje kolekci CustomPin objektů, které budou vykresleny nativním mapovacím ovládacím prvku na každé platformě. Třída CustomPin je uvedena v následujícím příkladu kódu:

public class CustomPin : Pin
{
    public string Name { get; set; }
    public string Url { get; set; }
}

Tato třída definuje CustomPin jako dědění vlastností Pin třídy a přidání Name a Url vlastnosti.

Využívání vlastní mapy

Na CustomMap tento ovládací prvek lze odkazovat v XAML v projektu knihovny .NET Standard deklarováním oboru názvů pro jeho umístění a použitím předpony oboru názvů ve vlastním ovládacím prvku mapování. Následující příklad kódu ukazuje, jak CustomMap může ovládací prvek využívat stránka XAML:

<ContentPage ...
			       xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer">
	<local:CustomMap x:Name="customMap"
                   MapType="Street" />
</ContentPage>

Předponu local oboru názvů lze pojmenovat cokoli. clr-namespace Hodnoty ale assembly musí odpovídat podrobnostem vlastní mapy. Jakmile je obor názvů deklarován, předpona se použije k odkazování na vlastní mapu.

Následující příklad kódu ukazuje, jak CustomMap může ovládací prvek využívat stránka jazyka C#:

public class MapPageCS : ContentPage
{
    public MapPageCS()
    {
        CustomMap customMap = new CustomMap
        {
            MapType = MapType.Street
        };
        // ...
        Content = customMap;
    }
}

Instance CustomMap se použije k zobrazení nativní mapy na jednotlivých platformách. MapType Vlastnost nastaví styl zobrazení objektu Map, s možnými hodnotami, které jsou definovány v výčtuMapType.

Umístění mapy a špendlíky, které obsahuje, se inicializují, jak je znázorněno v následujícím příkladu kódu:

public MapPage()
{
    // ...
    CustomPin pin = new CustomPin
    {
        Type = PinType.Place,
        Position = new Position(37.79752, -122.40183),
        Label = "Xamarin San Francisco Office",
        Address = "394 Pacific Ave, San Francisco CA",
        Name = "Xamarin",
        Url = "http://xamarin.com/about/"
    };
    customMap.CustomPins = new List<CustomPin> { pin };
    customMap.Pins.Add(pin);
    customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}

Tato inicializace přidá vlastní špendlík a umístí zobrazení mapy s MoveToRegion metodou, která změní pozici a úroveň přiblížení mapy vytvořením MapSpan z Position a a Distance.

Do každého projektu aplikace je teď možné přidat vlastní renderer, který přizpůsobí nativní ovládací prvky mapování.

Vytvoření vlastního rendereru na jednotlivých platformách

Proces vytvoření vlastní třídy rendereru je následující:

  1. Vytvořte podtřídu MapRenderer třídy, která vykreslí vlastní mapu.
  2. Přepište metodu OnElementChanged , která vykreslí vlastní mapování a logiku zápisu, aby ji přizpůsobila. Tato metoda se volá při vytvoření odpovídajícího Xamarin.Forms vlastního mapování.
  3. Přidejte do vlastní třídy rendereru ExportRenderer atribut, který určí, že se použije k vykreslení Xamarin.Forms vlastní mapy. Tento atribut se používá k registraci vlastního rendereru v Xamarin.Forms.

Poznámka:

V každém projektu platformy je volitelné zadat vlastní renderer. Pokud není zaregistrovaný vlastní renderer, použije se výchozí renderer základní třídy ovládacího prvku.

Následující diagram znázorňuje zodpovědnosti jednotlivých projektů v ukázkové aplikaci spolu s relacemi mezi nimi:

CustomMap Custom Renderer Project Responsibilities

Ovládací CustomMap prvek je vykreslen pomocí tříd rendereru specifických pro platformu, které jsou odvozeny od třídy pro každou platformu MapRenderer . Výsledkem je vykreslení každého CustomMap ovládacího prvku pomocí ovládacích prvků specifických pro platformu, jak je znázorněno na následujících snímcích obrazovky:

CustomMap on each Platform

MapRenderer Třída zveřejňuje metoduOnElementChanged, která je volána při Xamarin.Forms vytvoření vlastní mapování pro vykreslení odpovídajícího nativního ovládacího prvku. Tato metoda přebírá ElementChangedEventArgs parametr, který obsahuje OldElement a NewElement vlastnosti. Tyto vlastnosti představují Xamarin.Forms prvek, ke kterému byl renderer připojen, a Xamarin.Forms prvek, ke kterému je renderer připojen, v uvedeném pořadí. V ukázkové aplikaci OldElement bude vlastnost a NewElement vlastnost bude obsahovat odkaz na CustomMapnull instanci.

Přepsáná verze OnElementChanged metody v každé třídě rendereru specifické pro platformu je místo pro provedení přizpůsobení nativního ovládacího prvku. Typový odkaz na nativní ovládací prvek, který se používá na platformě, je přístupný prostřednictvím Control vlastnosti. Kromě toho lze prostřednictvím vlastnosti získat Element odkaz na Xamarin.Forms vykreslovaný ovládací prvek.

Při přihlášení k odběru obslužných rutin událostí v OnElementChanged metodě je potřeba věnovat pozornost, jak je znázorněno v následujícím příkladu kódu:

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

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

  if (e.NewElement != null)
  {
      // Configure the native control and subscribe to event handlers
  }
}

Nativní ovládací prvek by se měl nakonfigurovat a obslužné rutiny událostí odebírané pouze v případě, že je vlastní renderer připojený k novému Xamarin.Forms prvku. Podobně by se měly všechny obslužné rutiny událostí, které byly přihlášeny k odběru, odhlásit pouze tehdy, když je prvek, který renderer připojí ke změnám. Přijetí tohoto přístupu vám pomůže vytvořit vlastní renderer, který netrpí nevracením paměti.

Každá vlastní třída rendereru je zdobena ExportRenderer atributem, který registruje renderer s Xamarin.Forms. Atribut má dva parametry – název typu vykreslovaného vlastního Xamarin.Forms ovládacího prvku a název typu vlastního rendereru. Předpona assembly atributu určuje, že atribut se vztahuje na celé sestavení.

Následující části se týkají implementace jednotlivých vlastních tříd rendereru specifických pro platformu.

Vytvoření vlastního rendereru v iOSu

Následující snímky obrazovky znázorňují mapu před a po přizpůsobení:

Screenshots show a mobile device with an ordinary pin and an annotated pin.

V iOSu se pin označuje jako poznámka a může se jednat o vlastní obrázek nebo systémově definovaný špendlík různých barev. Poznámky můžou volitelně zobrazit bublinový popisek, který se zobrazí v reakci na uživatele, který vybere poznámku. Bublinový popisek zobrazí Label vlastnosti a Address vlastnosti Pin instance s volitelnými zobrazeními zleva a doprava. Na snímku obrazovky výše je zobrazení levého přístupového objektu obrázek opice s pravým zobrazením příslušenství, které je tlačítkem Informace .

Následující příklad kódu ukazuje vlastní renderer pro platformu iOS:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.iOS
{
    public class CustomMapRenderer : MapRenderer
    {
        UIView customPinView;
        List<CustomPin> customPins;

        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                var nativeMap = Control as MKMapView;
                if (nativeMap != null)
                {
                    nativeMap.RemoveAnnotations(nativeMap.Annotations);
                    nativeMap.GetViewForAnnotation = null;
                    nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
                    nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
                    nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
                }
            }

            if (e.NewElement != null)
            {
                var formsMap = (CustomMap)e.NewElement;
                var nativeMap = Control as MKMapView;
                customPins = formsMap.CustomPins;

                nativeMap.GetViewForAnnotation = GetViewForAnnotation;
                nativeMap.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
                nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
                nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
            }
        }
        // ...
    }
}

Metoda OnElementChanged provádí následující konfiguraci instance za předpokladu MKMapView , že vlastní renderer je připojen k novému Xamarin.Forms prvku:

Zobrazení poznámky

Metoda GetViewForAnnotation se volá, když se umístění anotace zobrazí na mapě a slouží k přizpůsobení anotace před zobrazením. Poznámka má dvě části:

  • MkAnnotation – obsahuje název, podnadpis a umístění poznámky.
  • MkAnnotationView – obsahuje obrázek, který představuje poznámku, a volitelně popisek, který se zobrazí, když uživatel klepne na poznámku.

Metoda GetViewForAnnotation přijme IMKAnnotation , která obsahuje data poznámek a vrátí MKAnnotationView zobrazení na mapě a je znázorněna v následujícím příkladu kódu:

protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
    MKAnnotationView annotationView = null;

    if (annotation is MKUserLocation)
        return null;

    var customPin = GetCustomPin(annotation as MKPointAnnotation);
    if (customPin == null)
    {
        throw new Exception("Custom pin not found");
    }

    annotationView = mapView.DequeueReusableAnnotation(customPin.Name);
    if (annotationView == null)
    {
        annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
        annotationView.Image = UIImage.FromFile("pin.png");
        annotationView.CalloutOffset = new CGPoint(0, 0);
        annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
        annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
        ((CustomMKAnnotationView)annotationView).Name = customPin.Name;
        ((CustomMKAnnotationView)annotationView).Url = customPin.Url;
    }
    annotationView.CanShowCallout = true;

    return annotationView;
}

Tato metoda zajistí, že se poznámka zobrazí jako vlastní obrázek, nikoli jako systémový pin kód, a že se při klepnutí na poznámku zobrazí popisek, který bude obsahovat další obsah vlevo a vpravo od názvu a adresy poznámky. To se provádí takto:

  1. Volá se GetCustomPin metoda pro vrácení vlastních dat připnutí pro anotaci.
  2. Aby se ušetřila paměť, je zobrazení poznámek ve fondu pro opakované použití s voláním DequeueReusableAnnotation.
  3. Třída CustomMKAnnotationView rozšiřuje MKAnnotationView třídu o Name vlastnosti Url , které odpovídají identickým vlastnostem CustomPin v instanci. Vytvoří se nová instance za předpokladu CustomMKAnnotationView , že poznámka je null:
    • Vlastnost CustomMKAnnotationView.Image je nastavena na obrázek, který bude představovat poznámku na mapě.
    • Vlastnost CustomMKAnnotationView.CalloutOffset je nastavena na CGPoint hodnotu, která určuje, že popisek bude zacentrován nad poznámkou.
    • Vlastnost CustomMKAnnotationView.LeftCalloutAccessoryView je nastavena na obrázek opice, která se zobrazí nalevo od názvu a adresy poznámky.
    • Vlastnost CustomMKAnnotationView.RightCalloutAccessoryView je nastavena na tlačítko Informace , které se zobrazí vpravo od názvu a adresy poznámky.
    • Vlastnost je nastavena CustomMKAnnotationView.Name na CustomPin.Name vlastnost vrácenou metodou GetCustomPin . To umožňuje identifikaci poznámek, aby bylo možné popisek dále přizpůsobit, pokud je to žádoucí.
    • Vlastnost je nastavena CustomMKAnnotationView.Url na CustomPin.Url vlastnost vrácenou metodou GetCustomPin . Adresa URL se přepne, když uživatel klepne na tlačítko zobrazené v pravém zobrazení přístupového popisku.
  4. Vlastnost MKAnnotationView.CanShowCallout je nastavena tak true , aby se bublinový popisek zobrazil při klepnutí na poznámku.
  5. Pro zobrazení na mapě se vrátí poznámka.

Výběr poznámky

Když uživatel klepne na poznámku, DidSelectAnnotationView aktivuje se událost, která následně spustí metodu OnDidSelectAnnotationView :

void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
{
    CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
    customPinView = new UIView();

    if (customView.Name.Equals("Xamarin"))
    {
        customPinView.Frame = new CGRect(0, 0, 200, 84);
        var image = new UIImageView(new CGRect(0, 0, 200, 84));
        image.Image = UIImage.FromFile("xamarin.png");
        customPinView.AddSubview(image);
        customPinView.Center = new CGPoint(0, -(e.View.Frame.Height + 75));
        e.View.AddSubview(customPinView);
    }
}

Tato metoda rozšiřuje existující bublinový popisek (který obsahuje zobrazení levého a pravého přístupového objektu) přidáním UIView instance, která obsahuje obrázek loga Xamarinu za předpokladu, že vybraná poznámka má jeho Name vlastnost nastavena na Xamarin. To umožňuje scénáře, ve kterých se pro různé poznámky dají zobrazit různé bublinové popisky. Instance UIView se zobrazí uprostřed nad existujícím popisem.

Klepnutí na pravé zobrazení přístupového popisku

Když uživatel klepne na tlačítko Informace v pravém zobrazení přístupového popisku, CalloutAccessoryControlTapped událost se aktivuje, což následně spustí metodu OnCalloutAccessoryControlTapped :

void OnCalloutAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)
{
    CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
    if (!string.IsNullOrWhiteSpace(customView.Url))
    {
        UIApplication.SharedApplication.OpenUrl(new Foundation.NSUrl(customView.Url));
    }
}

Tato metoda otevře webový prohlížeč a přejde na adresu uloženou CustomMKAnnotationView.Url ve vlastnosti. Všimněte si, že adresa byla definována při vytváření CustomPin kolekce v projektu knihovny .NET Standard.

Zrušení výběru poznámky

Když se zobrazí poznámka a uživatel klepne na mapu, DidDeselectAnnotationView aktivuje se událost, která následně spustí metodu OnDidDeselectAnnotationView :

void OnDidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)
{
    if (!e.View.Selected)
    {
        customPinView.RemoveFromSuperview();
        customPinView.Dispose();
        customPinView = null;
    }
}

Tato metoda zajistí, že pokud není vybraný existující popisek, přestane se zobrazovat i rozšířená část popisku (obrázek loga Xamarinu) a uvolní se její prostředky.

Další informace o přizpůsobení MKMapView instance najdete v tématu Mapy iOS.

Vytvoření vlastního rendereru v Androidu

Následující snímky obrazovky znázorňují mapu před a po přizpůsobení:

Screenshots show a mobile device with an ordinary marker and a customized marker.

V Androidu se špendlík nazývá značka a může to být vlastní obrázek nebo značka definovaná systémem různých barev. Značky můžou zobrazit informační okno, které se zobrazí v reakci na uživatele, který klepne na značku. V okně s informacemi se Label zobrazí vlastnosti Pin instance Address a dá se přizpůsobit tak, aby zahrnovalo další obsah. Najednou se ale dá zobrazit jenom jedno okno s informacemi.

Následující příklad kódu ukazuje vlastní renderer pro platformu Android:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.Droid
{
    public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
    {
        List<CustomPin> customPins;

        public CustomMapRenderer(Context context) : base(context)
        {
        }

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

            if (e.OldElement != null)
            {
                NativeMap.InfoWindowClick -= OnInfoWindowClick;
            }

            if (e.NewElement != null)
            {
                var formsMap = (CustomMap)e.NewElement;
                customPins = formsMap.CustomPins;
            }
        }

        protected override void OnMapReady(GoogleMap map)
        {
            base.OnMapReady(map);

            NativeMap.InfoWindowClick += OnInfoWindowClick;
            NativeMap.SetInfoWindowAdapter(this);
        }
        ...
    }
}

Za předpokladu, že vlastní renderer je připojen k novému Xamarin.Forms prvku, OnElementChanged metoda načte seznam vlastních špendlíků z ovládacího prvku. GoogleMap Jakmile je instance k dispozici, OnMapReady vyvolá se přepsání. Tato metoda zaregistruje obslužnou rutinu InfoWindowClick události pro událost, která se aktivuje při kliknutí na informační okno a odhlásí se pouze v případě, že je renderer připojen ke změnám. Přepsání OnMapReady také volá metodu SetInfoWindowAdapter k určení, že CustomMapRenderer instance třídy poskytne metody pro přizpůsobení informačního okna.

Třída CustomMapRenderer implementuje GoogleMap.IInfoWindowAdapter rozhraní pro přizpůsobení informačního okna. Toto rozhraní určuje, že musí být implementovány následující metody:

  • public Android.Views.View GetInfoWindow(Marker marker) – Tato metoda je volána k vrácení vlastního informačního okna pro značku. Pokud se vrátí null, použije se výchozí vykreslování oken. Pokud vrátí hodnotu View, pak se View umístí do rámce informačního okna.
  • public Android.Views.View GetInfoContents(Marker marker) – Tato metoda je volána k vrácení View obsahující obsah informačního okna a bude volána pouze v případě, že GetInfoWindow metoda vrátí null. Pokud se vrátí null, použije se výchozí vykreslení obsahu okna s informacemi.

V ukázkové aplikaci je přizpůsobený pouze obsah informačního okna, takže GetInfoWindow metoda se vrátí null k povolení.

Přizpůsobení značky

Ikonu použitou k reprezentaci značky lze přizpůsobit voláním MarkerOptions.SetIcon metody. Toho lze dosáhnout přepsáním CreateMarker metody, která se vyvolá pro každou Pin přidanou do mapy:

protected override MarkerOptions CreateMarker(Pin pin)
{
    var marker = new MarkerOptions();
    marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
    marker.SetTitle(pin.Label);
    marker.SetSnippet(pin.Address);
    marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
    return marker;
}

Tato metoda vytvoří novou MarkerOption instanci pro každou Pin instanci. Po nastavení pozice, popisku a adresy značky se její ikona nastaví pomocí SetIcon metody. Tato metoda přebírá BitmapDescriptor objekt obsahující data potřebná k vykreslení ikony, se BitmapDescriptorFactory třídou poskytující pomocné metody pro zjednodušení vytváření BitmapDescriptor. Další informace o použití BitmapDescriptorFactory třídy k přizpůsobení značky naleznete v tématu Přizpůsobení značky.

Poznámka:

V případě potřeby lze metodu GetMarkerForPin vyvolat ve vykreslovacím modulu mapování, která načte Marker z objektu Pin.

Přizpůsobení informačního okna

Když uživatel klepne na značku, GetInfoContents spustí se metoda za předpokladu GetInfoWindow , že metoda vrátí null. Následující příklad kódu ukazuje metodu GetInfoContents :

public Android.Views.View GetInfoContents(Marker marker)
{
    var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
    if (inflater != null)
    {
        Android.Views.View view;

        var customPin = GetCustomPin(marker);
        if (customPin == null)
        {
            throw new Exception("Custom pin not found");
        }

        if (customPin.Name.Equals("Xamarin"))
        {
            view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
        }
        else
        {
            view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
        }

        var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
        var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);

        if (infoTitle != null)
        {
            infoTitle.Text = marker.Title;
        }
        if (infoSubtitle != null)
        {
            infoSubtitle.Text = marker.Snippet;
        }

        return view;
    }
    return null;
}

Tato metoda vrátí View obsah informačního okna. To se provádí takto:

  • Načte LayoutInflater se instance. Slouží k vytvoření instance souboru XML rozložení do odpovídajícího Viewsouboru .
  • Volá se GetCustomPin metoda pro vrácení vlastních dat připnutí pro informační okno.
  • Rozložení XamarinMapInfoWindow se nafoukne, pokud CustomPin.Name je vlastnost rovna Xamarin. MapInfoWindow Jinak se rozložení nafoukne. To umožňuje scénáře, ve kterých se pro různé značky dají zobrazit různá rozložení okna s informacemi.
  • Prostředky se InfoWindowSubtitleInfoWindowTitle načítají z nafouštěného rozložení a jejich Text vlastnosti jsou nastaveny na odpovídající data z instance za předpokladuMarker, že prostředky nejsou null.
  • Instance View se vrátí pro zobrazení na mapě.

Poznámka:

Informační okno není živé View. Místo toho Android převede View na statický rastrový obrázek a zobrazí ho jako obrázek. To znamená, že zatímco informační okno může reagovat na událost kliknutí, nemůže reagovat na žádné dotykové události nebo gesta a jednotlivé ovládací prvky v informačním okně nemohou reagovat na vlastní události kliknutí.

Kliknutí na okno Informace

Když uživatel klikne na informační okno, InfoWindowClick událost se aktivuje, což následně spustí metodu OnInfoWindowClick :

void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
    var customPin = GetCustomPin(e.Marker);
    if (customPin == null)
    {
        throw new Exception("Custom pin not found");
    }

    if (!string.IsNullOrWhiteSpace(customPin.Url))
    {
        var url = Android.Net.Uri.Parse(customPin.Url);
        var intent = new Intent(Intent.ActionView, url);
        intent.AddFlags(ActivityFlags.NewTask);
        Android.App.Application.Context.StartActivity(intent);
    }
}

Tato metoda otevře webový prohlížeč a přejde na adresu uloženou Url ve vlastnosti načtené CustomPin instance pro Markerobjekt . Všimněte si, že adresa byla definována při vytváření CustomPin kolekce v projektu knihovny .NET Standard.

Další informace o přizpůsobení MapView instance najdete v tématu Mapy API.

Vytvoření vlastního rendereru na Univerzální platforma Windows

Následující snímky obrazovky znázorňují mapu před a po přizpůsobení:

Screenshots show a mobile device with an ordinary map icon and a customized map icon.

Při UPW se špendlík nazývá ikona mapy a může to být vlastní obrázek nebo výchozí obrázek definovaný systémem. Ikona mapy může zobrazit UserControlikonu , která se zobrazí v reakci na uživatele klepnutím na ikonu mapy. Může UserControl zobrazit libovolný obsah, včetně Label vlastností a Address vlastností Pin instance.

Následující příklad kódu ukazuje vlastní renderer UPW:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.UWP
{
    public class CustomMapRenderer : MapRenderer
    {
        MapControl nativeMap;
        List<CustomPin> customPins;
        XamarinMapOverlay mapOverlay;
        bool xamarinOverlayShown = false;

        protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                nativeMap.MapElementClick -= OnMapElementClick;
                nativeMap.Children.Clear();
                mapOverlay = null;
                nativeMap = null;
            }

            if (e.NewElement != null)
            {
                var formsMap = (CustomMap)e.NewElement;
                nativeMap = Control as MapControl;
                customPins = formsMap.CustomPins;

                nativeMap.Children.Clear();
                nativeMap.MapElementClick += OnMapElementClick;

                foreach (var pin in customPins)
                {
                    var snPosition = new BasicGeoposition { Latitude = pin.Pin.Position.Latitude, Longitude = pin.Pin.Position.Longitude };
                    var snPoint = new Geopoint(snPosition);

                    var mapIcon = new MapIcon();
                    mapIcon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///pin.png"));
                    mapIcon.CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible;
                    mapIcon.Location = snPoint;
                    mapIcon.NormalizedAnchorPoint = new Windows.Foundation.Point(0.5, 1.0);

                    nativeMap.MapElements.Add(mapIcon);                    
                }
            }
        }
        ...
    }
}

Metoda OnElementChanged provádí následující operace za předpokladu, že vlastní renderer je připojen k novému Xamarin.Forms prvku:

  • Vymaže MapControl.Children kolekci, aby před registrací obslužné rutiny události pro MapElementClick událost odebrala z mapy všechny existující prvky uživatelského rozhraní. Tato událost se aktivuje, když uživatel klepne nebo klikne na MapElement ikonu a MapControlzruší odběr pouze v případě, že je vykreslovací prvek připojený ke změnám.
  • Každý špendlík v customPins kolekci se zobrazí ve správném zeměpisném umístění na mapě následujícím způsobem:
    • Umístění špendlíku se vytvoří jako Geopoint instance.
    • Vytvoří MapIcon se instance představující špendlík.
    • Obrázek použitý k reprezentaci MapIcon je určen nastavením MapIcon.Image vlastnosti. Obrázek ikony mapy ale není vždy zaručen, že se zobrazí, protože může být zakrytý jinými prvky na mapě. Proto je vlastnost ikony CollisionBehaviorDesired mapy nastavena na MapElementCollisionBehavior.RemainVisible, aby se zajistilo, že zůstane viditelný.
    • Umístění MapIcon je určeno nastavením MapIcon.Location vlastnosti.
    • Vlastnost MapIcon.NormalizedAnchorPoint je nastavena na přibližné umístění ukazatele na obrázku. Pokud tato vlastnost zachová výchozí hodnotu (0,0), která představuje levý horní roh obrázku, změny na úrovni přiblížení mapy můžou vést k tomu, že obrázek odkazuje na jiné místo.
    • Instance MapIcon se přidá do MapControl.MapElements kolekce. Výsledkem je zobrazení ikony mapy na kartě MapControl.

Poznámka:

Při použití stejného obrázku pro více ikon RandomAccessStreamReference mapy by se instance měla deklarovat na úrovni stránky nebo aplikace, aby byl nejlepší výkon.

Zobrazení UserControl

Když uživatel klepne na ikonu mapy, spustí se OnMapElementClick metoda. Následující příklad kódu ukazuje tuto metodu:

private void OnMapElementClick(MapControl sender, MapElementClickEventArgs args)
{
    var mapIcon = args.MapElements.FirstOrDefault(x => x is MapIcon) as MapIcon;
    if (mapIcon != null)
    {
        if (!xamarinOverlayShown)
        {
            var customPin = GetCustomPin(mapIcon.Location.Position);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }

            if (customPin.Name.Equals("Xamarin"))
            {
                if (mapOverlay == null)
                {
                    mapOverlay = new XamarinMapOverlay(customPin);
                }

                var snPosition = new BasicGeoposition { Latitude = customPin.Position.Latitude, Longitude = customPin.Position.Longitude };
                var snPoint = new Geopoint(snPosition);

                nativeMap.Children.Add(mapOverlay);
                MapControl.SetLocation(mapOverlay, snPoint);
                MapControl.SetNormalizedAnchorPoint(mapOverlay, new Windows.Foundation.Point(0.5, 1.0));
                xamarinOverlayShown = true;
            }
        }
        else
        {
            nativeMap.Children.Remove(mapOverlay);
            xamarinOverlayShown = false;
        }
    }
}

Tato metoda vytvoří UserControl instanci, která zobrazí informace o špendlíku. To se provádí takto:

  • Instance MapIcon se načte.
  • Volá se GetCustomPin metoda pro vrácení vlastních dat připnutí, která se zobrazí.
  • Vytvoří se XamarinMapOverlay instance pro zobrazení vlastních dat připnutí. Tato třída je uživatelský ovládací prvek.
  • Zeměpisné umístění, ve kterém se má instance MapControl zobrazitXamarinMapOverlay, se vytvoří jako Geopoint instance.
  • Instance XamarinMapOverlay se přidá do MapControl.Children kolekce. Tato kolekce obsahuje prvky uživatelského rozhraní XAML, které se zobrazí na mapě.
  • Zeměpisné umístění XamarinMapOverlay instance na mapě je nastaveno voláním SetLocation metody.
  • Relativní umístění v XamarinMapOverlay instanci, která odpovídá zadanému umístění, je nastaveno voláním SetNormalizedAnchorPoint metody. Tím se zajistí, že se změny na úrovni přiblížení mapy zobrazí vždy XamarinMapOverlay ve správném umístění.

Pokud se na mapě už zobrazují informace o špendlíku, klepnutím na mapu odeberete XamarinMapOverlay instanci z MapControl.Children kolekce.

Klepnutí na tlačítko Informace

Když uživatel klepne na tlačítko Informace v ovládacím XamarinMapOverlay prvku uživatele, Tapped událost se aktivuje, která následně spustí metodu OnInfoButtonTapped :

private async void OnInfoButtonTapped(object sender, TappedRoutedEventArgs e)
{
    await Launcher.LaunchUriAsync(new Uri(customPin.Url));
}

Tato metoda otevře webový prohlížeč a přejde na adresu uloženou Url ve vlastnosti CustomPin instance. Všimněte si, že adresa byla definována při vytváření CustomPin kolekce v projektu knihovny .NET Standard.

Další informace o přizpůsobení MapControl instance najdete v tématu Mapy a přehledu umístění na webu MSDN.