Dostosowywanie pinezki mapy
W tym artykule pokazano, jak utworzyć niestandardowy moduł renderowania dla kontrolki Mapa, który wyświetla natywną mapę z dostosowanym przypięciem i dostosowanym widokiem danych pinezki na każdej platformie.
Każdy Xamarin.Forms widok ma towarzyszący moduł renderujący dla każdej platformy, który tworzy wystąpienie kontrolki natywnej. Gdy element Map
jest renderowany przez aplikację Xamarin.Forms w systemie iOS, MapRenderer
klasę tworzy wystąpienie, co z kolei tworzy wystąpienie kontrolki natywnej MKMapView
. Na platformie MapRenderer
Android klasa tworzy wystąpienie natywnej MapView
kontrolki. W platforma uniwersalna systemu Windows (UWP) MapRenderer
klasa tworzy wystąpienie natywnej MapControl
klasy . Aby uzyskać więcej informacji na temat klasy renderera i natywnych kontrolek mapowanych Xamarin.Forms na, zobacz Renderer Base Classes and Native Controls (Klasy bazowe modułu renderowania i kontrolki natywne).
Na poniższym diagramie przedstawiono relację między kontrolkami Map
macierzystymi i odpowiadającymi im kontrolkami natywnymi, które je implementują:
Proces renderowania może służyć do implementowania dostosowań specyficznych dla platformy przez utworzenie niestandardowego modułu renderowania dla elementu na Map
każdej platformie. Proces wykonywania tej czynności jest następujący:
- Utwórz mapę niestandardową Xamarin.Forms .
- Zużyj mapę niestandardową z pliku Xamarin.Forms.
- Utwórz niestandardowy moduł renderowania dla mapy na każdej platformie.
Każdy element zostanie omówiony z kolei, aby zaimplementować CustomMap
moduł renderujący, który wyświetla mapę natywną z dostosowanym numerem PIN i dostosowanym widokiem danych pinezki na każdej platformie.
Uwaga
Xamarin.Forms.Maps
należy zainicjować i skonfigurować przed użyciem. Aby uzyskać więcej informacji, zobacz Maps Control
.
Tworzenie mapy niestandardowej
Niestandardową kontrolkę mapy można utworzyć przez podklasę Map
klasy, jak pokazano w poniższym przykładzie kodu:
public class CustomMap : Map
{
public List<CustomPin> CustomPins { get; set; }
}
Kontrolka CustomMap
jest tworzona w projekcie biblioteki .NET Standard i definiuje interfejs API dla mapy niestandardowej. Mapa niestandardowa uwidacznia CustomPins
właściwość reprezentującą kolekcję CustomPin
obiektów, które będą renderowane przez natywną kontrolkę mapy na każdej platformie. Klasa jest pokazana CustomPin
w poniższym przykładzie kodu:
public class CustomPin : Pin
{
public string Name { get; set; }
public string Url { get; set; }
}
Ta klasa definiuje CustomPin
element jako dziedziczący właściwości Pin
klasy oraz dodając Name
i Url
właściwości.
Korzystanie z mapy niestandardowej
Kontrolkę CustomMap
można odwoływać w języku XAML w projekcie biblioteki .NET Standard, deklarując przestrzeń nazw dla swojej lokalizacji i używając prefiksu przestrzeni nazw w kontrolce mapy niestandardowej. Poniższy przykład kodu pokazuje, jak kontrolka CustomMap
może być zużywana przez stronę XAML:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer">
<local:CustomMap x:Name="customMap"
MapType="Street" />
</ContentPage>
Prefiks local
przestrzeni nazw może mieć nazwę dowolnych elementów. clr-namespace
Jednak wartości i assembly
muszą być zgodne ze szczegółami mapy niestandardowej. Po zadeklarowaniu przestrzeni nazw prefiks jest używany do odwołwania się do mapy niestandardowej.
Poniższy przykład kodu pokazuje, jak kontrolka CustomMap
może być zużywana przez stronę języka C#:
public class MapPageCS : ContentPage
{
public MapPageCS()
{
CustomMap customMap = new CustomMap
{
MapType = MapType.Street
};
// ...
Content = customMap;
}
}
Wystąpienie CustomMap
będzie używane do wyświetlania mapy natywnej na każdej platformie. MapType
Właściwość ustawia styl Map
wyświetlania obiektu , z możliwymi wartościami zdefiniowanymi w wyliczeniemMapType
.
Lokalizacja mapy i zawarte w niej pinezki są inicjowane, jak pokazano w poniższym przykładzie kodu:
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)));
}
Ta inicjalizacja dodaje niestandardowy numer PIN i umieszcza widok mapy za MoveToRegion
pomocą metody , która zmienia położenie i poziom powiększenia mapy, tworząc element MapSpan
na podstawie elementu Position
i Distance
.
Niestandardowy moduł renderowania można teraz dodać do każdego projektu aplikacji w celu dostosowania natywnych kontrolek mapy.
Tworzenie niestandardowego modułu renderowania na każdej platformie
Proces tworzenia niestandardowej klasy renderera jest następujący:
- Utwórz podklasę
MapRenderer
klasy, która renderuje mapę niestandardową. - Zastąpi metodę
OnElementChanged
, która renderuje mapę niestandardową i zapisuje logikę, aby ją dostosować. Ta metoda jest wywoływana podczas tworzenia odpowiedniej Xamarin.Forms mapy niestandardowej. ExportRenderer
Dodaj atrybut do niestandardowej klasy renderera, aby określić, że będzie on używany do renderowania mapy niestandardowejXamarin.Forms. Ten atrybut służy do rejestrowania niestandardowego modułu renderowania za pomocą Xamarin.Formspolecenia .
Uwaga
Opcjonalne jest udostępnienie niestandardowego modułu renderowania w każdym projekcie platformy. Jeśli niestandardowy moduł renderowania nie jest zarejestrowany, zostanie użyty domyślny moduł renderowania dla klasy bazowej kontrolki.
Na poniższym diagramie przedstawiono obowiązki każdego projektu w przykładowej aplikacji wraz z relacjami między nimi:
Kontrolka CustomMap
jest renderowana przez klasy renderera specyficzne dla platformy, które pochodzą z MapRenderer
klasy dla każdej platformy. Powoduje to renderowanie każdej CustomMap
kontrolki z kontrolkami specyficznymi dla platformy, jak pokazano na poniższych zrzutach ekranu:
Klasa MapRenderer
uwidacznia metodę OnElementChanged
, która jest wywoływana podczas Xamarin.Forms tworzenia mapy niestandardowej w celu renderowania odpowiedniej kontrolki natywnej. Ta metoda przyjmuje ElementChangedEventArgs
parametr zawierający OldElement
właściwości i NewElement
. Te właściwości reprezentują Xamarin.Forms element dołączony do modułu renderowania, a Xamarin.Forms element, do którego jest dołączony moduł renderujący . W przykładowej aplikacji OldElement
właściwość będzie i null
NewElement
właściwość będzie zawierać odwołanie do CustomMap
wystąpienia.
Zastąpiona wersja metody , w każdej klasie modułu OnElementChanged
renderowania specyficznego dla platformy, to miejsce do wykonania dostosowania natywnej kontrolki. Za pośrednictwem właściwości można uzyskać dostęp do wpisanego odwołania do natywnej kontrolki używanej Control
na platformie. Ponadto można uzyskać odwołanie do Xamarin.Forms renderowanej kontrolki Element
za pośrednictwem właściwości .
Podczas subskrybowania programów obsługi zdarzeń w metodzie OnElementChanged
należy zachować ostrożność, jak pokazano w poniższym przykładzie kodu:
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
}
}
Kontrolka natywna powinna być skonfigurowana i programy obsługi zdarzeń subskrybowane tylko wtedy, gdy niestandardowy moduł renderujący jest dołączony do nowego Xamarin.Forms elementu. Podobnie wszystkie programy obsługi zdarzeń, które zostały zasubskrybowane, powinny zostać anulowane tylko wtedy, gdy element renderujący jest dołączony do zmian. Wdrożenie tego podejścia pomoże utworzyć niestandardowy moduł renderujący, który nie cierpi na przecieki pamięci.
Każda niestandardowa klasa modułu renderowania jest ozdobiona atrybutem ExportRenderer
, który rejestruje program renderujący za pomocą Xamarin.Formspolecenia . Atrybut przyjmuje dwa parametry — nazwę Xamarin.Forms typu renderowanej kontrolki niestandardowej i nazwę typu niestandardowego modułu renderowania. Prefiks assembly
atrybutu określa, że atrybut ma zastosowanie do całego zestawu.
W poniższych sekcjach omówiono implementację poszczególnych niestandardowych klas renderer specyficznych dla platformy.
Tworzenie niestandardowego modułu renderowania w systemie iOS
Na poniższych zrzutach ekranu przedstawiono mapę przed dostosowaniem i po nim:
W systemie iOS numer PIN jest nazywany adnotacją i może być obrazem niestandardowym lub numerem PIN zdefiniowanym przez system różnych kolorów. Adnotacje mogą opcjonalnie wyświetlać objaśnienie, które jest wyświetlane w odpowiedzi na użytkownika wybierającego adnotację. Objaśnienie wyświetla Label
właściwości Pin
i Address
wystąpienia z opcjonalnymi widokami dostępu po lewej i prawej stronie. Na powyższym zrzucie ekranu lewy widok akcesoriów jest obrazem małpy, z odpowiednim widokiem akcesorium jest przycisk Informacje .
Poniższy przykład kodu przedstawia niestandardowy moduł renderowania dla platformy 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
wykonuje następującą konfigurację MKMapView
wystąpienia, pod warunkiem, że niestandardowy moduł renderujący jest dołączony do nowego Xamarin.Forms elementu:
- Właściwość
GetViewForAnnotation
jest ustawiona na metodęGetViewForAnnotation
. Ta metoda jest wywoływana, gdy lokalizacja adnotacji staje się widoczna na mapie i służy do dostosowywania adnotacji przed wyświetleniem. - Programy obsługi zdarzeń
CalloutAccessoryControlTapped
dla zdarzeń ,DidSelectAnnotationView
iDidDeselectAnnotationView
są rejestrowane. Te zdarzenia są wyzwalane, gdy użytkownik naciśnie odpowiednią metodę dostępu w objaśnieniu, a gdy użytkownik wybierze i usunie zaznaczenie adnotacji, odpowiednio. Zdarzenia są anulowane tylko wtedy, gdy element renderator jest dołączony do zmian.
Wyświetlanie adnotacji
Metoda GetViewForAnnotation
jest wywoływana, gdy lokalizacja adnotacji staje się widoczna na mapie i służy do dostosowywania adnotacji przed wyświetleniem. Adnotacja ma dwie części:
MkAnnotation
— zawiera tytuł, podtytuł i lokalizację adnotacji.MkAnnotationView
— zawiera obraz reprezentujący adnotację i opcjonalnie objaśnienie wyświetlane po naciśnięciu adnotacji.
Metoda GetViewForAnnotation
akceptuje element IMKAnnotation
zawierający dane adnotacji i zwraca element MKAnnotationView
do wyświetlania na mapie i jest wyświetlany w poniższym przykładzie kodu:
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;
}
Ta metoda gwarantuje, że adnotacja będzie wyświetlana jako obraz niestandardowy, a nie jako numer PIN zdefiniowany przez system, a gdy adnotacja zostanie naciśnięta, zostanie wyświetlona objaśnienie zawierające dodatkową zawartość po lewej i prawej stronie tytułu adnotacji i adresu. Jest to realizowane w następujący sposób:
- Metoda jest wywoływana
GetCustomPin
w celu zwrócenia niestandardowych danych pin dla adnotacji. - Aby zaoszczędzić pamięć, widok adnotacji jest w puli do ponownego użycia za pomocą wywołania metody
DequeueReusableAnnotation
. - Klasa
CustomMKAnnotationView
rozszerza klasę oMKAnnotationView
Name
właściwości iUrl
odpowiadające identycznym właściwościom w wystąpieniuCustomPin
. Zostanie utworzone nowe wystąpienieCustomMKAnnotationView
elementu , pod warunkiem że adnotacja tonull
:- Właściwość jest ustawiona
CustomMKAnnotationView.Image
na obraz, który będzie reprezentować adnotację na mapie. - Właściwość
CustomMKAnnotationView.CalloutOffset
jest ustawiona na wartośćCGPoint
, która określa, że objaśnienie będzie wyśrodkowane powyżej adnotacji. - Właściwość
CustomMKAnnotationView.LeftCalloutAccessoryView
jest ustawiona na obraz małpy, która będzie widoczna po lewej stronie tytułu i adresu adnotacji. - Właściwość
CustomMKAnnotationView.RightCalloutAccessoryView
jest ustawiona na przycisk Informacje , który będzie wyświetlany po prawej stronie tytułu adnotacji i adresu. - Właściwość
CustomMKAnnotationView.Name
jest ustawionaCustomPin.Name
na właściwość zwracaną przez metodęGetCustomPin
. Dzięki temu adnotacja może zostać zidentyfikowana, aby można było ją dodatkowo dostosować, jeśli jest to konieczne. - Właściwość
CustomMKAnnotationView.Url
jest ustawionaCustomPin.Url
na właściwość zwracaną przez metodęGetCustomPin
. Adres URL zostanie wyświetlony, gdy użytkownik naciągnie przycisk wyświetlany w prawym widoku dostępu objaśnień.
- Właściwość jest ustawiona
- Właściwość
MKAnnotationView.CanShowCallout
jest ustawiona natrue
wartość , aby objaśnienie było wyświetlane po naciśnięciu adnotacji. - Adnotacja jest zwracana do wyświetlania na mapie.
Wybieranie adnotacji
Gdy użytkownik naciśnie adnotację, DidSelectAnnotationView
zdarzenie zostanie uruchomione OnDidSelectAnnotationView
, co z kolei spowoduje wykonanie metody :
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);
}
}
Ta metoda rozszerza istniejące objaśnienie (zawierające widoki akcesoriów po lewej i prawej stronie), dodając UIView
do niego wystąpienie zawierające obraz logo platformy Xamarin, pod warunkiem że wybrana adnotacja ma jej Name
właściwość ustawioną na Xamarin
wartość . Pozwala to na scenariusze, w których różne objaśnienia mogą być wyświetlane dla różnych adnotacji. Wystąpienie UIView
zostanie wyświetlone wyśrodkowane powyżej istniejącego objaśnienie.
Naciśnięcie odpowiedniego widoku akcesoriów objaśniania
Gdy użytkownik naciągnie przycisk Informacje w prawym widoku CalloutAccessoryControlTapped
wywołania, zdarzenie jest uruchamiane, co z kolei wykonuje metodę 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));
}
}
Ta metoda otwiera przeglądarkę internetową i przechodzi do adresu przechowywanego CustomMKAnnotationView.Url
we właściwości . Należy pamiętać, że adres został zdefiniowany podczas tworzenia CustomPin
kolekcji w projekcie biblioteki .NET Standard.
Usuwanie zaznaczenia adnotacji
Gdy adnotacja jest wyświetlana i użytkownik naciśnie na mapie, DidDeselectAnnotationView
zdarzenie jest uruchamiane, co z kolei wykonuje metodę OnDidDeselectAnnotationView
:
void OnDidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)
{
if (!e.View.Selected)
{
customPinView.RemoveFromSuperview();
customPinView.Dispose();
customPinView = null;
}
}
Ta metoda gwarantuje, że po wybraniu istniejącego objaśnienia rozszerzona część objaśnienia (obraz logo platformy Xamarin) również przestanie być wyświetlana, a jej zasoby zostaną zwolnione.
Aby uzyskać więcej informacji na temat dostosowywania MKMapView
wystąpienia, zobacz Mapy systemu iOS.
Tworzenie niestandardowego modułu renderowania w systemie Android
Na poniższych zrzutach ekranu przedstawiono mapę przed dostosowaniem i po nim:
W systemie Android numer PIN jest nazywany znacznikiem i może być obrazem niestandardowym lub znacznikiem zdefiniowanym przez system różnych kolorów. Znaczniki mogą wyświetlać okno informacji, które jest wyświetlane w odpowiedzi na naciśnięcie znacznika przez użytkownika. W oknie informacji są wyświetlane Label
właściwości Pin
i Address
wystąpienia, które można dostosować w celu uwzględnienia innej zawartości. Można jednak wyświetlić tylko jedno okno informacji jednocześnie.
W poniższym przykładzie kodu pokazano niestandardowy moduł renderowania dla platformy 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);
}
...
}
}
Jeśli niestandardowy moduł renderujący jest dołączony do nowego Xamarin.Forms elementu, OnElementChanged
metoda pobiera listę niestandardowych numerów PIN z kontrolki. Po udostępnieniu GoogleMap
OnMapReady
wystąpienia zostanie wywołane przesłonięcia. Ta metoda rejestruje program obsługi zdarzeń dla InfoWindowClick
zdarzenia, który jest uruchamiany po kliknięciu okna informacji i jest anulowany tylko wtedy, gdy element renderator jest dołączony do zmian. Przesłonięcia OnMapReady
wywołuje również metodę SetInfoWindowAdapter
, aby określić, że CustomMapRenderer
wystąpienie klasy zapewni metody dostosowywania okna informacji.
Klasa CustomMapRenderer
implementuje interfejs w GoogleMap.IInfoWindowAdapter
celu dostosowania okna informacji. Ten interfejs określa, że należy zaimplementować następujące metody:
public Android.Views.View GetInfoWindow(Marker marker)
— Ta metoda jest wywoływana w celu zwrócenia niestandardowego okna informacji dla znacznika. Jeśli zwrócinull
wartość , zostanie użyte domyślne renderowanie okna. Jeśli zwróci wartośćView
,View
zostanie ona umieszczona wewnątrz okna informacji.public Android.Views.View GetInfoContents(Marker marker)
— Ta metoda jest wywoływana w celu zwróceniaView
zawartości okna informacji i będzie wywoływana tylko wtedy, gdyGetInfoWindow
metoda zwrócinull
wartość . Jeśli zwrócinull
wartość , zostanie użyte domyślne renderowanie zawartości okna informacji.
W przykładowej aplikacji dostosowywuje się tylko zawartość okna informacji, dlatego GetInfoWindow
metoda zwraca null
tę funkcję.
Dostosowywanie znacznika
Ikona używana do reprezentowania znacznika można dostosować, wywołując metodę MarkerOptions.SetIcon
. Można to zrobić przez zastąpienie CreateMarker
metody, która jest wywoływana dla każdego Pin
dodanego 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;
}
Ta metoda tworzy nowe MarkerOption
wystąpienie dla każdego Pin
wystąpienia. Po ustawieniu pozycji, etykiety i adresu znacznika jego ikona jest ustawiona za pomocą SetIcon
metody . Ta metoda przyjmuje BitmapDescriptor
obiekt zawierający dane niezbędne do renderowania ikony, a BitmapDescriptorFactory
klasa udostępnia metody pomocnicze, aby uprościć tworzenie BitmapDescriptor
obiektu . Aby uzyskać więcej informacji na temat dostosowywania znacznika BitmapDescriptorFactory
przy użyciu klasy, zobacz Dostosowywanie znacznika.
Uwaga
Jeśli jest to wymagane, można wywołać metodę w narzędziu GetMarkerForPin
renderowanym mapy, aby pobrać element Marker
z elementu Pin
.
Dostosowywanie okna informacji
Gdy użytkownik naciągnie znacznik, GetInfoContents
metoda jest wykonywana, pod warunkiem, że GetInfoWindow
metoda zwraca null
wartość . Poniższy przykład kodu przedstawia metodę 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;
}
Ta metoda zwraca View
zawartość okna informacji. Jest to realizowane w następujący sposób:
- Pobrano
LayoutInflater
wystąpienie. Służy do tworzenia wystąpienia pliku XML układu w odpowiadającym muView
pliku . - Metoda jest wywoływana
GetCustomPin
w celu zwrócenia niestandardowych danych pin dla okna informacji. - Układ
XamarinMapInfoWindow
jest zawyżony, jeśliCustomPin.Name
właściwość jest równaXamarin
.MapInfoWindow
W przeciwnym razie układ jest zawyżony. Pozwala to na scenariusze, w których różne układy okien informacyjnych mogą być wyświetlane dla różnych znaczników. - Zasoby
InfoWindowTitle
iInfoWindowSubtitle
są pobierane z zawyżonego układu, a ichText
właściwości są ustawione na odpowiednie dane zMarker
wystąpienia, pod warunkiem, że zasoby nienull
są . - Wystąpienie
View
jest zwracane do wyświetlania na mapie.
Uwaga
Okno informacji nie jest aktywne View
. Zamiast tego system Android przekonwertuje View
element na statyczną mapę bitową i wyświetli go jako obraz. Oznacza to, że chociaż okno informacji może odpowiedzieć na zdarzenie kliknięcia, nie może reagować na żadne zdarzenia lub gesty dotykowe, a poszczególne kontrolki w oknie informacji nie mogą reagować na własne zdarzenia kliknięcia.
Kliknięcie okna informacji
Gdy użytkownik kliknie okno informacji, InfoWindowClick
zdarzenie zostanie wyzwolony, co z kolei spowoduje wykonanie OnInfoWindowClick
metody :
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);
}
}
Ta metoda otwiera przeglądarkę internetową i przechodzi do adresu przechowywanego we Url
właściwości pobranego CustomPin
wystąpienia dla elementu Marker
. Należy pamiętać, że adres został zdefiniowany podczas tworzenia CustomPin
kolekcji w projekcie biblioteki .NET Standard.
Aby uzyskać więcej informacji na temat dostosowywania MapView
wystąpienia, zobacz Interfejs API usługi Maps.
Tworzenie niestandardowego modułu renderowania na platforma uniwersalna systemu Windows
Na poniższych zrzutach ekranu przedstawiono mapę przed dostosowaniem i po nim:
Na platformie UWP pinezka jest nazywana ikoną mapy i może być obrazem niestandardowym lub obrazem domyślnym zdefiniowanym przez system. Ikona mapy może wyświetlić ikonę UserControl
, która jest wyświetlana w odpowiedzi na naciśnięcie przez użytkownika ikony mapy. Element UserControl
może wyświetlać dowolną zawartość, w tym Label
właściwości Pin
i Address
wystąpienia.
W poniższym przykładzie kodu pokazano niestandardowy moduł renderowania platformy UWP:
[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
wykonuje następujące operacje, pod warunkiem, że niestandardowy moduł renderujący jest dołączony do nowego Xamarin.Forms elementu:
- Spowoduje to wyczyszczenie
MapControl.Children
kolekcji w celu usunięcia wszystkich istniejących elementów interfejsu użytkownika z mapy przed zarejestrowaniem programu obsługi zdarzeń dlaMapElementClick
zdarzenia. To zdarzenie jest uruchamiane, gdy użytkownik naciągnie lub kliknie elementMapElement
naMapControl
obiekcie , i zostanie anulowane tylko wtedy, gdy element renderator jest dołączony do zmian. - Każde przypięcie
customPins
w kolekcji jest wyświetlane w odpowiedniej lokalizacji geograficznej na mapie w następujący sposób:- Lokalizacja pinezki jest tworzona
Geopoint
jako wystąpienie. - Zostanie
MapIcon
utworzone wystąpienie reprezentujące numer PIN. - Obraz używany do reprezentowania
MapIcon
elementu jest określony przez ustawienieMapIcon.Image
właściwości . Jednak obraz ikony mapy nie zawsze jest wyświetlany, ponieważ może być zasłonięty przez inne elementy na mapie. W związku z tym właściwość ikonyCollisionBehaviorDesired
mapy jest ustawiona naMapElementCollisionBehavior.RemainVisible
, aby upewnić się, że pozostaje widoczna. - Lokalizacja
MapIcon
obiektu jest określana przez ustawienieMapIcon.Location
właściwości . - Właściwość
MapIcon.NormalizedAnchorPoint
jest ustawiona na przybliżoną lokalizację wskaźnika na obrazie. Jeśli ta właściwość zachowuje domyślną wartość (0,0), która reprezentuje lewy górny róg obrazu, zmiany na poziomie powiększenia mapy mogą spowodować wyświetlenie obrazu wskazującego inną lokalizację. - Wystąpienie
MapIcon
jest dodawane do kolekcjiMapControl.MapElements
. Spowoduje to wyświetlenie ikony mapy naMapControl
.
- Lokalizacja pinezki jest tworzona
Uwaga
W przypadku używania tego samego obrazu dla wielu ikon RandomAccessStreamReference
mapy wystąpienie powinno zostać zadeklarowane na poziomie strony lub aplikacji w celu uzyskania najlepszej wydajności.
Wyświetlanie kontrolek użytkownika
Gdy użytkownik naciągnie ikonę mapy, OnMapElementClick
zostanie wykonana metoda. Poniższy przykład kodu przedstawia tę metodę:
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;
}
}
}
Ta metoda tworzy UserControl
wystąpienie, które wyświetla informacje o numerze PIN. Jest to realizowane w następujący sposób:
- Wystąpienie
MapIcon
jest pobierane. - Metoda jest wywoływana
GetCustomPin
w celu zwrócenia niestandardowych danych pin, które zostaną wyświetlone. - Zostanie
XamarinMapOverlay
utworzone wystąpienie w celu wyświetlenia niestandardowych danych pinezki. Ta klasa jest kontrolką użytkownika. - Lokalizacja geograficzna, w której ma być wyświetlane
XamarinMapOverlay
wystąpienie,MapControl
jest tworzone jakoGeopoint
wystąpienie. - Wystąpienie
XamarinMapOverlay
jest dodawane do kolekcjiMapControl.Children
. Ta kolekcja zawiera elementy interfejsu użytkownika XAML, które będą wyświetlane na mapie. - Lokalizacja
XamarinMapOverlay
geograficzna wystąpienia na mapie jest ustawiana przez wywołanieSetLocation
metody . - Lokalizacja względna w wystąpieniu
XamarinMapOverlay
, która odpowiada określonej lokalizacji, jest ustawiana przez wywołanieSetNormalizedAnchorPoint
metody . Gwarantuje to, że zmiany na poziomie powiększenia mapy powodująXamarinMapOverlay
, że wystąpienie zawsze jest wyświetlane w odpowiedniej lokalizacji.
Alternatywnie, jeśli informacje o numerze PIN są już wyświetlane na mapie, naciśnięcie mapy spowoduje usunięcie XamarinMapOverlay
wystąpienia z MapControl.Children
kolekcji.
Naciśnięcie przycisku Informacje
Gdy użytkownik naciągnie przycisk Informacje w kontrolce XamarinMapOverlay
użytkownika, Tapped
zdarzenie zostanie wyzwolony, co z kolei spowoduje wykonanie OnInfoButtonTapped
metody:
private async void OnInfoButtonTapped(object sender, TappedRoutedEventArgs e)
{
await Launcher.LaunchUriAsync(new Uri(customPin.Url));
}
Ta metoda otwiera przeglądarkę internetową i przechodzi do adresu przechowywanego Url
we właściwości CustomPin
wystąpienia. Należy pamiętać, że adres został zdefiniowany podczas tworzenia CustomPin
kolekcji w projekcie biblioteki .NET Standard.
Aby uzyskać więcej informacji na temat dostosowywania MapControl
wystąpienia, zobacz Mapy i lokalizacja — omówienie w witrynie MSDN.