Compartir a través de


Este artículo proviene de un motor de traducción automática.

Windows Phone

Escribir una aplicación de brújula para Windows Phone

Donn Morse

Descargar el ejemplo de código

Como un writerresponsible para la documentación de la plataforma de sensor para Windows 8, quiero ver como muchos desarrolladores posible adoptan nuestra nueva plataforma.Y, porque Metro-estilo apps pueden escribirse utilizando XAML y C#, el desarrollador de Windows Phone es un candidato ideal para esta migración.Los desarrolladores de Windows Phone ya tienen Car­rience con XAML y un número también tienen experiencia con sensores (porque el acelerómetro, brújula, giróscopo y sensores GPS están expuestos en la versión más reciente de Windows Phone).

Para ayudarme a entender mejor los desarrolladores Windows Phone y su plataforma de desarrollo, decidí escribir una simple app brújula el otoño pasado.Una vez que lo escribí, he presentado una versión libre en el mercado de Windows Phone utilizar el concentrador de App.Desde la aceptación, la app ha sido descargado por los usuarios de Windows Phone desde lugares tan lejanos como Suiza y Malasia.

Este artículo cubre el desarrollo de la aplicación.

La aplicación de la brújula

La aplicación brújula utiliza la brújula, o magnetómetro, integrado en el dispositivo de Windows Phone.Esta aplicación proporciona una partida con respecto al norte verdadero, así como una partida de recíproca que puede ser útil cuando se navega en un barco o una orientación en un área remota con un mapa.Además, la aplicación permite al usuario alternar de una dirección numérica (por ejemplo, "090" grados) a una partida de alfa (por ejemplo, "E" para Oriente).La aplicación también permite al usuario bloquear la partida actual.Esto es útil cuando los usuarios necesitan el puntero a permanecer inmóvil para que pueden tomar un rodamiento en un punto específico de referencia o punto de referencia en un mapa o una carta.

Figura 1 muestra la aplicación que se ejecuta en un enfoque de Samsung.La imagen de la izquierda muestra una visualización numérica del rumbo y la imagen de la derecha muestra una partida de alfa.

The Running App, Showing a Numeric Heading (Left) and an Alpha Heading (Right)Figura 1 el funcionamiento App, mostrando un numérico partida (izquierda) y un alfa partida (derecha)

Diseñar la interfaz de usuario

Como desarrollador acostumbrado a escribir aplicaciones para PC, inicialmente sentí limitado por la inmobiliaria de pantalla reducida en el teléfono.Sin embargo, esta no fue la más severa.Sólo necesitaba dar un poco más de pensamiento — y una cuidadosa consideración — a las características de mi app con respecto a las nuevas dimensiones de la pantalla.Mi aplicación brújula tiene dos pantallas: una pantalla de calibración y la pantalla de navegación principal.

La pantalla de calibración la brújula, o magnetómetro, instalado en un dispositivo de Windows Phone requiere calibración después de que el dispositivo esté encendido.Además, estos sensores pueden requerir calibración periódica.Para ayudarle a detectar mediante programación cuando la calibración es necesaria, la plataforma admite una propiedad HeadingAccuracy que se puede utilizar para detectar la calibración actual.Además, la plataforma admite un evento de calibrar que se desencadena si la brújula requiere calibración.

Mi aplicación controla el evento de calibrar, que, a su vez, muestra una pantalla de calibración (calibrationStackPanel) que solicita al usuario que calibrar manualmente el dispositivo mediante el barrido el teléfono con un movimiento de la figura 8.Como el usuario barre el teléfono, la precisión actual se muestra en la CalibrationTextBlock con una fuente de color rojo hasta que se logre la precisión deseada, como se muestra en figura 2.Una vez que la precisión devuelta es menor o igual a 10 °, los valores numéricos se borran y aparece un verde "Complete!".

The Calibration ScreenFigura 2 la pantalla de calibración

El código correspondiente que soporta calibración se encuentra en el módulo MainPage.xaml.cs en la compass_Current­controlador de evento ValueChanged, como se muestra en la figura 3.

Figura 3 calibrar la brújula

...
else
{
 if (HeadingAccuracy <= 10)
 {
  CalibrationTextBlock.Foreground = 
    new SolidColorBrush(Colors.Green);
  CalibrationTextBlock.Text = "Complete!";
 }
 else
 {
  CalibrationTextBlock.Foreground = 
    new SolidColorBrush(Colors.Red);
  CalibrationTextBlock.Text = 
    HeadingAccuracy.ToString("0.0");
 }
}

Una vez lograda la precisión deseada, el usuario se pedirá que pulse el botón listo, que oculta la pantalla de calibración y muestra la pantalla principal de la aplicación.

La pantalla principal esta pantalla muestra un valor recíproco y título numérico o alfa. Además, representa el rostro de una brújula que ha orientado con respecto al norte verdadero. Finalmente, la pantalla principal muestra los cuatro controles (o botones) que permite al usuario modificar la salida como así como bloqueo el valor de partida y la cara de la brújula.

Figura 4 muestra la pantalla principal de mi aplicación, MainPage.xaml, tal y como aparece en Visual Studio.

The App’s Primary Screen in Visual Studio
Figura 4 la App de la principal pantalla en Visual Studio

La mayoría de los elementos de la interfaz de usuario en la pantalla principal son simples controles TextBlock y botón. Los bloques de texto identifican la partida y su valor recíproco. Los botones, permiten al usuario controlar la salida. Sin embargo, la brújula cara es un poco más complicada.

La cara de brújula la cara brújula consta de tres componentes: una imagen de fondo, una imagen de primer plano y una elipse mayor, limítrofe en que rotar las imágenes de fondo y primer plano. La imagen de fondo contiene las letras correspondientes a los cuatro puntos sobre una brújula, una línea horizontal y una línea vertical. La imagen en primer plano crea el efecto de vidrio ahumado.

La imagen de fondo en el XAML, la imagen de fondo es llamada CompassFace (este nombre de la variable se hace referencia más adelante en el código que gira la cara de la brújula):

<Image Height="263" HorizontalAlignment="Left" Margin="91,266,0,0"
  Name="CompassFace" VerticalAlignment="Top" Width="263"  
  Source="/Compass71;component/compass.png" Stretch="None" />

La imagen en primer plano el primer plano de la cara de brújula, EllipseGlass, se define en el código XAML sí. El efecto de vidrio ahumado se crea utilizando un pincel de degradado lineal. He creado esta elipse utilizando Microsoft Expression Blend 4. La herramienta Expression Blend es compatible con Visual Studio y le permite cargar XAML la aplicación y mejorar la interfaz de usuario mediante la personalización de los gráficos. Figura 5 muestra la Expression Blend editor como parecía al crear la elipse sombreada.

Creating a Shaded Ellipse in Expression Blend
Figura 5 crear una elipse sombreada en Expression Blend

Después de terminar la edición de la elipse en Expression Blend, se actualizó el XAML en mi proyecto de Visual Studio con el siguiente código XML:

<Ellipse Height="263"  Width="263" x:Name="EllipseGlass" 
  Margin="91,266,102,239" Stroke="Black" StrokeThickness="1">
  <Ellipse.Fill>
    <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
    <GradientStop Color="#A5000000" Offset="0" />
    <GradientStop Color="#BFFFFFFF" Offset="1" />
    </LinearGradientBrush>
  </Ellipse.Fill>

Tenga en cuenta que las dimensiones de EllipseGlass (263 x 263 píxeles) son una copia exacta de las dimensiones de compass.png. También tenga en cuenta que el nombre del objeto, EllipseGlass, se hace referencia más adelante en el código que realiza la rotación de la cara de la brújula.

La frontera de la cara de brújula la cara de la brújula gira dentro de una elipse mayor, blanca con un borde rojo. Esta elipse es definida en el código XAML y el nombre de EllipseBorder:

<Ellipse Height="385" HorizontalAlignment="Left" Margin="31,0,0,176"
  Name="EllipseBorder" Stroke="#FFF80D0D" StrokeThickness="2"
  VerticalAlignment="Bottom" Width="385" Fill="White" />

El código detrás de la interfaz de usuario

El código se encuentra en el archivo MainPage.xaml.cs en la descarga de código que lo acompaña, y accede a los espacios de nombres necesarios para la aplicación, inicializa el sensor, establece un intervalo de informes y maneja las distintas características de aplicación: calibración, girar la brújula cara, alternar entre numérico y alfa salida y así sucesivamente.

Acceso a la brújula de su código es el primer paso para escribir una aplicación de brújula (o cualquier aplicación que accede a uno de los sensores del teléfono) para obtener acceso a los objetos de sensor expuestos por el espacio de nombres Microsoft.Devices.Sensors. Esto se logra con la siguiente directiva using en MainPage.xaml.cs:

using Microsoft.Devices.Sensors;

Una vez esta utilizando Directiva aparece en el archivo, puedo crear una variable de brújula que me da acceso programático en el dispositivo real en el teléfono:

namespace Compass71
{
  public partial class MainPage : PhoneApplicationPage
  {
    Compass compass = new Compass();

Usaré esta variable para iniciar la brújula, detenerla, recuperar la precisión de partida actual, establecer el intervalo de informe y así sucesivamente.

Comenzando la brújula y ajuste de la frecuencia de informe una vez que se crea la variable brújula, puedo comenzar invocar métodos y establecer las propiedades del objeto. El primer método que invoca es el método de inicio, que me permite comenzar recibiendo datos del sensor. Después de iniciar la brújula, configurar el intervalo de informe — el tiempo entre actualizaciones de sensor — a 400 ms (Observe que la propiedad de TimeBetweenUpdates requiere un múltiplo de 20 ms):

compass.TimeBetweenUpdates = 
  TimeSpan.FromMilliseconds(400);  // Must be multiple of 20
compass.Start();

El valor de 400 ms fue elegido por ensayo y error. El intervalo predeterminado de informe es extremadamente corto. Si intenta ejecutar la aplicación en este valor predeterminado, la cara de la brújula gira con tanta frecuencia que parece ser inestable.

Establecer los controladores de eventos de la brújula la brújula app admite dos controladores de eventos: uno que muestra la página de calibración (calibración­StackPanel) y otro que procesa la partida actual y gira la cara de la brújula.

Definir y establecer el controlador de eventos de calibración el controlador de eventos de calibración contiene relativamente pocas líneas de código. Este código, se muestra en la figura 6, lleva a cabo dos tareas principales: en primer lugar, se muestra la pantalla de calibración que se define en el archivo de MainPage.xaml; en segundo lugar, establece una variable Boolean calibrar en true.

Figura 6 el controlador de eventos de calibración

void compass_Calibrate(object sender, 
  CalibrationEventArgs e)
{
  try
  {
    Dispatcher.BeginInvoke(() => 
    { calibrationStackPanel.Visibility =
      Visibility.Visible; 
    });
    calibrating = true;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message.ToString(), 
       "Error!", MessageBoxButton.OK);
  }
}

Porque este controlador de eventos se llama desde un subproceso en segundo plano, no tiene acceso directo al subproceso de la interfaz de usuario. Así, para mostrar la pantalla de calibración, que necesito llamar al método BeginInvoke en el objeto Dispatcher.

La calibración variable booleana se examina dentro del código para el controlador del evento cambia de valor (compass_CurrentValueChanged). Cuando esta variable es true, ignore la brújula y actualizar la pantalla de calibración con los últimos datos de calibración. Cuando la variable es falsa, yo actualizar las lecturas de la brújula y a realizar rotaciones de la cara de la brújula.

Este controlador de eventos se establece en el constructor de página principal con la siguiente línea de código:

compass.Calibrate += new EventHandler<CalibrationEventArgs>(compass_Calibrate);

Definir y establecer el controlador de Value-Changed se invoca el controlador de evento cambia de valor (compass_CurrentValueChanged) cada vez que llega una nueva lectura de la brújula. Y, dependiendo del estado de la calibración de la variable, o bien actualiza la pantalla de calibración o actualiza la pantalla principal.

Cuando se está actualizando la pantalla principal, el controlador de eventos realiza las siguientes tareas:

  • Calcula los títulos verdaderos y recíprocos con respecto al norte verdadero.
  • Gira la cara de la brújula.
  • Procesa los títulos actuales y recíprocos.

Computación los títulos el código siguiente muestra cómo el controlador de eventos recupera la partida con respecto al verdadero norte utilizando la propiedad TrueHeading del objeto SensorReading:

 

TrueHeading = e.SensorReading.TrueHeading;
  if ((180 <= TrueHeading) && (TrueHeading <= 360))
    ReciprocalHeading = TrueHeading - 180;
  Else
    ReciprocalHeading = TrueHeading + 180;

Figura 7 demuestra cómo actualiza el controlador de eventos los títulos actuales y recíprocos.

Figura 7 actualización corriente y recíproco encabezados

if (!Alphabetic) // Render numeric heading
{
  HeadingTextBlock.Text = TrueHeading.ToString();
  RecipTextBlock.Text = ReciprocalHeading.ToString();
}
else // Render alpha heading
{
  if (((337 <= TrueHeading) && (TrueHeading < 360)) ||
    ((0 <= TrueHeading) && (TrueHeading < 22)))
  {
    HeadingTextBlock.Text = "N";
    RecipTextBlock.Text = "S";
  }
  else if ((22 <= TrueHeading) && (TrueHeading < 67))
  {
    HeadingTextBlock.Text = "NE";
    RecipTextBlock.Text = "SW";
  }
  else if ((67 <= TrueHeading) && (TrueHeading < 112))
  {
    HeadingTextBlock.Text = "E";
    RecipTextBlock.Text = "W";
  }
  else if ((112 <= TrueHeading) && (TrueHeading < 152))
  {
    HeadingTextBlock.Text = "SE";
    RecipTextBlock.Text = "NW";
  }
  else if ((152 <= TrueHeading) && (TrueHeading < 202))
  {
    HeadingTextBlock.Text = "S";
    RecipTextBlock.Text = "N";
  }
  else if ((202 <= TrueHeading) && (TrueHeading < 247))
  {
    HeadingTextBlock.Text = "SW";
    RecipTextBlock.Text = "NE";
  }
  else if ((247 <= TrueHeading) && (TrueHeading < 292))
  {
    HeadingTextBlock.Text = "W";
    RecipTextBlock.Text = "E";
  }
  else if ((292 <= TrueHeading) && (TrueHeading < 337))
  {
    HeadingTextBlock.Text = "NW";
    RecipTextBlock.Text = "SE";
  }
}

Girar la brújula cara el siguiente fragmento de código muestra cómo la app gira las dos elipses que constituyen el fondo y primer plano de la cara de brújula:

CompassFace.RenderTransformOrigin = new Point(0.5, 0.5);
EllipseGlass.RenderTransformOrigin = new Point(0.5, 0.5);
transform.Angle = 360 - TrueHeading;
CompassFace.RenderTransform = transform;
EllipseGlass.RenderTransform = transform;

La variable CompassFace se corresponde con la imagen de fondo que contiene los cuatro puntos de la brújula (N, E, W y S) y la línea horizontal y vertical. La variable EllipseGlass corresponde a la capa de cristal ahumado.

Antes de que puedo aplicar una transformación de giro, necesito asegurar que la transformación se centra en los dos objetos que voy a girar. Esto se hace invocando el método RenderTransformOrigin sobre cada objeto y suministrar las coordenadas (0.5, 0.5). (Para obtener más información acerca de este método y su uso, consulte la página de MSDN Library, «Propiedad de UIElement.RenderTransformOrigin», en bit.ly/KIn8Zh.)

Una vez que he centrado en la transformación, puedo calcular el ángulo y realizar la rotación. Puedo calcular el ángulo restando el rumbo actual de 360. (Este es el título que acaba de recibir en el controlador de eventos). Aplico este nuevo ángulo con la propiedad RenderTransform.

Bloqueo y desbloqueo de la brújula el bloqueo y desbloqueo­ing característica fue pensada para alguien en el exterior que está usando la app para navegar (ya sea en un barco o caminar por un sendero con mapa en mano). Esta característica es simple; invoca al método Stop de la brújula para bloquear el encabezado y, a continuación, invoca el método Start para reanudar la recuperación de la partida.

El método Stop se invoca cuando el usuario presiona LockButton:

private void LockButton_Click(object sender, 
  RoutedEventArgs e)
{
  try
  {
    compass.Stop();
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message.ToString(), 
      "Error!", MessageBoxButton.OK);
  }
}

El método de inicio se invoca cuando el usuario presiona UnlockButton:

private void UnlockButton_Click(object sender, 
  RoutedEventArgs e)
{
  try
  {
    compass.Start();
    compass.TimeBetweenUpdates =
      TimeSpan.FromMilliseconds(400);  
      // Must be multiple of 20
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message.ToString(), 
      "Error!", MessageBoxButton.OK);
  }
}

Tenga en cuenta que además de reiniciar la brújula, reinicio el intervalo de informe a 400 ms para garantizar un comportamiento coherente.

Cambio entre numérico y encabezados de alfa el código que alterna entre alfa y encabezamientos numéricos es controlado por una sola variable Boolean denominada alfabética que se establece cuando el usuario presiona AlphaButton o NumericButton. Cuando el usuario presiona AlphaButton, esta variable se establece en True; Cuando el usuario presiona NumericButton, está establecido en False.

Lo que sigue es el código para el evento click de AlphaButton:

private void AlphaButton_Click(
    object sender, RoutedEventArgs e)
  {
    try
    {
      Alphabetic = true;
    }
    catch (Exception ex)
    {
      MessageBox.Show(
         ex.Message.ToString(), "Error!",
        MessageBoxButton.OK);
    }
  }

El código en el controlador de eventos compass_CurrentValueChanged examina alfabética para determinar si debe representar las cabeceras numéricas o alfa.

Apoyo a la luz y oscuro de visibilidad de temas después de creado el app y sometió a la App Hub para la certificación, me sorprendió recibir una notificación de que había fracasado debido a que ciertos elementos de la IU desaparecieron cuando se analizó el tema de la visibilidad de luz. (Había estado funcionando exclusivamente con el tema oscuro y no había podido probar el tema de la luz).

Para resolver este problema, he añadido código para el constructor de la página principal, que recupera el tema actual y, a continuación, establece el color de primer plano de los elementos de la interfaz de usuario (bloques de texto y botones) para trabajar con el tema determinado. Si es el tema de la luz, los colores de primer plano de los elementos se establecen en negro y rojo. Si se establece el tema oscuro, los colores de primer plano de los elementos se establecen a gris claro y oscuro. Figura 8 muestra este código.

Figura 8 coordinar temas y colores

Visibility isLight = (Visibility)Resources["PhoneLightThemeVisibility"]; // For light theme
if (isLight == System.Windows.Visibility.Visible) // Light theme enabled
{
  // Constructor technique
  SolidColorBrush scb = new SolidColorBrush(Colors.Black);
  SolidColorBrush scb2 = new SolidColorBrush(Colors.Red);
  RecipLabelTextBlock.Foreground = scb;
  HeadingLabelTextBlock.Foreground = scb;
  RecipTextBlock.Foreground = scb2;
  HeadingTextBlock.Foreground = scb2;
  LockButton.Foreground = scb;
  UnlockButton.Foreground = scb;
  AlphaButton.Foreground = scb;
  NumericButton.Foreground = scb;
}
else // Dark color scheme is selected—set text colors accordingly
{
  // Constructor technique
  SolidColorBrush scb = new SolidColorBrush(Colors.DarkGray);
  SolidColorBrush scb2 = new SolidColorBrush(Colors.LightGray);
  RecipLabelTextBlock.Foreground = scb;
  HeadingLabelTextBlock.Foreground = scb;
  RecipTextBlock.Foreground = scb2;
  HeadingTextBlock.Foreground = scb2;
  LockButton.Foreground = scb;
  UnlockButton.Foreground = scb;
  AlphaButton.Foreground = scb;
  NumericButton.Foreground = scb;
}

Divertido y valioso

La creación de esta aplicación fue muy divertido, y así fue valiosa. Después de haber trabajado con un sensor en la plataforma de Windows Phone, ahora tengo una comprensión más clara de las diferencias entre esta plataforma y el soporte de sensor de Windows 8. Pero lo que me impactó la mayoría fueron las similitudes. Mi corazonada es que si eres un desarrollador de Windows Phone que ha pasado en cualquier momento con el espacio de nombres del sensor, vas a encontrar la migración a Windows 8 excepcionalmente sencillo. Y, en Windows 8, encontrará sensores adicionales como el inclinómetro, sensor de orientación y sensor de orientación sencilla. (El sensor de orientación es una fusión de varios sensores que devuelve un cuaternión o matriz de rotación, que puede utilizar para controlar juegos complejos. El sensor de orientación simple permite detectar si el dispositivo está en modo retrato o paisaje, así como hacia o boca abajo.)

Las oportunidades de desarrollo que ofrece todos estos sensores son emocionantes, y estoy deseoso de ver las formas imaginativas de que nuestra comunidad de desarrolladores creativos puede ponerlos a utilizar.

Donn Morse es un escritor programación senior en el equipo de Windows de Microsoft, que en los últimos años se ha centrado en la plataforma de sensor, desde el lado de aplicación para el conductor. Es apasionado y fascinado por sensores y su uso.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Jason Scott