한국마이크로소프트에서 초급 스마트폰 개발자 분들을 위해 공개하는 모다의 윈도우폰7 뚝딱 팩토리 열다섯번째 영상!

스마트폰에서 터치를 제어한다는 것은 매우 중요한 일입니다. 특히 스마트폰 인터페이스가 발전하면서 사용자 경험(UX: User Experience) 측면이 많이 강조가 되고 있는데, 이러한 UX를  터치를 향상시키기 위해 많이 활용하는 것이 다양한 터치패턴(제스쳐)을 활용하는 것입니다.

윈도우폰에서 터치를 인식하는 것은 이벤트 핸들러로도 충분히 할 수 있지만, 조금 더 나아가 멀티 터치를 한다거나, 아니면 터치의 궤적을 추적한다거나 하는 기능이 필요한 어플리케이션을 개발하려고 하면 조금 복잡해져서 단순 이벤트 핸들러에서는 이를 처리할 수 없게 됩니다.
터치를 통해 여러 가지 제어를 하는것을 윈도우폰에서는 Manipulation이라고 하는데요, 윈도우폰에서는 이와 관련된 이벤트를 3가지 제공하고, 흐름을 추적할 수 있는 개발환경을 지원합니다. 터치 흐름 추적과 관련된 이벤트로는 ManipulationStarted / ManipulationDelta / ManipulationCompleted 가 있으며, 이름에서 짐작이 가능하듯이 각각 터치를 막 시작했을때(스크린에 손을 대는 순간), 그리고 손을 댄 이후부터 손을 때기 직전까지, 그리고 손을 때는 순간에 걸쳐 3번 이벤트가 발생하게 됩니다.

그리고, 터치 흐름을 추적하는 방법도 있는데요, 터치는 2차원의 스크린 위에서 이루어 지므로 2차원 좌표계를 이용하게 됩니다. 특히 터치 흐름은 ManipulationDelta 이벤트가 일어나는 과정중에 추적해야 하므로 ManipulationDelta 이벤트로 생성한 메서드에서만 사용이 가능하고요, e.DeltaManipulation.Translation.X / Y 를 통해 터치의 2차원 추적이 가능합니다. 이렇게 손가락 하나의 흐름을 추적하는 것 외에도 손가락 2개, 즉 멀티터치의 궤적을 추적할 수 있는데요, 역시 2차원 좌표계를 이용해 두 손가락 사이의 위치 변화를 감지합니다. 이것 역시 ManipulationDelta 이벤트로 생성한 메서드 안에서 e.DeltaManipulcation.Scale.X / Y 를 이용해서 추적할 수 있습니다.
또한 이번 예제에서 터치기능을 이용해 구현 한 것이 바로 도형의 위치와 크기를 변화시키는 어플리케이션인데요, TranslateTransform 클래스를 이용해 도형의 위치제어를, ScaleTransform 클래스를 이용해 도형의 크기제어를 할 수 있습니다. 이것을 이용해 터치추적-도형모영 제어를 연동할 수 있는데요, 다음 코드와 같이 누적덧셈/곱셈 연산을 통해 제어가 가능합니다.

translation.X += e.DeltaManipulation.Translation.X

보시다시피 상당히 직관적이고 편리한 터치제어 환경을 지원하고 있습니다. 이번 예제는 간단하게 도형의 변화 정도만을 다루었지만 이것을 이용해 사용자만의 제스쳐를 구현한다거나, 이미지 편집 프로그램을 구현할 수 있겠지요.

 

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Net;
   5:  using System.Windows;
   6:  using System.Windows.Controls;
   7:  using System.Windows.Documents;
   8:  using System.Windows.Input;
   9:  using System.Windows.Media;
  10:  using System.Windows.Media.Animation;
  11:  using System.Windows.Shapes;
  12:  using Microsoft.Phone.Controls;
  13:   
  14:  namespace ManupulationTest
  15:  {
  16:      public partial class MainPage : PhoneApplicationPage
  17:      {
  18:          TranslateTransform translation;
  19:          TransformGroup transformGroup;
  20:          ScaleTransform scale;
  21:   
  22:          // Constructor
  23:          public MainPage()
  24:          {
  25:              InitializeComponent();
  26:   
  27:              transformGroup = new TransformGroup();
  28:              translation = new TranslateTransform();
  29:              scale = new ScaleTransform();
  30:   
  31:              transformGroup.Children.Add(translation);
  32:              transformGroup.Children.Add(scale);
  33:   
  34:              rectangle1.RenderTransform = transformGroup;
  35:   
  36:              ManipulationStarted += new EventHandler<ManipulationStartedEventArgs>(MainPage_ManipulationStarted);
  37:              ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(MainPage_ManipulationDelta);
  38:              ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(MainPage_ManipulationCompleted);
  39:          }
  40:   
  41:          void MainPage_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
  42:          {
  43:              //throw new NotImplementedException();
  44:              rectangle1.Fill = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
  45:          }
  46:   
  47:          void MainPage_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
  48:          {
  49:              //throw new NotImplementedException();
  50:              translation.X += e.DeltaManipulation.Translation.X;
  51:              translation.Y += e.DeltaManipulation.Translation.Y;
  52:   
  53:              if (e.DeltaManipulation.Scale.X != 0)
  54:                  scale.ScaleX *= e.DeltaManipulation.Scale.X;
  55:              if (e.DeltaManipulation.Scale.Y != 0)
  56:                  scale.ScaleY *= e.DeltaManipulation.Scale.Y;
  57:          }
  58:   
  59:          void MainPage_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
  60:          {
  61:              // throw new NotImplementedException();
  62:              rectangle1.Fill = new SolidColorBrush(Color.FromArgb(127, 255, 0, 0));
  63:          }
  64:      }
  65:   
  66:  }