다음을 통해 공유


방향 센서 사용하기

방향 센서를 사용하여 디바이스 방향을 확인하는 방법을 알아봅니다.

중요 API

필수 조건

XAML(Extensible Application Markup Language), Microsoft Visual C#, 이벤트에 대해 잘 알고 있어야 합니다.

사용 중인 디바이스 또는 에뮬레이터는 방향 센서를 지원해야 합니다.

OrientationSensor 앱 만들기

방향 센서는 앱이 디바이스 방향의 변경에 응답할 수 있도록 하는 여러 형식의 환경 센서 중 하나입니다.

Windows.Devices.Sensors 네임스페이스에는 OrientationSensorSimpleOrientation이라는 두 가지 유형의 방향 센서 API가 포함되어 있습니다. 이 두 센서는 모두 방향 센서이지만 해당 용어는 오버로드되고 매우 다른 용도로 사용됩니다. 그러나 둘 다 방향 센서이므로 둘 다 이 문서에서 다룹니다.

OrientationSensor API는 3D 앱에서 쿼터니언 및 회전 행렬을 가져오는 데 사용됩니다. 쿼터니언은 임의의 축을 중심으로 한 점[x,y,z]의 회전이라고 이해하면 제일 쉽습니다(세 축을 중심으로 한 회전을 나타내는 회전 행렬과 대조적). 쿼터니언 뒤의 수학은 복소수의 기하학적 속성과 허수의 수학적 속성을 포함하지만, 간단하게 협동하며 DirectX와 같은 프레임 워크의 지원을 받는다는 측면에서 상당히 이국적인입니다. 복잡한 3D 앱은 방향 센서를 사용하여 사용자의 관점을 조정할 수 있습니다. 이 센서는 가속도계, 자이로미터 및 나침반의 입력을 결합합니다.

SimpleOrientation API는 세로 위, 세로 아래쪽, 가로 왼쪽 및 가로 오른쪽과 같은 정의 측면에서 현재 디바이스 방향을 결정하는 데 사용됩니다. 디바이스가 페이스업 또는 페이스다운인지를 감지할 수 있습니다. 이 센서는 "세로 위로" 또는 "가로 왼쪽"과 같은 속성을 반환하는 대신 회전 값 "회전 안 함", "Rotated90DegreesCounterclockwise" 등을 반환합니다. 다음의 테이블은 공통 방향 속성을 해당 센서 판독값에 매핑합니다.

방향 해당 센서 판독값
세로 방향(위쪽) NotRotated
가로 방향(왼쪽) Rotated90DegreesCounterclockwise
세로 방향(아래쪽) Rotated180DegreesCounterclockwise
가로 방향(오른쪽) Rotated270DegreesCounterclockwise

참고

보다 완전한 구현은 다음을 참조하세요.

지침

  • Visual C# 프로젝트 템플릿에서 빈 앱(Universal Windows)을 선택하여 새 프로젝트를 만듭니다.

  • 프로젝트의 MainPage.xaml.cs 파일을 열고 기존의 코드를 다음과 같이 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;

    using Windows.UI.Core;
    using Windows.Devices.Sensors;

    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/p/?linkid=234238

    namespace App1
    {
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class MainPage : Page
        {
            private OrientationSensor _sensor;

            private async void ReadingChanged(object sender, OrientationSensorReadingChangedEventArgs e)
            {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    OrientationSensorReading reading = e.Reading;

                    // Quaternion values
                    txtQuaternionX.Text = String.Format("{0,8:0.00000}", reading.Quaternion.X);
                    txtQuaternionY.Text = String.Format("{0,8:0.00000}", reading.Quaternion.Y);
                    txtQuaternionZ.Text = String.Format("{0,8:0.00000}", reading.Quaternion.Z);
                    txtQuaternionW.Text = String.Format("{0,8:0.00000}", reading.Quaternion.W);

                    // Rotation Matrix values
                    txtM11.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M11);
                    txtM12.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M12);
                    txtM13.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M13);
                    txtM21.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M21);
                    txtM22.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M22);
                    txtM23.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M23);
                    txtM31.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M31);
                    txtM32.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M32);
                    txtM33.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M33);
                });
            }

            public MainPage()
            {
                this.InitializeComponent();
                _sensor = OrientationSensor.GetDefault();

                // Establish the report interval for all scenarios
                uint minReportInterval = _sensor.MinimumReportInterval;
                uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
                _sensor.ReportInterval = reportInterval;

                // Establish event handler
                _sensor.ReadingChanged += new TypedEventHandler<OrientationSensor, OrientationSensorReadingChangedEventArgs>(ReadingChanged);
            }
        }
    }

이전 코드 조각의 네임스페이스의 이름을 프로젝트에 지정한 이름으로 바꿔야 합니다. 예를 들어 OrientationSensorCS라는 프로젝트를 만든 경우, namespace App1을(를) namespace OrientationSensorCS(으)로 교체합니다.

  • MainPage.xaml 파일을 열고 이 파일의 원본 내용을 다음의 XAML로 바꿉니다.
        <Page
        x:Class="App1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">

        <Grid x:Name="LayoutRoot" Background="Black">
            <TextBlock HorizontalAlignment="Left" Height="28" Margin="4,4,0,0" TextWrapping="Wrap" Text="M11:" VerticalAlignment="Top" Width="46"/>
            <TextBlock HorizontalAlignment="Left" Height="23" Margin="4,36,0,0" TextWrapping="Wrap" Text="M12:" VerticalAlignment="Top" Width="39"/>
            <TextBlock HorizontalAlignment="Left" Height="24" Margin="4,72,0,0" TextWrapping="Wrap" Text="M13:" VerticalAlignment="Top" Width="39"/>
            <TextBlock HorizontalAlignment="Left" Height="31" Margin="4,118,0,0" TextWrapping="Wrap" Text="M21:" VerticalAlignment="Top" Width="39"/>
            <TextBlock HorizontalAlignment="Left" Height="24" Margin="4,160,0,0" TextWrapping="Wrap" Text="M22:" VerticalAlignment="Top" Width="39"/>
            <TextBlock HorizontalAlignment="Left" Height="24" Margin="8,201,0,0" TextWrapping="Wrap" Text="M23:" VerticalAlignment="Top" Width="35"/>
            <TextBlock HorizontalAlignment="Left" Height="23" Margin="4,234,0,0" TextWrapping="Wrap" Text="M31:" VerticalAlignment="Top" Width="39"/>
            <TextBlock HorizontalAlignment="Left" Height="28" Margin="4,274,0,0" TextWrapping="Wrap" Text="M32:" VerticalAlignment="Top" Width="46"/>
            <TextBlock HorizontalAlignment="Left" Height="21" Margin="4,322,0,0" TextWrapping="Wrap" Text="M33:" VerticalAlignment="Top" Width="39"/>
            <TextBlock x:Name="txtM11" HorizontalAlignment="Left" Height="19" Margin="43,4,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM12" HorizontalAlignment="Left" Height="23" Margin="43,36,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM13" HorizontalAlignment="Left" Height="15" Margin="43,72,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM21" HorizontalAlignment="Left" Height="20" Margin="43,114,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM22" HorizontalAlignment="Left" Height="19" Margin="43,156,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM23" HorizontalAlignment="Left" Height="16" Margin="43,197,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM31" HorizontalAlignment="Left" Height="17" Margin="43,230,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM32" HorizontalAlignment="Left" Height="19" Margin="43,270,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock x:Name="txtM33" HorizontalAlignment="Left" Height="21" Margin="43,322,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="53"/>
            <TextBlock HorizontalAlignment="Left" Height="15" Margin="194,8,0,0" TextWrapping="Wrap" Text="Quaternion X:" VerticalAlignment="Top" Width="81"/>
            <TextBlock HorizontalAlignment="Left" Height="23" Margin="194,36,0,0" TextWrapping="Wrap" Text="Quaternion Y:" VerticalAlignment="Top" Width="81"/>
            <TextBlock HorizontalAlignment="Left" Height="15" Margin="194,72,0,0" TextWrapping="Wrap" Text="Quaternion Z:" VerticalAlignment="Top" Width="81"/>
            <TextBlock x:Name="txtQuaternionX" HorizontalAlignment="Left" Height="15" Margin="279,8,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="104"/>
            <TextBlock x:Name="txtQuaternionY" HorizontalAlignment="Left" Height="12" Margin="275,36,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="108"/>
            <TextBlock x:Name="txtQuaternionZ" HorizontalAlignment="Left" Height="19" Margin="275,68,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="89"/>
            <TextBlock HorizontalAlignment="Left" Height="21" Margin="194,96,0,0" TextWrapping="Wrap" Text="Quaternion W:" VerticalAlignment="Top" Width="81"/>
            <TextBlock x:Name="txtQuaternionW" HorizontalAlignment="Left" Height="12" Margin="279,96,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="72"/>

        </Grid>
    </Page>

이전 코드 조각에서 클래스 이름의 첫 번째 부분을 앱의 네임스페이스로 바꿔야 합니다. 예를 들어 OrientationSensorCS라는 프로젝트를 만든 경우, x:Class="App1.MainPage"을(를) x:Class="OrientationSensorCS.MainPage"(으)로 교체합니다. 또한 xmlns:local="using:App1"을(를) xmlns:local="using:OrientationSensorCS"(으)로 대체해야 합니다.

  • F5 키를 누르거나 디버그>디버깅 시작을 선택하여 앱을 빌드하고 배포하고 실행합니다.

앱이 실행되면 방향을 변경하기 위해 디바이스를 이동하거나 Emulator 도구를 사용할 수 있습니다.

  • Visual Studio로 돌아가서 Shift+F5를 눌러 앱을 중지하거나 디버그>디버깅 중지를 선택하여 앱을 중지합니다.

설명

이전 예시는 앱에서 방향 센서 입력을 통합하기 위해 작성해야 하는 코드가 얼마나 적은지를 보여 줍니다.

앱은 MainPage 메서드에서 기본 방향 센서와의 연결을 설정합니다.

_sensor = OrientationSensor.GetDefault();

앱은 MainPage 메서드 내에서 보고서 간격을 설정합니다. 이 코드는 디바이스에서 지원하는 최소 간격을 검색하고 요청된 간격인 16밀리초(약 60Hz 새로 고침 속도)와 비교합니다. 지원되는 최소 간격이 요청된 간격보다 큰 경우 코드는 값을 최소값으로 설정합니다. 그렇지 않으면 값을 요청된 간격으로 설정합니다.

uint minReportInterval = _sensor.MinimumReportInterval;
uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
_sensor.ReportInterval = reportInterval;

새로운 센서 데이터는 ReadingChanged 메서드에서 캡처됩니다. 센서 드라이버가 센서에서 새 데이터를 받을 때마다 이 이벤트 처리기를 사용하여 값을 앱에 전달합니다. 앱은 다음의 줄에 이 이벤트 처리기를 등록합니다.

_sensor.ReadingChanged += new TypedEventHandler<OrientationSensor,
OrientationSensorReadingChangedEventArgs>(ReadingChanged);

이러한 새 값은 프로젝트의 XAML에 있는 TextBlocks에 기록됩니다.

SimpleOrientation 앱 만들기

이 섹션은 두 개의 하위 섹션으로 나뉩니다. 첫 번째 하위 섹션은 간단한 방향 애플리케이션을 처음부터 만드는 데 필요한 단계를 안내합니다. 다음의 하위 섹션은 방금 만든 앱을 설명합니다.

지침

  • Visual C# 프로젝트 템플릿에서 빈 앱(Universal Windows)을 선택하여 새 프로젝트를 만듭니다.

  • 프로젝트의 MainPage.xaml.cs 파일을 열고 기존의 코드를 다음과 같이 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;

    using Windows.UI.Core;
    using Windows.Devices.Sensors;
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/p/?linkid=234238

    namespace App1
    {
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class MainPage : Page
        {
            // Sensor and dispatcher variables
            private SimpleOrientationSensor _simpleorientation;

            // This event handler writes the current sensor reading to
            // a text block on the app' s main page.

            private async void OrientationChanged(object sender, SimpleOrientationSensorOrientationChangedEventArgs e)
            {
                await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    SimpleOrientation orientation = e.Orientation;
                    switch (orientation)
                    {
                        case SimpleOrientation.NotRotated:
                            txtOrientation.Text = "Not Rotated";
                            break;
                        case SimpleOrientation.Rotated90DegreesCounterclockwise:
                            txtOrientation.Text = "Rotated 90 Degrees Counterclockwise";
                            break;
                        case SimpleOrientation.Rotated180DegreesCounterclockwise:
                            txtOrientation.Text = "Rotated 180 Degrees Counterclockwise";
                            break;
                        case SimpleOrientation.Rotated270DegreesCounterclockwise:
                            txtOrientation.Text = "Rotated 270 Degrees Counterclockwise";
                            break;
                        case SimpleOrientation.Faceup:
                            txtOrientation.Text = "Faceup";
                            break;
                        case SimpleOrientation.Facedown:
                            txtOrientation.Text = "Facedown";
                            break;
                        default:
                            txtOrientation.Text = "Unknown orientation";
                            break;
                    }
                });
            }

            public MainPage()
            {
                this.InitializeComponent();
                _simpleorientation = SimpleOrientationSensor.GetDefault();

                // Assign an event handler for the sensor orientation-changed event
                if (_simpleorientation != null)
                {
                    _simpleorientation.OrientationChanged += new TypedEventHandler<SimpleOrientationSensor, SimpleOrientationSensorOrientationChangedEventArgs>(OrientationChanged);
                }
            }
        }
    }

이전 코드 조각의 네임스페이스의 이름을 프로젝트에 지정한 이름으로 바꿔야 합니다. 예를 들어 SimpleOrientationCS라는 프로젝트를 만든 경우, namespace App1을(를) namespace SimpleOrientationCS(으)로 교체합니다.

  • MainPage.xaml 파일을 열고 이 파일의 원본 내용을 다음의 XAML로 바꿉니다.
    <Page
        x:Class="App1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">

        <Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
            <TextBlock HorizontalAlignment="Left" Height="24" Margin="8,8,0,0" TextWrapping="Wrap" Text="Current Orientation:" VerticalAlignment="Top" Width="101" Foreground="#FFF8F7F7"/>
            <TextBlock x:Name="txtOrientation" HorizontalAlignment="Left" Height="24" Margin="118,8,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="175" Foreground="#FFFEFAFA"/>

        </Grid>
    </Page>

이전 코드 조각에서 클래스 이름의 첫 번째 부분을 앱의 네임스페이스로 바꿔야 합니다. 예를 들어 SimpleOrientationCS라는 프로젝트를 만든 경우, x:Class="App1.MainPage"을(를) x:Class="SimpleOrientationCS.MainPage"(으)로 교체합니다. 또한 xmlns:local="using:App1"을(를) xmlns:local="using:SimpleOrientationCS"(으)로 대체해야 합니다.

  • F5 키를 누르거나 디버그>디버깅 시작을 선택하여 앱을 빌드하고 배포하고 실행합니다.

앱이 실행되면 방향을 변경하기 위해 디바이스를 이동하거나 Emulator 도구를 사용할 수 있습니다.

  • Visual Studio로 돌아가서 Shift+F5를 눌러 앱을 중지하거나 디버그>디버깅 중지를 선택하여 앱을 중지합니다.

설명

이전 예시는 앱에서 간단한 방향 센서 입력을 통합하기 위해 작성해야 하는 코드가 얼마나 적은 지를 보여 줍니다.

앱은 MainPage 메서드에서 기본 센서와의 연결을 설정합니다.

_simpleorientation = SimpleOrientationSensor.GetDefault();

새로운 센서 데이터는 OrientationChanged 메서드에서 캡처됩니다. 센서 드라이버가 센서에서 새 데이터를 받을 때마다 이 이벤트 처리기를 사용하여 값을 앱에 전달합니다. 앱은 다음의 줄에 이 이벤트 처리기를 등록합니다.

_simpleorientation.OrientationChanged += new TypedEventHandler<SimpleOrientationSensor,
SimpleOrientationSensorOrientationChangedEventArgs>(OrientationChanged);

이러한 새 값은 프로젝트의 XAML에 있는 TextBlock에 기록됩니다.

<TextBlock HorizontalAlignment="Left" Height="24" Margin="8,8,0,0" TextWrapping="Wrap" Text="Current Orientation:" VerticalAlignment="Top" Width="101" Foreground="#FFF8F7F7"/>
 <TextBlock x:Name="txtOrientation" HorizontalAlignment="Left" Height="24" Margin="118,8,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="175" Foreground="#FFFEFAFA"/>