Sdílet prostřednictvím


Mapy v Xamarin.iOS

Mapy jsou běžnou funkcí ve všech moderních mobilních operačních systémech. iOS nabízí nativně podporu mapování prostřednictvím architektury Map Kit. Pomocí sady Map Kit můžou aplikace snadno přidávat bohaté interaktivní mapy. Tyto mapy lze přizpůsobit různými způsoby, například přidáním poznámek k označení umístění na mapě a překrytím grafiky libovolných obrazců. Map Kit má dokonce integrovanou podporu pro zobrazení aktuálního umístění zařízení.

Přidání mapy

Přidání mapy do aplikace se provádí přidáním MKMapView instance do hierarchie zobrazení, jak je znázorněno níže:

// map is an MKMapView declared as a class variable
map = new MKMapView (UIScreen.MainScreen.Bounds);
View = map;

MKMapViewUIView je podtřída, která zobrazuje mapu. Jednoduše přidáním mapy pomocí výše uvedeného kódu vznikne interaktivní mapa:

Ukázková mapa

Styl mapy

MKMapView podporuje 3 různé styly map. Pokud chcete použít styl mapy, jednoduše nastavte MapType vlastnost na hodnotu z výčtu MKMapType :

map.MapType = MKMapType.Standard; //road map
map.MapType = MKMapType.Satellite;
map.MapType = MKMapType.Hybrid;

Následující snímek obrazovky ukazuje různé dostupné styly mapy:

Tento snímek obrazovky ukazuje různé dostupné styly mapy.

Posouvání a přiblížení

MKMapView zahrnuje podporu pro funkce interaktivity mapování, jako jsou:

  • Přiblížení gestem připnutí
  • Posouvání pomocí gesta posouvání

Tyto funkce je možné povolit nebo zakázat jednoduchým nastavením ZoomEnabled a ScrollEnabled vlastnostmi MKMapView instance, kde výchozí hodnota platí pro oba. Pokud chcete například zobrazit statickou mapu, jednoduše nastavte odpovídající vlastnosti na false:

map.ZoomEnabled = false;
map.ScrollEnabled = false;

Umístění uživatele

Kromě interakce MKMapView uživatelů má také integrovanou podporu pro zobrazení polohy zařízení. Dělá to pomocí architektury Core Location . Než budete mít přístup k umístění uživatele, musíte uživatele vyzvat. Chcete-li to provést, vytvořte instanci CLLocationManager a volání RequestWhenInUseAuthorization.

CLLocationManager locationManager = new CLLocationManager();
locationManager.RequestWhenInUseAuthorization();
//locationManager.RequestAlwaysAuthorization(); //requests permission for access to location data while running in the background

Všimněte si, že při pokusu o volání RequestWhenInUseAuthorization ve verzích iOS starších než 8.0 dojde k chybě. Před voláním nezapomeňte zkontrolovat verzi iOS, pokud máte v úmyslu podporovat verze starší než 8.

Přístup k umístění uživatele také vyžaduje úpravy souboru Info.plist. Měly by být nastaveny následující klíče týkající se údajů o poloze:

  • NSLocationWhenInUseUsageDescription – Pokud při interakci s vaší aplikací přistupujete k umístění uživatele.
  • NSLocationAlwaysUsageDescription – Pokud vaše aplikace přistupuje k umístění uživatele na pozadí.

Tyto klíče můžete přidat tak, že otevřete Soubor Info.plist a vyberete Zdroj v dolní části editoru.

Po aktualizaci souboru Info.plist a zobrazení výzvy uživateli, aby získal oprávnění pro přístup k jeho umístění, můžete zobrazit polohu uživatele na mapě nastavením ShowsUserLocation vlastnosti na hodnotu true:

map.ShowsUserLocation = true;

Upozornění na povolení přístupu k umístění

Poznámky

MKMapView podporuje také zobrazování obrázků, označovaných jako poznámky, na mapě. Můžou to být vlastní image nebo systémově definované špendlíky různých barev. Například následující snímek obrazovky ukazuje mapu s připnutím i vlastním obrázkem:

Tento snímek obrazovky ukazuje mapu s připnutím i vlastním obrázkem.

Přidání poznámky

Samotná poznámka má dvě části:

  • Objekt MKAnnotation , který obsahuje data modelu o anotaci, například název a umístění poznámky.
  • , MKAnnotationView který obsahuje obrázek, který se má zobrazit, a volitelně popisek, který se zobrazí, když uživatel klepne na poznámku.

Map Kit používá vzor delegování iOS k přidání poznámek do mapy, kde Delegate vlastnost objektu MKMapView je nastavena na instanci objektu MKMapViewDelegate. Je to implementace tohoto delegáta, která je zodpovědná za vrácení poznámky MKAnnotationView .

Pokud chcete přidat poznámku, nejprve se přidá poznámka voláním AddAnnotations instance MKMapView :

// add an annotation
map.AddAnnotations (new MKPointAnnotation (){
    Title="MyAnnotation",
    Coordinate = new CLLocationCoordinate2D (42.364260, -71.120824)
});

Když se na mapě zobrazí umístění poznámek, zavolá metoda delegátaGetViewForAnnotation, MKMapView aby se zobrazilaMKAnnotationView.

Následující kód například vrátí systém MKPinAnnotationView:

string pId = "PinAnnotation";

public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
{
    if (annotation is MKUserLocation)
        return null;

    // create pin annotation view
    MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

    if (pinView == null)
        pinView = new MKPinAnnotationView (annotation, pId);

    ((MKPinAnnotationView)pinView).PinColor = MKPinAnnotationColor.Red;
    pinView.CanShowCallout = true;

    return pinView;
}

Opakované přidávání poznámek

Chcete-li ušetřit paměť, MKMapView umožňuje, aby bylo zobrazení poznámek ve fondu pro opakované použití, podobně jako jsou buňky tabulky opakovaně používány. Získání zobrazení poznámek z fondu se provádí voláním DequeueReusableAnnotation:

MKAnnotationView pinView = (MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

Zobrazení bublinových popisků

Jak už bylo zmíněno dříve, poznámka může volitelně zobrazit bublinový popisek. Chcete-li zobrazit bublinový popisek jednoduše nastaven CanShowCallout na hodnotu true na kartě MKAnnotationView. Výsledkem je zobrazení názvu poznámky při klepnutí na poznámku, jak je znázorněno na obrázku:

Zobrazovaný název poznámek

Přizpůsobení bublinového popisku

Popisek lze také přizpůsobit tak, aby zobrazoval zobrazení levého a pravého přístupového objektu, jak je znázorněno níže:

pinView.RightCalloutAccessoryView = UIButton.FromType (UIButtonType.DetailDisclosure);
pinView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile ("monkey.png"));

Výsledkem tohoto kódu je následující bublinový popisek:

Příklad bublinového popisku

Pokud chcete pracovat s uživatelem klepnutím na správné příslušenství, jednoduše implementujte metodu CalloutAccessoryControlTapped v :MKMapViewDelegate

public override void CalloutAccessoryControlTapped (MKMapView mapView, MKAnnotationView view, UIControl control)
{
    ...
}

Překryvy

Další způsob, jak vrstvit grafiku na mapě, je použití překrytí. Překryvné vrstvy podporují grafický obsah výkresu, který se při přiblížení zvětšuje s mapou. iOS poskytuje podporu pro několik typů překryvů, mezi které patří:

  • Mnohoúhelníky – běžně se používá ke zvýraznění určité oblasti na mapě.
  • Křivky – často se zobrazuje při zobrazení trasy.
  • Kruhy – slouží ke zvýraznění kruhové oblasti mapy.

Kromě toho je možné vytvořit vlastní překrytí, aby bylo možné zobrazit libovolné geometrie s podrobným přizpůsobeným kódem výkresu. Například meteorologický radar by byl vhodným kandidátem pro vlastní překryv.

Přidání překryvného objektu

Podobně jako poznámky zahrnuje přidání překrytí 2 části:

  • Vytvoření objektu modelu pro překrytí a jeho přidání do objektu MKMapView .
  • Vytvoření zobrazení pro překryvné zobrazení v objektu MKMapViewDelegate .

Model pro překryvné vrstvy může být libovolná MKShape podtřída. Xamarin.iOS obsahuje MKShape podtřídy pro mnohoúhelníky, lomené čáry a kruhy prostřednictvím MKPolyline MKPolygontříd a MKCircle tříd.

Například následující kód se používá k přidání MKCircle:

var circleOverlay = MKCircle.Circle (mapCenter, 1000);
map.AddOverlay (circleOverlay);

Zobrazení pro překryvné zobrazení je MKOverlayView instance, která je vrácena GetViewForOverlay v objektu MKMapViewDelegate. Každá z nich MKShape má odpovídající, MKOverlayView která ví, jak zobrazit daný obrazec. Pro MKPolygon tam je MKPolygonView. Podobně odpovídá MKPolyline MKPolylineView, a pro MKCircle tam je MKCircleView.

Například následující kód vrátí MKCircleView pro:MKCircle

public override MKOverlayView GetViewForOverlay (MKMapView mapView, NSObject overlay)
{
    var circleOverlay = overlay as MKCircle;
    var circleView = new MKCircleView (circleOverlay);
    circleView.FillColor = UIColor.Blue;
    return circleView;
}

Zobrazí se kruh na mapě, jak je znázorněno:

Kruh zobrazený na mapě

iOS obsahuje rozhraní API pro místní vyhledávání se sadou Map Kit, které umožňuje asynchronní vyhledávání bodů zájmu v zadané geografické oblasti.

Pokud chcete provést místní vyhledávání, musí aplikace postupovat takto:

  1. Vytvořit MKLocalSearchRequest objekt.
  2. Vytvořte objekt MKLocalSearch z objektu MKLocalSearchRequest .
  3. Zavolejte metodu Start objektu MKLocalSearch .
  4. MKLocalSearchResponse Načtěte objekt v zpětném volání.

Samotné rozhraní API místního vyhledávání neposkytuje žádné uživatelské rozhraní. Nevyžaduje ani použití mapy. Aby se ale místní vyhledávání prakticky využilo, musí aplikace poskytnout nějaký způsob, jak zadat vyhledávací dotaz a zobrazit výsledky. Vzhledem k tomu, že výsledky budou obsahovat údaje o poloze, často dávají smysl je zobrazit na mapě.

Přidání uživatelského rozhraní místního vyhledávání

Jedním zezpůsobůch UISearchBarUISearchController

Následující kód přidá UISearchController (který má vlastnost vyhledávacího pruhu) v ViewDidLoad metodě MapViewController:

//Creates an instance of a custom View Controller that holds the results
var searchResultsController = new SearchResultsViewController (map);

//Creates a search controller updater
var searchUpdater = new SearchResultsUpdator ();
searchUpdater.UpdateSearchResults += searchResultsController.Search;

//add the search controller
searchController = new UISearchController (searchResultsController) {
                SearchResultsUpdater = searchUpdater
            };

//format the search bar
searchController.SearchBar.SizeToFit ();
searchController.SearchBar.SearchBarStyle = UISearchBarStyle.Minimal;
searchController.SearchBar.Placeholder = "Enter a search query";

//the search bar is contained in the navigation bar, so it should be visible
searchController.HidesNavigationBarDuringPresentation = false;

//Ensure the searchResultsController is presented in the current View Controller
DefinesPresentationContext = true;

//Set the search bar in the navigation bar
NavigationItem.TitleView = searchController.SearchBar;

Všimněte si, že zodpovídáte za začlenění objektu vyhledávacího panelu do uživatelského rozhraní. V tomto příkladu jsme ho přiřadili k ovládacímu prvku TitleView navigačního panelu, ale pokud ve své aplikaci nepoužíváte navigační kontroler, budete muset najít jiné místo, kde ho chcete zobrazit.

V tomto fragmentu kódu jsme vytvořili další vlastní kontroler zobrazení – searchResultsController který zobrazuje výsledky hledání a pak jsme tento objekt použili k vytvoření objektu kontroleru vyhledávání. Vytvořili jsme také nový aktualizátor vyhledávání, který se aktivuje, když uživatel pracuje s panelem hledání. Přijímá oznámení o hledáních pomocí jednotlivých klávesových úhošť a zodpovídá za aktualizaci uživatelského rozhraní. Podíváme se, jak implementovat jak tuto searchResultsController verzi, tak i searchResultsUpdater později v této příručce.

Výsledkem je panel hledání zobrazený na mapě, jak je znázorněno níže:

Panel hledání zobrazený na mapě

Zobrazení výsledků hledání

Abychom mohli zobrazit výsledky hledání, musíme vytvořit vlastní kontroler zobrazení; normálně a UITableViewController. Jak je znázorněno výše, searchResultsController předá se konstruktoru searchController při jeho vytváření. Následující kód je příkladem vytvoření tohoto vlastního kontroleru zobrazení:

public class SearchResultsViewController : UITableViewController
{
    static readonly string mapItemCellId = "mapItemCellId";
    MKMapView map;

    public List<MKMapItem> MapItems { get; set; }

    public SearchResultsViewController (MKMapView map)
    {
        this.map = map;

        MapItems = new List<MKMapItem> ();
    }

    public override nint RowsInSection (UITableView tableView, nint section)
    {
        return MapItems.Count;
    }

    public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
    {
        var cell = tableView.DequeueReusableCell (mapItemCellId);

        if (cell == null)
            cell = new UITableViewCell ();

        cell.TextLabel.Text = MapItems [indexPath.Row].Name;
        return cell;
    }

    public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
    {
        // add item to map
        CLLocationCoordinate2D coord = MapItems [indexPath.Row].Placemark.Location.Coordinate;
        map.AddAnnotations (new MKPointAnnotation () {
            Title = MapItems [indexPath.Row].Name,
            Coordinate = coord
        });

        map.SetCenterCoordinate (coord, true);

        DismissViewController (false, null);
    }

    public void Search (string forSearchString)
    {
        // create search request
        var searchRequest = new MKLocalSearchRequest ();
        searchRequest.NaturalLanguageQuery = forSearchString;
        searchRequest.Region = new MKCoordinateRegion (map.UserLocation.Coordinate, new MKCoordinateSpan (0.25, 0.25));

        // perform search
        var localSearch = new MKLocalSearch (searchRequest);

        localSearch.Start (delegate (MKLocalSearchResponse response, NSError error) {
            if (response != null && error == null) {
                this.MapItems = response.MapItems.ToList ();
                this.TableView.ReloadData ();
            } else {
                Console.WriteLine ("local search error: {0}", error);
            }
        });

    }
}

Aktualizace výsledků hledání

Jedná SearchResultsUpdater se jako mediátor mezi searchControllervyhledávacím panelem a výsledky hledání.

V tomto příkladu musíme nejprve vytvořit vyhledávací metodu v souboru SearchResultsViewController. K tomu musíme vytvořit MKLocalSearch objekt a použít ho k vydání hledání , MKLocalSearchRequestvýsledky se načtou v zpětném volání předané Start metodě objektu MKLocalSearch . Výsledky se pak vrátí v objektu MKLocalSearchResponse obsahujícím pole MKMapItem objektů:

public void Search (string forSearchString)
{
    // create search request
    var searchRequest = new MKLocalSearchRequest ();
    searchRequest.NaturalLanguageQuery = forSearchString;
    searchRequest.Region = new MKCoordinateRegion (map.UserLocation.Coordinate, new MKCoordinateSpan (0.25, 0.25));

    // perform search
    var localSearch = new MKLocalSearch (searchRequest);

    localSearch.Start (delegate (MKLocalSearchResponse response, NSError error) {
        if (response != null && error == null) {
            this.MapItems = response.MapItems.ToList ();
            this.TableView.ReloadData ();
        } else {
            Console.WriteLine ("local search error: {0}", error);
        }
    });

}

Pak v naší MapViewController vytvoříme vlastní implementaci UISearchResultsUpdating, která je přiřazena k SearchResultsUpdater vlastnosti našeho searchController v části Přidání místního vyhledávacího uživatelského rozhraní :

public class SearchResultsUpdator : UISearchResultsUpdating
{
    public event Action<string> UpdateSearchResults = delegate {};

    public override void UpdateSearchResultsForSearchController (UISearchController searchController)
    {
        this.UpdateSearchResults (searchController.SearchBar.Text);
    }
}

Výše uvedená implementace přidá do mapy poznámku, když je položka vybrána z výsledků, jak je znázorněno níže:

Poznámka přidaná do mapy při výběru položky z výsledků

Důležité

UISearchController byla implementována v iOSu 8. Pokud chcete zařízení podporovat dříve, budete muset použít UISearchDisplayController.

Shrnutí

Tento článek prozkoumal architekturu mapových sad pro iOS. Nejprve se podívala na to, jak MKMapView třída umožňuje zahrnutí interaktivních map do aplikace. Pak ukázal, jak dále přizpůsobit mapy pomocí poznámek a překryvných objektů. Nakonec prozkoumala možnosti místního vyhledávání, které byly přidány do mapové sady s iOSem 6.1, a ukázala, jak použít provádění dotazů založených na poloze pro body zájmu a přidat je do mapy.