다음을 통해 공유


연습: Xamarin.iOS에서 Touch 사용

이 연습에서는 다양한 종류의 터치 이벤트에 응답하는 코드를 작성하는 방법을 보여 줍니다. 각 예제는 별도의 화면에 포함됩니다.

각 섹션에는 코드를 처음부터 작성하는 지침이 포함되어 있습니다.

아래 지침에 따라 스토리보드에 코드를 추가하고 iOS에서 사용할 수 있는 다양한 유형의 터치 이벤트에 대해 알아봅니다.

터치 샘플

이 샘플에서는 일부 터치 API를 보여 줍니다. 터치 이벤트를 구현하는 데 필요한 코드를 추가하려면 다음 단계를 수행합니다.

  1. 프로젝트 Touch_Start 엽니다. 먼저 프로젝트를 실행하여 모든 것이 괜찮은지 확인하고 터치 샘플 단추를 터치합니다. 다음과 유사한 화면이 표시됩니다(단추는 작동하지 않지만).

    작동하지 않는 단추로 실행되는 샘플 앱

  2. 파일 TouchViewController.cs 편집하고 클래스에 다음 두 개의 인스턴스 변수를 TouchViewController추가합니다.

    #region Private Variables
    private bool imageHighlighted = false;
    private bool touchStartedInside;
    #endregion
    
  3. TouchesBegan 아래 코드와 같이 메서드를 구현합니다.

    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        base.TouchesBegan(touches, evt);
    
        // If Multitouch is enabled, report the number of fingers down
        TouchStatus.Text = string.Format ("Number of fingers {0}", touches.Count);
    
        // Get the current touch
        UITouch touch = touches.AnyObject as UITouch;
        if (touch != null)
        {
            // Check to see if any of the images have been touched
            if (TouchImage.Frame.Contains(touch.LocationInView(TouchView)))
            {
                // Fist image touched
                TouchImage.Image = UIImage.FromBundle("TouchMe_Touched.png");
                TouchStatus.Text = "Touches Began";
            } else if (touch.TapCount == 2 && DoubleTouchImage.Frame.Contains(touch.LocationInView(TouchView)))
            {
                // Second image double-tapped, toggle bitmap
                if (imageHighlighted)
                {
                    DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe.png");
                    TouchStatus.Text = "Double-Tapped Off";
                }
                else
                {
                    DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe_Highlighted.png");
                    TouchStatus.Text = "Double-Tapped On";
                }
                imageHighlighted = !imageHighlighted;
            } else if (DragImage.Frame.Contains(touch.LocationInView(View)))
            {
                // Third image touched, prepare to drag
                touchStartedInside = true;
            }
        }
    }
    

    이 메서드는 개체에 대해 UITouch 검사 작동하며, 개체가 있는 경우 터치가 발생한 위치에 따라 몇 가지 작업을 수행합니다.

    • TouchImage 내부 – 레이블에 텍스트를 Touches Began 표시하고 이미지를 변경합니다.
    • DoubleTouchImage 내부 – 제스처가 두 번 탭된 경우 표시되는 이미지를 변경합니다.
    • DragImage 내부 – 터치가 시작되었음을 나타내는 플래그를 설정합니다. 이 메서드 TouchesMoved 는 다음 단계에서 볼 수 있듯이 이 플래그를 사용하여 화면 주위로 이동해야 하는지 DragImage 여부를 결정합니다.

    위의 코드는 개별 터치만 처리하며 사용자가 화면에서 손가락을 이동하는 경우에도 동작이 없습니다. 이동에 응답하려면 아래 코드와 같이 구현 TouchesMoved 합니다.

    public override void TouchesMoved(NSSet touches, UIEvent evt)
    {
        base.TouchesMoved(touches, evt);
        // get the touch
        UITouch touch = touches.AnyObject as UITouch;
        if (touch != null)
        {
            //==== IMAGE TOUCH
            if (TouchImage.Frame.Contains(touch.LocationInView(TouchView)))
            {
                TouchStatus.Text = "Touches Moved";
            }
    
            //==== IMAGE DRAG
            // check to see if the touch started in the drag me image
            if (touchStartedInside)
            {
                // move the shape
                float offsetX = touch.PreviousLocationInView(View).X - touch.LocationInView(View).X;
                float offsetY = touch.PreviousLocationInView(View).Y - touch.LocationInView(View).Y;
                DragImage.Frame = new RectangleF(new PointF(DragImage.Frame.X - offsetX, DragImage.Frame.Y - offsetY), DragImage.Frame.Size);
            }
        }
    }
    

    이 메서드는 개체를 UITouch 가져오고 검사 터치가 발생한 위치를 확인합니다. 터치가 발생한 TouchImage경우 터치 이동 텍스트가 화면에 표시됩니다.

    true이면 touchStartedInside 사용자가 손가락을 대 DragImage 고 이동하는 것을 알 수 있습니다. 사용자가 화면을 손가락으로 이동하면 코드가 이동합니다 DragImage .

  4. 사용자가 화면에서 손가락을 떼거나 iOS에서 터치 이벤트를 취소할 때 사례를 처리해야 합니다. 이를 위해 아래와 같이 구현 TouchesEnded 합니다 TouchesCancelled .

    public override void TouchesCancelled(NSSet touches, UIEvent evt)
    {
        base.TouchesCancelled(touches, evt);
    
        // reset our tracking flags
        touchStartedInside = false;
        TouchImage.Image = UIImage.FromBundle("TouchMe.png");
        TouchStatus.Text = "";
    }
    
    public override void TouchesEnded(NSSet touches, UIEvent evt)
    {
        base.TouchesEnded(touches, evt);
        // get the touch
        UITouch touch = touches.AnyObject as UITouch;
        if (touch != null)
        {
            //==== IMAGE TOUCH
            if (TouchImage.Frame.Contains(touch.LocationInView(TouchView)))
            {
                TouchImage.Image = UIImage.FromBundle("TouchMe.png");
                TouchStatus.Text = "Touches Ended";
            }
        }
        // reset our tracking flags
        touchStartedInside = false;
    }
    

    이러한 두 방법 모두 플래그를 false로 touchStartedInside 다시 설정합니다. TouchesEnded 화면에도 표시됩니다 TouchesEnded .

  5. 이 시점에서 터치 샘플 화면이 완료됩니다. 다음 스크린샷과 같이 각 이미지와 상호 작용할 때 화면이 어떻게 변경되는지 확인합니다.

    시작 앱 화면

    사용자가 단추를 끈 후의 화면

제스처 인식기 샘플

이전 섹션에서터치 이벤트를 사용하여 화면 주위에 개체를 끄는 방법을 보여 줍니다. 이 섹션에서는 터치 이벤트를 제거하고 다음 제스처 인식기를 사용하는 방법을 보여 줍니다.

  • UIPanGestureRecognizer 화면 주위에 이미지를 끌기 위한 것입니다.
  • UITapGestureRecognizer 화면의 두 번 탭에 응답하는 것입니다.

제스처 인식기를 구현하려면 다음 단계를 수행합니다.

  1. 파일 GestureViewController.cs 편집하고 다음 인스턴스 변수를 추가합니다.

    #region Private Variables
    private bool imageHighlighted = false;
    private RectangleF originalImageFrame = RectangleF.Empty;
    #endregion
    

    이미지의 이전 위치를 추적하려면 이 인스턴스 변수가 필요합니다. 이동 제스처 인식기 화면에서 이미지를 다시 그리는 데 필요한 오프셋을 계산 하는 값을 사용 originalImageFrame 합니다.

  2. 컨트롤러에 다음 메서드를 추가합니다.

    private void WireUpDragGestureRecognizer()
    {
        // Create a new tap gesture
        UIPanGestureRecognizer gesture = new UIPanGestureRecognizer();
    
        // Wire up the event handler (have to use a selector)
        gesture.AddTarget(() => HandleDrag(gesture));  // to be defined
    
        // Add the gesture recognizer to the view
        DragImage.AddGestureRecognizer(gesture);
    }
    

    이 코드는 인스턴스를 UIPanGestureRecognizer 인스턴스화하고 뷰에 추가합니다. 메서드의 HandleDrag 형태로 제스처에 대상을 할당합니다. 이 메서드는 다음 단계에서 제공됩니다.

  3. HandleDrag를 구현하려면 컨트롤러에 다음 코드를 추가합니다.

    private void HandleDrag(UIPanGestureRecognizer recognizer)
    {
        // If it's just began, cache the location of the image
        if (recognizer.State == UIGestureRecognizerState.Began)
        {
            originalImageFrame = DragImage.Frame;
        }
    
        // Move the image if the gesture is valid
        if (recognizer.State != (UIGestureRecognizerState.Cancelled | UIGestureRecognizerState.Failed
            | UIGestureRecognizerState.Possible))
        {
            // Move the image by adding the offset to the object's frame
            PointF offset = recognizer.TranslationInView(DragImage);
            RectangleF newFrame = originalImageFrame;
            newFrame.Offset(offset.X, offset.Y);
            DragImage.Frame = newFrame;
        }
    }
    

    위의 코드는 먼저 제스처 인식기의 상태를 검사 다음 화면 주위로 이미지를 이동합니다. 이 코드를 사용하면 컨트롤러에서 이제 화면 주위에서 하나의 이미지 끌기를 지원할 수 있습니다.

  4. DoubleTouchImage에 표시되는 이미지를 변경하는 A UITapGestureRecognizer 를 추가합니다. 컨트롤러에 다음 메서드를 GestureViewController 추가합니다.

    private void WireUpTapGestureRecognizer()
    {
        // Create a new tap gesture
        UITapGestureRecognizer tapGesture = null;
    
        // Report touch
        Action action = () => {
            TouchStatus.Text = string.Format("Image touched at: {0}",tapGesture.LocationOfTouch(0, DoubleTouchImage));
    
            // Toggle the image
            if (imageHighlighted)
            {
                DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe.png");
            }
            else
            {
                DoubleTouchImage.Image = UIImage.FromBundle("DoubleTapMe_Highlighted.png");
            }
            imageHighlighted = !imageHighlighted;
        };
    
        tapGesture = new UITapGestureRecognizer(action);
    
        // Configure it
        tapGesture.NumberOfTapsRequired = 2;
    
        // Add the gesture recognizer to the view
        DoubleTouchImage.AddGestureRecognizer(tapGesture);
    }
    

    이 코드는 해당 코드 UIPanGestureRecognizer 와 매우 유사하지만 대상에 대리자를 사용하는 대신 사용 Action중입니다.

  5. 마지막으로 해야 할 일은 방금 추가한 메서드를 호출하도록 수정 ViewDidLoad 하는 것입니다. ViewDidLoad를 변경하여 다음 코드와 유사하게 변경합니다.

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        Title = "Gesture Recognizers";
    
        // Save initial state
        originalImageFrame = DragImage.Frame;
    
        WireUpTapGestureRecognizer();
        WireUpDragGestureRecognizer();
    }
    

    의 값을 originalImageFrame초기화합니다.

  6. 애플리케이션을 실행하고 두 이미지와 상호 작용합니다. 다음 스크린샷은 이러한 상호 작용의 한 예입니다.

    이 스크린샷은 끌기 상호 작용을 보여줍니다.

사용자 지정 제스처 인식기

이 섹션에서는 이전 섹션의 개념을 적용하여 사용자 지정 제스처 인식기를 빌드합니다. 사용자 지정 제스처 인식기는 서브클래스를 UIGestureRecognizer수행하고 사용자가 화면에서 "V"를 그린 다음 비트맵을 토글할 때 인식합니다. 다음 스크린샷은 이 화면의 예입니다.

사용자가 화면에 V를 그릴 때 앱이 인식됩니다.

사용자 지정 제스처 인식기를 만들려면 다음 단계를 수행합니다.

  1. 프로젝트에 CheckmarkGestureRecognizer새 클래스를 추가하고 다음 코드와 같이 표시합니다.

    using System;
    using CoreGraphics;
    using Foundation;
    using UIKit;
    
    namespace Touch
    {
        public class CheckmarkGestureRecognizer : UIGestureRecognizer
        {
            #region Private Variables
            private CGPoint midpoint = CGPoint.Empty;
            private bool strokeUp = false;
            #endregion
    
            #region Override Methods
            /// <summary>
            ///   Called when the touches end or the recognizer state fails
            /// </summary>
            public override void Reset()
            {
                base.Reset();
    
                strokeUp = false;
                midpoint = CGPoint.Empty;
            }
    
            /// <summary>
            ///   Is called when the fingers touch the screen.
            /// </summary>
            public override void TouchesBegan(NSSet touches, UIEvent evt)
            {
                base.TouchesBegan(touches, evt);
    
                // we want one and only one finger
                if (touches.Count != 1)
                {
                    base.State = UIGestureRecognizerState.Failed;
                }
    
                Console.WriteLine(base.State.ToString());
            }
    
            /// <summary>
            ///   Called when the touches are cancelled due to a phone call, etc.
            /// </summary>
            public override void TouchesCancelled(NSSet touches, UIEvent evt)
            {
                base.TouchesCancelled(touches, evt);
                // we fail the recognizer so that there isn't unexpected behavior
                // if the application comes back into view
                base.State = UIGestureRecognizerState.Failed;
            }
    
            /// <summary>
            ///   Called when the fingers lift off the screen
            /// </summary>
            public override void TouchesEnded(NSSet touches, UIEvent evt)
            {
                base.TouchesEnded(touches, evt);
                //
                if (base.State == UIGestureRecognizerState.Possible && strokeUp)
                {
                    base.State = UIGestureRecognizerState.Recognized;
                }
    
                Console.WriteLine(base.State.ToString());
            }
    
            /// <summary>
            ///   Called when the fingers move
            /// </summary>
            public override void TouchesMoved(NSSet touches, UIEvent evt)
            {
                base.TouchesMoved(touches, evt);
    
                // if we haven't already failed
                if (base.State != UIGestureRecognizerState.Failed)
                {
                    // get the current and previous touch point
                    CGPoint newPoint = (touches.AnyObject as UITouch).LocationInView(View);
                    CGPoint previousPoint = (touches.AnyObject as UITouch).PreviousLocationInView(View);
    
                    // if we're not already on the upstroke
                    if (!strokeUp)
                    {
                        // if we're moving down, just continue to set the midpoint at
                        // whatever point we're at. when we start to stroke up, it'll stick
                        // as the last point before we upticked
                        if (newPoint.X >= previousPoint.X && newPoint.Y >= previousPoint.Y)
                        {
                            midpoint = newPoint;
                        }
                        // if we're stroking up (moving right x and up y [y axis is flipped])
                        else if (newPoint.X >= previousPoint.X && newPoint.Y <= previousPoint.Y)
                        {
                            strokeUp = true;
                        }
                        // otherwise, we fail the recognizer
                        else
                        {
                            base.State = UIGestureRecognizerState.Failed;
                        }
                    }
                }
    
                Console.WriteLine(base.State.ToString());
            }
            #endregion
        }
    }
    

    Reset 메서드는 속성이 State 둘 중 하나 Recognized 또는 Ended.로 변경되면 호출됩니다. 사용자 지정 제스처 인식기에서 설정된 내부 상태를 다시 설정해야 합니다. 이제 다음 번에 사용자가 애플리케이션과 상호 작용할 때 클래스가 새로 시작되고 제스처를 다시 인식할 준비가 될 수 있습니다.

  2. 이제 사용자 지정 제스처 인식기(CheckmarkGestureRecognizer)를 정의했으므로 CustomGestureViewController.cs 파일을 편집하고 다음 두 개의 인스턴스 변수를 추가합니다.

    #region Private Variables
    private bool isChecked = false;
    private CheckmarkGestureRecognizer checkmarkGesture;
    #endregion
    
  3. 제스처 인식기를 인스턴스화하고 구성하려면 컨트롤러에 다음 메서드를 추가합니다.

    private void WireUpCheckmarkGestureRecognizer()
    {
        // Create the recognizer
        checkmarkGesture = new CheckmarkGestureRecognizer();
    
        // Wire up the event handler
        checkmarkGesture.AddTarget(() => {
            if (checkmarkGesture.State == (UIGestureRecognizerState.Recognized | UIGestureRecognizerState.Ended))
            {
                if (isChecked)
                {
                    CheckboxImage.Image = UIImage.FromBundle("CheckBox_Unchecked.png");
                }
                else
                {
                    CheckboxImage.Image = UIImage.FromBundle("CheckBox_Checked.png");
                }
                isChecked = !isChecked;
            }
        });
    
        // Add the gesture recognizer to the view
        View.AddGestureRecognizer(checkmarkGesture);
    }
    
  4. 다음 코드 조각과 같이 호출WireUpCheckmarkGestureRecognizer되도록 편집 ViewDidLoad 합니다.

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
    
        // Wire up the gesture recognizer
        WireUpCheckmarkGestureRecognizer();
    }
    
  5. 애플리케이션을 실행하고 화면에 "V"를 그려 봅니다. 다음 스크린샷과 같이 변경 내용이 표시되는 이미지가 표시됩니다.

    단추가 검사

    단추가 검사

위의 세 섹션에서는 터치 이벤트, 기본 제공 제스처 인식기 또는 사용자 지정 제스처 인식기를 사용하여 iOS에서 터치 이벤트에 응답하는 다양한 방법을 보여 줍니다.