다음을 통해 공유


Xamarin.iOS의 지도

지도 모든 최신 모바일 운영 체제에서 일반적인 기능입니다. iOS는 Map Kit 프레임워크를 통해 기본적으로 매핑 지원을 제공합니다. 맵 키트를 사용하면 애플리케이션에서 풍부한 대화형 맵을 쉽게 추가할 수 있습니다. 이러한 맵은 지도의 위치를 표시하는 주석을 추가하고 임의 셰이프의 그래픽을 오버레이하는 등 다양한 방법으로 사용자 지정할 수 있습니다. 지도 키트는 디바이스의 현재 위치를 표시하기 위한 기본 제공 지원도 제공합니다.

지도 추가

아래와 같이 뷰 계층 구조에 인스턴스를 MKMapView 추가하여 애플리케이션에 맵을 추가합니다.

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

MKMapView 는 지도를 UIView 표시하는 하위 클래스입니다. 위의 코드를 사용하여 맵을 추가하면 대화형 맵이 생성됩니다.

샘플 맵

지도 스타일

MKMapView 는 3가지 스타일의 지도를 지원합니다. 지도 스타일을 적용하려면 열거형의 MKMapType 값으로 속성을 설정 MapType 하기만 하면됩니다.

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

다음 스크린샷은 사용할 수 있는 다양한 맵 스타일을 보여 줍니다.

이 스크린샷은 사용 가능한 다양한 지도 스타일을 보여 줍니다.

이동 및 확대/축소

MKMapView 에는 다음과 같은 지도 대화형 기능 지원이 포함되어 있습니다.

  • 손가락 모으기 제스처를 통해 확대/축소
  • 이동 제스처를 통한 이동

이러한 기능은 인스턴스의 MKMapView 속성과 속성을 설정 ZoomEnabled 하기만 하면 사용하거나 사용하지 않도록 설정할 수 있습니다ScrollEnabled. 여기서 기본값은 둘 다에 대해 true입니다. 예를 들어 정적 맵을 표시하려면 적절한 속성을 false로 설정하기만 하면됩니다.

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

사용자 위치

사용자 상호 작용 MKMapView 외에도 디바이스의 위치를 표시하기 위한 기본 제공 지원도 있습니다. Core Location 프레임워크를 사용하여 이 작업을 수행합니다. 사용자의 위치에 액세스하려면 먼저 사용자에게 메시지를 표시해야 합니다. 이렇게 하려면 인스턴스 CLLocationManager 를 만들고 호출 RequestWhenInUseAuthorization합니다.

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

8.0 이전의 iOS 버전에서 호출 RequestWhenInUseAuthorization 을 시도하면 오류가 발생합니다. 8 이전 버전을 지원하려는 경우 호출하기 전에 iOS 버전을 검사 합니다.

사용자의 위치에 액세스하려면 Info.plist를 수정해야 합니다. 위치 데이터와 관련된 다음 키를 설정해야 합니다.

  • NSLocationWhenInUseUsageDescription - 사용자가 앱과 상호 작용하는 동안 사용자의 위치에 액세스하는 경우
  • NSLocationAlwaysUsageDescription - 앱이 백그라운드에서 사용자의 위치에 액세스하는 경우

Info.plist를 열고 편집기 아래쪽에서 원본선택하여 해당 키를 추가할 수 있습니다.

Info.plist를 업데이트하고 사용자에게 해당 위치에 액세스할 수 있는 권한을 묻는 메시지가 표시되면 속성을 true로 설정 ShowsUserLocation 하여 지도에 사용자의 위치를 표시할 수 있습니다.

map.ShowsUserLocation = true;

위치 액세스 허용 경고

주석

MKMapView 에서는 주석이라고 하는 이미지를 지도에 표시할 수도 있습니다. 사용자 지정 이미지 또는 다양한 색의 시스템 정의 핀일 수 있습니다. 예를 들어 다음 스크린샷은 핀과 사용자 지정 이미지가 모두 있는 맵을 보여줍니다.

이 스크린샷은 핀과 사용자 지정 이미지가 모두 있는 맵을 보여줍니다.

주석 추가

주석 자체에는 다음 두 부분이 있습니다.

  • 주석의 MKAnnotation 제목 및 위치와 같은 주석에 대한 모델 데이터를 포함하는 개체입니다.
  • MKAnnotationView 표시할 이미지를 포함하고 필요에 따라 사용자가 주석을 탭할 때 표시되는 설명선입니다.

지도 키트는 iOS 위임 패턴을 사용하여 지도에 주석을 추가합니다. 여기서 Delegate 속성 MKMapView 은 인스턴스 MKMapViewDelegate로 설정됩니다. 주석을 반환하는 MKAnnotationView 것은 이 대리자의 구현입니다.

주석을 추가하려면 먼저 인스턴스를 호출 AddAnnotations 하여 주석을 MKMapView 추가합니다.

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

주석의 위치가 지도에 MKMapView 표시되면 해당 대리자의 GetViewForAnnotation 메서드를 호출하여 MKAnnotationView 표시를 가져옵니다.

예를 들어 다음 코드는 시스템 제공을 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;
}

주석 다시 사용

메모리 MKMapView 를 절약하려면 표 셀을 다시 사용하는 방식과 유사하게 주석 뷰를 다시 사용할 수 있도록 풀화할 수 있습니다. 풀에서 주석 보기를 가져오는 작업은 다음을 호출하여 DequeueReusableAnnotation수행됩니다.

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

설명선 표시

앞에서 멘션 주석은 필요에 따라 설명선이 표시될 수 있습니다. 설명선 표시를 표시하려면 해당 설명선에서 true로 설정 CanShowCallout 하기 MKAnnotationView만 하면됩니다. 그러면 주석을 탭할 때 주석의 제목이 다음과 같이 표시됩니다.

표시할 주석 제목

설명선 사용자 지정

설명선은 아래와 같이 왼쪽 및 오른쪽 액세서리 보기를 표시하도록 사용자 지정할 수도 있습니다.

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

이 코드는 다음과 같은 설명선이 생성됩니다.

설명선 예제

오른쪽 액세서리를 탭하는 사용자를 처리하려면 다음에서 MKMapViewDelegate메서드를 CalloutAccessoryControlTapped 구현하기만 하면됩니다.

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

오버레이

맵에서 그래픽을 계층화하는 또 다른 방법은 오버레이를 사용하는 것입니다. 오버레이는 확대/축소하는 대로 맵을 크기 조정하는 그래픽 그리기 콘텐츠를 지원합니다. iOS는 다음을 비롯한 여러 유형의 오버레이를 지원합니다.

  • 다각형 - 일반적으로 맵의 일부 영역을 강조 표시하는 데 사용됩니다.
  • 폴리라인 - 경로를 표시할 때 자주 표시됩니다.
  • 원 - 지도의 원형 영역을 강조 표시하는 데 사용됩니다.

또한 사용자 지정 오버레이를 만들어 세분화된 사용자 지정 그리기 코드를 사용하여 임의의 기하 도형을 표시할 수 있습니다. 예를 들어 날씨 레이더는 사용자 지정 오버레이에 적합한 후보입니다.

오버레이 추가

주석과 마찬가지로 오버레이를 추가하려면 다음 두 부분이 포함됩니다.

  • 오버레이에 대한 모델 개체를 만들고 에 추가 MKMapView 합니다.
  • 에 오버레이 MKMapViewDelegate 에 대한 뷰 만들기

오버레이 모델은 모든 MKShape 서브클래스일 수 있습니다. Xamarin.iOS에는 각각 다각형, 다각형 및 원을 통한 서브클래스 및 MKCircle 클래스가 MKPolylineMKPolygon포함 MKShape 됩니다.

예를 들어 다음 코드를 사용하여 다음을 추가합니다.MKCircle

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

오버레이에 대한 뷰는 MKOverlayView 에 있는 인스턴스에서 MKMapViewDelegate반환 GetViewForOverlay 되는 인스턴스입니다. 각 MKShape 셰이프에는 지정된 셰이프를 표시하는 방법을 알고 있는 해당 MKOverlayView 셰이프가 있습니다. 가 MKPolygon 있습니다 MKPolygonView. 마찬가지로, MKPolyline 에 해당 MKPolylineView하고 MKCircle 있습니다 MKCircleView.

예를 들어 다음 코드는 다음에 대한 값을 MKCircleView 반환합니다.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;
}

다음과 같이 지도에 원을 표시합니다.

지도에 표시되는 원

iOS에는 맵 키트가 있는 로컬 검색 API가 포함되어 있어 지정된 지역에서 관심 지점을 비동기 검색할 수 있습니다.

로컬 검색을 수행하려면 애플리케이션이 다음 단계를 수행해야 합니다.

  1. 개체를 만듭니다 MKLocalSearchRequest .
  2. 에서 MKLocalSearch 개체를 만듭니다 MKLocalSearchRequest .
  3. 개체에서 Start 메서드를 호출합니다 MKLocalSearch .
  4. 콜백에서 MKLocalSearchResponse 개체를 검색합니다.

로컬 검색 API 자체는 사용자 인터페이스를 제공하지 않습니다. 맵을 사용할 필요도 없습니다. 그러나 로컬 검색을 실질적으로 사용하려면 애플리케이션에서 검색 쿼리를 지정하고 결과를 표시하는 방법을 제공해야 합니다. 또한 결과에 위치 데이터가 포함되므로 지도에 표시하는 것이 좋습니다.

로컬 검색 UI 추가

검색 입력 UISearchBar을 수락하는 한 가지 방법은 a에서 제공하며 UISearchController 테이블에 결과를 표시하는 것입니다.

다음 코드는 다음 메서드MapViewControllerUISearchController 검색 표시줄 속성이 ViewDidLoad 있는 값을 추가합니다.

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

검색 창 개체를 사용자 인터페이스에 통합해야 합니다. 이 예제에서는 탐색 모음의 TitleView에 할당했지만 애플리케이션에서 탐색 컨트롤러를 사용하지 않는 경우 표시할 다른 위치를 찾아야 합니다.

이 코드 조각에서는 검색 결과를 표시하는 다른 사용자 지정 뷰 컨트롤러 searchResultsController 를 만든 다음 이 개체를 사용하여 검색 컨트롤러 개체를 만들었습니다. 또한 사용자가 검색 창과 상호 작용할 때 활성화되는 새 검색 업데이트 관리자를 만들었습니다. 각 키 입력을 사용하여 검색에 대한 알림을 수신하고 UI 업데이트를 담당합니다. 이 가이드의 뒷부분에서 구현 searchResultsControllersearchResultsUpdater 하는 방법을 살펴보겠습니다.

그러면 아래와 같이 맵 위에 검색 창이 표시됩니다.

지도 위에 표시되는 검색 창

검색 결과 표시

검색 결과를 표시하려면 사용자 지정 뷰 컨트롤러를 만들어야 합니다. 일반적으로는 .입니다 UITableViewController. 위 searchResultsController 와 같이 생성될 때 생성자에 searchController 전달됩니다. 다음 코드는 이 사용자 지정 뷰 컨트롤러를 만드는 방법의 예입니다.

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

    }
}

검색 결과 업데이트

검색 SearchResultsUpdater 창과 검색 결과 사이의 searchController중재자 역할을합니다.

이 예제에서는 먼저 .에서 SearchResultsViewController검색 메서드를 만들어야 합니다. 이렇게 하려면 개체를 MKLocalSearch 만들고 이를 사용하여 검색MKLocalSearchRequest을 실행해야 합니다. 결과는 개체의 MKLocalSearch 메서드에 전달된 Start 콜백에서 검색됩니다. 그런 다음, 개체 배열 MKMapItemMKLocalSearchResponse 포함된 개체에서 결과가 반환됩니다.

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

}

그런 다음 로컬 MapViewController 검색 UI 추가 섹션에서 속성에 SearchResultsUpdatersearchController할당되는 사용자 지정 구현UISearchResultsUpdating을 만듭니다.

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

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

위의 구현은 아래와 같이 결과에서 항목을 선택할 때 맵에 주석을 추가합니다.

결과에서 항목을 선택할 때 맵에 추가된 주석

Important

UISearchController 는 iOS 8에서 구현되었습니다. 이보다 일찍 디바이스를 지원하려는 경우 .UISearchDisplayController

요약

이 문서에서는 iOS용 MapKit 프레임워크를 검토했습니다. 먼저 클래스에서 대화형 맵을 MKMapView 애플리케이션에 포함할 수 있는 방법을 살펴보았습니다. 그런 다음 주석 및 오버레이를 사용하여 맵을 추가로 사용자 지정하는 방법을 보여 줍니다. 마지막으로 iOS 6.1을 사용하여 지도 키트에 추가된 로컬 검색 기능을 검사하여 관심 지점에 대한 위치 기반 쿼리를 수행하고 지도에 추가하는 방법을 보여 줍니다.