2016년 11월 15일 화요일

Project A - Touch

프로젝트라고 하기에는 민망하지만, 간단하게 화면을 터치하면 그 좌표를 출력하는 앱을 만들어 봅시다.

1. 새로운 뷰 만들기
먼저 기본 뷰를 사용하지 않을 것이므로 새로운 뷰를 만들어야 합니다.

    public class TouchView : Android.Views.View
    {
        public TouchView(Context context) : base(context)
        {
        }
    }

그리고 이 뷰를 앱에 세팅시켜야겠죠.

        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            // Set our view from the "main" layout resource
            SetContentView (Resource.Layout.Main);


이 부분을

        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            SetContentView(new TouchView(this));


로 바꿉니다. 물론 이렇게 되면 기본적으로 등록되어 있던 오브젝트(버튼 등)들도 동작하지 않으므로 해당 코드를 지워줘야 합니다.

이대로 실행해 보면 다음과 같이 아무것도 없는 화면만이 나타납니다.




2. 터치이벤트 처리
터치이벤트를 처리하는 메소드는 이미 Android.Views.View에 포함되어 있습니다. 우리가 할 일은 이 메소드를 재정의하는 일입니다.

    public class TouchView : Android.Views.View
    {
        public TouchView(Context context) : base(context)
        {
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            return true;
        }
    }

여기에 브레이크포인트를 걸고 확인해보면 마우스를 클릭할 때마다 이곳으로 들어옴을 알 수 있습니다.

클릭정보는 MotionEvent e를 통해서 들어옵니다. 여러가지 정보가 있지만 중요한 것은 다음과 같습니다.

① e.Action
어떤 이벤트가 일어났는지를 구분하는 enum입니다. 여러가지가 있지만, 지금 당장 필요한 것은 다음과 같은 세개입니다.

- Android.Views.MotionEventActions.Down : 화면을 터치할때 일어나는 이벤트
- Android.Views.MotionEventActions.Up : 화면에서 손을 뗄때 일어나는 이벤트
- Android.Views.MotionEventActions.Move : 화면에서 움직일때 일어나는 이벤트

② e.GetX(), e.GetY()
이벤트가 어디서 일어났는지 알려주는 부분입니다.


3. 화면출력
일단 이벤트가 일어났는데, 이벤트가 일어났는지 안일어났는지 밖에서는 알 수가 없겠죠. 그래서 간단하게 이벤트를 출력하는 부분을 만들어야 합니다.

    public class TouchView : Android.Views.View
    {
        public TouchView(Context context) : base(context)
        {
        }

        protected override void OnDraw(Canvas canvas)
        {
             base.OnDraw(canvas);
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            return true;
        }
    }

OnDraw()에서는 canvas에 여러가지 작업을 하면 그것이 화면에 나타나게 됩니다.
이 프로젝트에서 하는 일은 화면에 글을 쓰는 일입니다. 그 작업은 다음과 같은 함수로 할 수 있습니다.

        public virtual void DrawText(string text, float x, float y, Paint paint);

이 외에도 몇가지 함수가 더 있는데 우선 이것만 보기로 하죠.

일어난 이벤트 종류와 위치를 화면에 출력하는 TouchView 클래스입니다.



    public class TouchView : Android.Views.View
    {
        private string eventAction;
        private float getX, getY;
        private Paint pen;

        public TouchView(Context context) : base(context)
        {
            pen = new Paint();
            pen.Color = Color.Yellow;
            pen.TextSize = 30;
            eventAction = "";
        }

        protected override void OnDraw(Canvas canvas)
        {
            canvas.DrawText("Touch Event " + eventAction, 10, 100, pen);
            canvas.DrawText("Get " + getX + ',' + getY, 10, 150, pen);
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            eventAction = e.Action.ToString();
            getX = e.GetX();
            getY = e.GetY();

            Invalidate();
            return true;
        }
    }



4. 핀치(Pinch)
핀치(Pinch)란, 두 손가락을 사용해서 화면을 축소확대하는 기능을 말합니다. 그러기 위해서는 좌표를 두개 받을 수 있어야 합니다.

MotionEvent e의 프로퍼티 PointerCount가, 터치점이 몇개인지 받아오는 프로퍼티입니다. 두 손가락으로 터치하면 2, 세 손가락으로 터치하면 3, ..., 양 손 손가락을 다 동원하면 10도 될 수 있습니다.
그리고 각 손가락의 이벤트 위치는 e.GetX(int p), e.GetY(int p) 함수로 얻어올 수 있습니다.
그러므로 모든 터치입력을 받기 위해서는 다음과 같이 리스트를 사용해야 합니다.

    public class TouchView : Android.Views.View
    {
        private List<string> eventAction = new List<string>();
        private List<float> getX = new List<float>();
        private List<float> getY = new List<float>();
        private Paint pen;

        public TouchView(Context context) : base(context)
        {
            pen = new Paint();
            pen.Color = Color.Yellow;
            pen.TextSize = 30;
            for(int k = 0; k < 10; ++k)
                eventAction.Add("");
        }

        protected override void OnDraw(Canvas canvas)
        {
            int row = 100;
            foreach (var e in eventAction)
            {
                canvas.DrawText("Touch Event [" + e + "] ", 10, row, pen);
                row += 50;
            }

            row += 50;

            for (int k = 0; k < getX.Count; ++k)
            {
                canvas.DrawText("Get " + getX[k] + ',' + getY[k], 10, row, pen);
                row += 50;
            }
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            eventAction.RemoveAt(0);
            eventAction.Add(e.Action.ToString() + ' ' + e.PointerCount.ToString());

            getX.Clear();
            getY.Clear();

            for (int k = 0; k < e.PointerCount; ++k)
            {
                getX.Add(e.GetX(k));
                getY.Add(e.GetY(k));
            }

            Invalidate();
            return true;
        }
    }

이 앱을 폰으로 옮겨 실행한 결과입니다.


조금 낯선 이벤트가 있네요. Pointer1Up, Pointer2Up 같은 것 말입니다.
폰에서는 손가락을 고정시켜도 Move이벤트가 계속 들어오므로 Move이벤트는 빼고, 차례로 6개의 손가락을 터치했다가 다시 하나씩 뗀 결과입니다.



보시다시피 차례로 Down(손가락 터치), Pointer2Down(두번째 손가락 터치), Pointer3Down(세번째 손가락 터치) 순으로 들어오는 것을 알 수 있습니다. 이후의 숫자들은 Enum이 정의되어 있지 않은 것이고 말입니다.
그리고 손가락을 뗄 때는 몇번째로 터치했던 손가락이 떨어졌는지가 Pointer?Up의 형태로 오는 모양네요.
뭐 스마트폰 쓰면서 3개의 터치도 필요한 적이 없으니 그 이상의 Enum을 정하지 않은 것이겠죠.

댓글 없음:

댓글 쓰기