在WindowsPhone的Here地图API上添加可交互图钉(Marker)

    最近在写地图应用的时候使用了Here地图API,应设计师要求需要实现一个可交互的图钉,效果如下:

                                            50`%~~U9L``{AF8VZP74TJV

    here地图API添加图钉与原来的bing地图API稍有不同,here地图没有Pushpin控件,不过可以把UIElement添加到MapOverLay中,再把MapOverLay添加到对应地图的mapLayer上。具体实现方法可以查阅官方文档:

http://developer.nokia.com/resources/library/Lumia/change-history/archived-content/maps-and-navigation/guide-to-the-wp8-maps-api.html#toc_Addinggraphicstoamapcontrol

直接用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>

实现的效果如图:

temp

然后是动画的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;
        }
    }
}

最终效果:

image   image   image

测试动画效果正常之后,就可以按着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类(工程太大,所以只发一个类)

https://files.cnblogs.com/ACzero/PhoneApp1.rar

https://files.cnblogs.com/ACzero/MapMarker.rar

posted @ 2014-07-24 09:47  凝结的云海  阅读(339)  评论(0)    收藏  举报