地圖功能
建立標籤式的樣板式頁面方案
-
-
-
-
-
-
-
-
原生專案的 Maps 初始化
Android 的 Maps 初始化
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
global::Xamarin.FormsMaps.Init(this, bundle);
LoadApplication(new App());
}
iOS 的 Maps 初始化
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
Xamarin.FormsMaps.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
複製所需要用到的圖片資源
Android 平台
iOS 平台
開始進行 核心PCL 頁面設計
App.xaml.cs
App.xaml.cs
public App()
{
InitializeComponent();
//MainPage = new XFMap.MainPage();
var tabs = new TabbedPage();
// demonstrates the map control with zooming and map-types
tabs.Children.Add(new MapPage { Title = "地圖縮放", Icon = "glyphish_74_location.png" });
// demonstrates the map control with zooming and map-types
tabs.Children.Add(new PinPage { Title = "位置標示", Icon = "glyphish_07_map_marker.png" });
// demonstrates the Geocoder class
tabs.Children.Add(new GeocoderPage { Title = "定位反查", Icon = "glyphish_13_target.png" });
// opens the platform's native Map app
tabs.Children.Add(new MapAppPage { Title = "外部地圖", Icon = "glyphish_103_map.png" });
MainPage = tabs;
}
MapPage.cs
-
-
-
-
-
MapPage.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace XFMap
{
public class MapPage : ContentPage
{
Map map;
public MapPage()
{
map = new Map
{
//IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
// You can use MapSpan.FromCenterAndRadius
//map.MoveToRegion (MapSpan.FromCenterAndRadius (new Position (37, -122), Distance.FromMiles (0.3)));
// or create a new MapSpan object directly
//map.MoveToRegion(new MapSpan(new Position(25.0436439, 121.525664), 0.01, 0.01));
map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(25.0436439, 121.525664), Distance.FromMeters(500)));
// add the slider
var slider = new Slider(1, 18, 1);
slider.ValueChanged += (sender, e) => {
var zoomLevel = e.NewValue; // between 1 and 18
var latlongdegrees = 360 / (Math.Pow(2, zoomLevel));
Debug.WriteLine(zoomLevel + " -> " + latlongdegrees);
if (map.VisibleRegion != null)
map.MoveToRegion(new MapSpan(map.VisibleRegion.Center, latlongdegrees, latlongdegrees));
};
// create map style buttons
var street = new Button { Text = "街道" };
var hybrid = new Button { Text = "混合" };
var satellite = new Button { Text = "衛星" };
street.Clicked += HandleClicked;
hybrid.Clicked += HandleClicked;
satellite.Clicked += HandleClicked;
var segments = new StackLayout
{
Spacing = 30,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Orientation = StackOrientation.Horizontal,
Children = { street, hybrid, satellite }
};
// put the page together
var stack = new StackLayout { Spacing = 0 };
stack.Children.Add(map);
stack.Children.Add(slider);
stack.Children.Add(segments);
Content = stack;
// for debugging output only
map.PropertyChanged += (sender, e) => {
Debug.WriteLine(e.PropertyName + " just changed!");
if (e.PropertyName == "VisibleRegion" && map.VisibleRegion != null)
CalculateBoundingCoordinates(map.VisibleRegion);
};
}
void HandleClicked(object sender, EventArgs e)
{
var b = sender as Button;
switch (b.Text)
{
case "街道":
map.MapType = MapType.Street;
break;
case "混合":
map.MapType = MapType.Hybrid;
break;
case "衛星":
map.MapType = MapType.Satellite;
break;
}
}
/// <summary>
/// In response to this forum question http://forums.xamarin.com/discussion/22493/maps-visibleregion-bounds
/// Useful if you need to send the bounds to a web service or otherwise calculate what
/// pins might need to be drawn inside the currently visible viewport.
/// </summary>
static void CalculateBoundingCoordinates(MapSpan region)
{
// WARNING: I haven't tested the correctness of this exhaustively!
var center = region.Center;
var halfheightDegrees = region.LatitudeDegrees / 2;
var halfwidthDegrees = region.LongitudeDegrees / 2;
var left = center.Longitude - halfwidthDegrees;
var right = center.Longitude + halfwidthDegrees;
var top = center.Latitude + halfheightDegrees;
var bottom = center.Latitude - halfheightDegrees;
// Adjust for Internation Date Line (+/- 180 degrees longitude)
if (left < -180) left = 180 + (180 + left);
if (right > 180) right = (right - 180) - 180;
// I don't wrap around north or south; I don't think the map control allows this anyway
Debug.WriteLine("Bounding box:");
Debug.WriteLine(" " + top);
Debug.WriteLine(" " + left + " " + right);
Debug.WriteLine(" " + bottom);
}
}
}
PinPage.cs
-
-
-
PinPage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace XFMap
{
public class PinPage : ContentPage
{
Map map;
public PinPage()
{
map = new Map
{
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
map.MoveToRegion(MapSpan.FromCenterAndRadius(
new Position(36.9628066, -122.0194722), Distance.FromMiles(3))); // Santa Cruz golf course
var position = new Position(36.9628066, -122.0194722); // Latitude, Longitude
var pin = new Pin
{
Type = PinType.Place,
Position = position,
Label = "Santa Cruz",
Address = "custom detail info"
};
map.Pins.Add(pin);
// create buttons
var morePins = new Button { Text = "加入更多 位置標示" };
morePins.Clicked += (sender, e) => {
map.Pins.Add(new Pin
{
Position = new Position(36.9641949, -122.0177232),
Label = "Boardwalk"
});
map.Pins.Add(new Pin
{
Position = new Position(36.9571571, -122.0173544),
Label = "Wharf"
});
map.MoveToRegion(MapSpan.FromCenterAndRadius(
new Position(36.9628066, -122.0194722), Distance.FromMiles(1.5)));
};
var reLocate = new Button { Text = "重新定位" };
reLocate.Clicked += (sender, e) => {
map.MoveToRegion(MapSpan.FromCenterAndRadius(
new Position(36.9628066, -122.0194722), Distance.FromMiles(3)));
};
var buttons = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children = {
morePins, reLocate
}
};
// put the page together
Content = new StackLayout
{
Spacing = 0,
Children = {
map,
buttons
}
};
}
}
}
GeocoderPage.cs
-
-
-
GeocoderPage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace XFMap
{
public class GeocoderPage : ContentPage
{
Geocoder geoCoder;
Label l = new Label();
public GeocoderPage()
{
geoCoder = new Geocoder();
var b1 = new Button { Text = "Reverse geocode '37.808, -122.432'" };
b1.Clicked += async (sender, e) => {
var fortMasonPosition = new Position(37.8044866, -122.4324132);
var possibleAddresses = await geoCoder.GetAddressesForPositionAsync(fortMasonPosition);
foreach (var a in possibleAddresses)
{
l.Text += a + "\n";
}
};
var b2 = new Button { Text = "Geocode '394 Pacific Ave'" };
b2.Clicked += async (sender, e) => {
var xamarinAddress = "394 Pacific Ave, San Francisco, California";
var approximateLocation = await geoCoder.GetPositionsForAddressAsync(xamarinAddress);
foreach (var p in approximateLocation)
{
l.Text += p.Latitude + ", " + p.Longitude + "\n";
}
};
Content = new StackLayout
{
Padding = new Thickness(0, 20, 0, 0),
Children = {
b2,
b1,
l
}
};
}
}
}
MapAppPage.cs
-
-
-
-
MapAppPage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using Xamarin.Forms;
namespace XFMap
{
public class MapAppPage : ContentPage
{
// WARNING: when adding latitude/longitude values be careful of localization.
// European (and other countries) use a comma as the separator, which will break the request
public MapAppPage()
{
var l = new Label
{
Text = "底下兩個按鈕按下之後,將會離開當前的應用程式,並且打開原生系統內建的地圖應用程式"
};
var openLocation = new Button
{
Text = "使用原生系統內建地圖程式,顯示指定座標"
};
openLocation.Clicked += (sender, e) => {
if (Device.OS == TargetPlatform.iOS)
{
//https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
Device.OpenUri(new Uri("http://maps.apple.com/?q=394+Pacific+Ave+San+Francisco+CA"));
}
else if (Device.OS == TargetPlatform.Android)
{
// opens the Maps app directly
Device.OpenUri(new Uri("geo:0,0?q=394+Pacific+Ave+San+Francisco+CA"));
}
else if (Device.OS == TargetPlatform.Windows)
{
Device.OpenUri(new Uri("bingmaps:?where=394 Pacific Ave San Francisco CA"));
}
};
var openDirections = new Button
{
Text = "使用原生系統內建地圖程式,提供導航資訊"
};
openDirections.Clicked += (sender, e) => {
if (Device.OS == TargetPlatform.iOS)
{
//https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
Device.OpenUri(new Uri("http://maps.apple.com/?daddr=San+Francisco,+CA&saddr=cupertino"));
}
else if (Device.OS == TargetPlatform.Android)
{
// opens the 'task chooser' so the user can pick Maps, Chrome or other mapping app
Device.OpenUri(new Uri("http://maps.google.com/?daddr=San+Francisco,+CA&saddr=Mountain+View"));
}
else if (Device.OS == TargetPlatform.Windows)
{
Device.OpenUri(new Uri("bingmaps:?rtp=adr.394 Pacific Ave San Francisco CA~adr.One Microsoft Way Redmond WA 98052"));
}
};
Content = new StackLayout
{
Padding = new Thickness(5, 20, 5, 0),
HorizontalOptions = LayoutOptions.Fill,
Children = {
l,
openLocation,
openDirections
}
};
}
}
}
執行結果
Android 執行結果
取得簽署檔案 SHA1 指紋
別名名稱: androiddebugkey
建立日期: 2016/5/5
項目類型: PrivateKeyEntry
憑證鏈長度: 1
憑證 [1]:
擁有者: CN=Android Debug, O=Android, C=US
發出者: CN=Android Debug, O=Android, C=US
序號: 257c88bf
有效期自: Thu May 05 02:33:12 CST 2016 到: Sat Apr 28 02:33:12 CST 2046
憑證指紋:
MD5: 7A:AB:DC:5C:FF:6B:2C:6A:6C:8A:70:3A:EF:D8:97:22
SHA1: 3C:D6:80:32:35:70:72:58:43:74:81:E6:F4:AB:C3:5E:65:55:DD:85
SHA256: 92:5D:17:FF:FF:47:F1:03:55:0B:D3:AC:0A:01:00:0A:77:E9:84:F1:1A:9B:6F:51:52:1C:8A:3F:B7:04:D1:2F
簽章演算法名稱: SHA256withRSA
版本: 3
擴充套件:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A7 65 E1 07 00 D0 51 1F B4 FE 68 FF 7E 3A A5 30 .e....Q...h..:.0
0010: 4E 85 F6 4D N..M
]
]
申請 Google Maps Android API
-
-
-
-
-
-
-
-
新增應用程式可以使用的能力
-
-
- AccessCoarseLocation
- AccessFineLocation
- AccessLocationExtraCommands
- AccessMockLocation
- AccessNetworkState
- AccessWifiState
- Internet
修正 XFMap.Droid 專案,加入 API 金鑰
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.miniasp.xfmap" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="$safeprojectname$">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBdQkIzAPJdPDCwXEnDUbayTE571-sW-sw" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
</application>
</manifest>
設定應用程式的套件名稱
實際執行畫面
佈署注意事項
iOS 執行結果
佈署注意事項
參考
java.lang.OutOfMemoryError
, 可是,整個專案都檢查過了,沒有任何問題,此時,請參考這篇文章,進行問題修復。