在WindowsPhone的Here地图API上添加可交互图钉(Marker)
最近在写地图应用的时候使用了Here地图API,应设计师要求需要实现一个可交互的图钉,效果如下:
here地图API添加图钉与原来的bing地图API稍有不同,here地图没有Pushpin控件,不过可以把UIElement添加到MapOverLay中,再把MapOverLay添加到对应地图的mapLayer上。具体实现方法可以查阅官方文档:
直接用C#代码写图钉没办法实时查看效果,因此还是先用xmal尝试一下~把图钉分为三个部分实现,里面的小圆,外面的大圆,以及底部的三角,另外还有点击图钉后扩散开的三个按钮,xaml代码如下:
<Canvas Height="200" Width="200"> <Ellipse Fill="Blue" Height="50" Width="50" Canvas.Left="-25" Canvas.Top="115" Canvas.ZIndex="3" Tap="Ellipse_Tap"/> <Ellipse x:Name="marker_part1" Fill="White" Height="60" Width="60" Canvas.Left="-30" Canvas.Top="110" Canvas.ZIndex="2"/> <Polygon x:Name="marker_part2" Fill="White" Canvas.Left="-30" Canvas.Top="140"> <Polygon.Points> <PointCollection> <Point X="0" Y="0"/> <Point X="60" Y="0"/> <Point X="30" Y="60"/> </PointCollection> </Polygon.Points> </Polygon> <Canvas x:Name="btn_i" Canvas.Left="-25" Canvas.Top="115" Canvas.ZIndex="1" Opacity="0"> <Ellipse Fill="Blue" Height="50" Width="50"/> <TextBlock Text="i" Foreground="White" FontSize="35" Height="50" Width="50" TextAlignment="Center"/> <Canvas.RenderTransform> <TranslateTransform x:Name="btn_i_tran" X="0" Y="0"/> </Canvas.RenderTransform> </Canvas> <Canvas x:Name="btn_b" Canvas.Left="-25" Canvas.Top="115" Canvas.ZIndex="1" Opacity="0"> <Ellipse Fill="Blue" Height="50" Width="50"/> <TextBlock Text="B" Foreground="White" FontSize="35" Height="50" Width="50" TextAlignment="Center"/> <Canvas.RenderTransform> <TranslateTransform x:Name="btn_b_tran" X="0" Y="0"/> </Canvas.RenderTransform> </Canvas> <Canvas x:Name="btn_e" Canvas.Left="-25" Canvas.Top="115" Canvas.ZIndex="1" Opacity="0"> <Ellipse Fill="Blue" Height="50" Width="50"/> <TextBlock Text="E" Foreground="White" FontSize="35" Height="50" Width="50" TextAlignment="Center"/> <Canvas.RenderTransform> <TranslateTransform x:Name="btn_e_tran" X="0" Y="0"/> </Canvas.RenderTransform> </Canvas> </Canvas>
实现的效果如图:
然后是动画的xaml代码,通过计算就可以得到每个圆的x,y如何变化:
<Grid.Resources> <Storyboard x:Name="MarkerShow"> <DoubleAnimation Storyboard.TargetName="btn_i" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_i_tran" Storyboard.TargetProperty="Y" From="0" To="-65" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_b" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_b_tran" Storyboard.TargetProperty="X" From="0" To="-56.3" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_b_tran" Storyboard.TargetProperty="Y" From="0" To="32.5" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_e" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_e_tran" Storyboard.TargetProperty="X" From="0" To="56.3" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_e_tran" Storyboard.TargetProperty="Y" From="0" To="32.5" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="marker_part1" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="marker_part2" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/> </Storyboard> <Storyboard x:Name="MarkerHide"> <DoubleAnimation Storyboard.TargetName="btn_i" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_i_tran" Storyboard.TargetProperty="Y" From="-65" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_b" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_b_tran" Storyboard.TargetProperty="X" From="-56.3" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_b_tran" Storyboard.TargetProperty="Y" From="32.5" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_e" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_e_tran" Storyboard.TargetProperty="X" From="56.3" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="btn_e_tran" Storyboard.TargetProperty="Y" From="32.5" To="0" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="marker_part1" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5"/> <DoubleAnimation Storyboard.TargetName="marker_part2" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5"/> </Storyboard> </Grid.Resources>
最后是后台的C#代码,逻辑很简单,通过变量isBusy判断动画是否处于播放中,然后为storyBoard添加completed事件来为isBusy赋值,同时用isShowed记录状态:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using PhoneApp1.Resources; namespace PhoneApp1 { public partial class MainPage : PhoneApplicationPage { private bool isBusy = false; private bool isShowed = false; public MainPage() { InitializeComponent(); MarkerShow.Completed += MarkerShow_Completed; MarkerHide.Completed += MarkerHide_Completed; } private void Ellipse_Tap(object sender, System.Windows.Input.GestureEventArgs e) { if (isBusy) return; if (!isShowed) MarkerShow.Begin(); else MarkerHide.Begin(); isBusy = true; } void MarkerShow_Completed(object sender, EventArgs e) { isBusy = false; isShowed = true; } void MarkerHide_Completed(object sender, EventArgs e) { isBusy = false; isShowed = false; } } }
最终效果:
测试动画效果正常之后,就可以按着xaml写C#的代码了
首先实现图钉:
Canvas marker = new Canvas();
marker.Height = 200; marker.Width = 200; marker.Margin = new System.Windows.Thickness(0, 0, 0, 0); Ellipse part1 = new Ellipse(); part1.Fill = new SolidColorBrush(Colors.Blue); part1.Height = 50; part1.Width = 50; part1.SetValue(Canvas.LeftProperty, (double)-25); part1.SetValue(Canvas.TopProperty, (double)115); part1.SetValue(Canvas.ZIndexProperty, 3); part1.Tap += part1_Tap; part2 = new Ellipse(); part2.Fill = new SolidColorBrush(Colors.Black); part2.Height = 60; part2.Width = 60; part2.SetValue(Canvas.LeftProperty, (double)-30); part2.SetValue(Canvas.TopProperty, (double)110); part2.SetValue(Canvas.ZIndexProperty, 2); part3 = new Polygon(); part3.Points.Add(new Point(0, 0)); part3.Points.Add(new Point(60, 0)); part3.Points.Add(new Point(30, 60)); part3.Fill = new SolidColorBrush(Colors.Black); part3.SetValue(Canvas.LeftProperty, (double)-30); part3.SetValue(Canvas.TopProperty, (double)140);
需要注意的是Margin属性为Thickness类型,而Canvas.LeftProperty为double类型,所以需要进行转换,当然把(double)-25写成-25.0也是可以的。
然后绘制三个圆点:
btn_i = getBtn("i"); btn_i.RenderTransform = btn_i_tran; btn_b = getBtn("B"); btn_b.RenderTransform = btn_b_tran; btn_e = getBtn("E"); btn_e.RenderTransform = btn_e_tran;
getBtn函数如下,画圆的方法跟上面一样:
private Canvas getBtn(string text) { Canvas btn_temp = new Canvas(); btn_temp.SetValue(Canvas.LeftProperty, (double)-25); btn_temp.SetValue(Canvas.TopProperty, (double)115); btn_temp.SetValue(Canvas.ZIndexProperty, 1); btn_temp.Opacity = 0; Ellipse btn_temp_ell = new Ellipse(); btn_temp_ell.Fill = new SolidColorBrush(Colors.Blue); btn_temp_ell.Height = 50; btn_temp_ell.Width = 50; TextBlock btn_temp_text = new TextBlock(); btn_temp_text.Text = text; btn_temp_text.Foreground = new SolidColorBrush(Colors.White); btn_temp_text.FontSize = 35; btn_temp_text.Height = 50; btn_temp_text.Width = 50; btn_temp_text.TextAlignment = TextAlignment.Center; btn_temp.Children.Add(btn_temp_ell); btn_temp.Children.Add(btn_temp_text); switch (text) { case "i": btn_temp.Tap += btn_i_tap; break; case "B": btn_temp.Tap += btn_b_tap; break; case "E": btn_temp.Tap += btn_e_tap; break; } return btn_temp; }
接下来就是设置动画,为了减少代码冗余,先写一个设定动画的函数,步骤为设定DoubleAnimation的From,To和Duration属性,然后通过Storyboard.SetTarget和Story.setTargetProperty两个方法设置DoubleAnimation绑定的对象以及属性:
private DoubleAnimation getAn(double from, double to,DependencyObject target, string Property) { DoubleAnimation temp = new DoubleAnimation(); temp.From = from; temp.To = to; temp.Duration = new Duration(new TimeSpan(0,0,0,0,500)); Storyboard.SetTarget(temp,target); Storyboard.SetTargetProperty(temp,new PropertyPath(Property)); return temp; }
初始化Storyboard,并添加动画:
Storyboard markerShow = new Storyboard(); markerShow.Completed += markerShow_Completed; markerShow.Children.Add(getAn(0, 1, btn_i, "Opacity")); markerShow.Children.Add(getAn(0, -65, btn_i_tran, "Y")); markerShow.Children.Add(getAn(0, 1, btn_b, "Opacity")); markerShow.Children.Add(getAn(0, -56.3, btn_b_tran, "X")); markerShow.Children.Add(getAn(0, 32.5, btn_b_tran, "Y")); markerShow.Children.Add(getAn(0, 1, btn_e, "Opacity")); markerShow.Children.Add(getAn(0, 56.3, btn_e_tran, "X")); markerShow.Children.Add(getAn(0, 32.5, btn_e_tran, "Y")); markerShow.Children.Add(getAn(1, 0, part2, "Opacity")); markerShow.Children.Add(getAn(1, 0, part3, "Opacity")); Storyboard markerHide = new Storyboard(); markerHide.Completed += markerHide_Completed; markerHide.Children.Add(getAn(1, 0, btn_i, "Opacity")); markerHide.Children.Add(getAn(-65, 0, btn_i_tran, "Y")); markerHide.Children.Add(getAn(1, 0, btn_b, "Opacity")); markerHide.Children.Add(getAn(-56.3, 0, btn_b_tran, "X")); markerHide.Children.Add(getAn(32.5, 0, btn_b_tran, "Y")); markerHide.Children.Add(getAn(1, 0, btn_e, "Opacity")); markerHide.Children.Add(getAn(56.3, 0, btn_e_tran, "X")); markerHide.Children.Add(getAn(32.5, 0, btn_e_tran, "Y")); markerHide.Children.Add(getAn(0, 1, part2, "Opacity")); markerHide.Children.Add(getAn(0, 1, part3, "Opacity"));
不要忘记把Storyboard添加到控件的resource,此处添加到对应的canvas.resource中:
marker.Resources.Add("storyboard1", markerShow); marker.Resources.Add("storyboard2", markerHide);
按钮点击的逻辑与前面写到的一样,就不再贴出来了。
要在地图上添加自定义的图钉,只需按着官方文档添加,即把canvas添加到MapOverLay中。
最后附上代码,依次是前面xaml的工程文件和后用用c#写的一个MapMarker类(工程太大,所以只发一个类)






浙公网安备 33010602011771号