Xamarin.Formsでタッチイベントを取得したときの話

#Xamarin.FormでView内のタッチイベントを取得する方法
Xamarinでアプリ開発をしていたとき「タッチイベント」を取得したかったのですが、Xamarin初心者にとっては少し難しい部分かと思うので参考になればとメモとして書き残しておきます。
※[こちら](https://younaship.com/2019/03/07/xamarin%e3%81%a7%e3%82%bf%e3%83%83%e3%83%81%e3%82%a4%e3%83%99%e3%83%b3%e3%83%88%e3%82%92%e5%8f%96%e5%be%97%e3%81%97%e3%81%9f%e6%99%82%e3%81%ae%e8%a9%b1/)とほとんど同じ内容になっています。

##取得した情報を入れるクラスを定義
```C#:TouchEvents.cs
    public class TouchEventArgs : EventArgs
    {
        public enum TouchEventType
        {
            Entered,
            Pressed,
            Moved,
            Released,
            Exited,
            Cancelled
        }
        public TouchEventArgs(long id,TouchEventType type,Vec2 pos)
        {
            Id = id;
            Type = type;
            Pos = pos;
        }
        public long Id { get; private set; }
        public TouchEventType Type { get; private set; }
        public Vec2 Pos { get; private set; }
    }
```
タッチされた指の識別番号を入れるためのid(long)、タッチイベントの種類を入れるためのtype(TouchEventType)、座標情報を入れるためのPos(Forms.Vec2)を定義しました。
取得する情報はViewに対する相対座標の為、汎用性を高くするために絶対座標を入れるVec2も定義してもいいかもしれません。

##デリゲートを定義
```C#:TouchEvents.cs
public delegate void TouchEventHundler(object obj, TouchEventArgs args);
```
イベント呼び出し用のデリゲートも定義します。

##Effectを定義
Xamlから呼び出すためのクラスを定義します。
今回はEffectを用いるため、RoutingEffectを継承します。

```C#:
    public class TEffect : RoutingEffect
    {
        public TEffect() : base("Effects.TouchEffect")
        {
        }
        public event TouchEventHundler OnTouch;
        public void OnTouchEvent(object obj,TouchEventArgs args)
        {
            OnTouch?.Invoke(obj, args);
        }
    }
```

##[Android用]
```C#:
[assembly: ResolutionGroupName("Effects")]
[assembly: ExportEffect(typeof(TouchEffect), "TouchEffect")]
namespace Test.Droid
{
    class TouchEffect : PlatformEffect
    {
        Android.Views.View view;
        Element element;
        TEffect tEffect;

        static Dictionary<Android.Views.View, TouchEffect> list = new Dictionary<Android.Views.View, TouchEffect>();

        protected override void OnAttached()
        {
            view = Control == null ? Container : Control;
            element = Element;
            if (view != null)
            {
                view.Touch += OnTouch;
                list.Add(view, this);
                tEffect = (TEffect)element.Effects.FirstOrDefault(e => e is TEffect);
            }
        }

        protected override void OnDetached()
        {
            if (list.ContainsKey(view))
            {
                view.Touch -= OnTouch;
                list.Remove(view);
            }
        }

        private void OnTouch(object obj, Android.Views.View.TouchEventArgs ev)
        {
                int actID = ev.Event.ActionIndex;
                int pointID = ev.Event.GetPointerId(actID);
                float x = ev.Event.GetX(actID);
                float y = ev.Event.GetY(actID);

                switch(ev.Event.Action){
                    //ここに各イベントごとの呼び出し処理を書く 
                }
        }
    }

}
```
これでタッチイベントが発生するたびにOnTouch()が呼ばれます。
ev.Event.ActionにMotionEventActions型でイベントタイプが入っているのでこれをオリジナルの型「TouchEventType」に変える処理もここに書きます。

##使い方
###Xmal上で使う例

```xml:
<ContentsPage xmlns:t="clr-namespace:MyTouchEffect">
        <Grid>
            <BoxView BackgroundColor="Red"/>
            <Grid.Effects>
                <t:TEffect OnTouch="TEffect_OnTouch"/>
            </Grid.Effects>
        </Grid>
```
こんな感じで使います。
Gridで重ねて使うのがおススメ(かつ定番？)だと思います。
namespaceは自分の環境に合わせてお使いください。

##最後に
Qiitaでの初めての記事になるので書き方おかしいかもしれませんが悪しからず。。。
いつもは[こちら](https://younaship.com)で記事を書いてます。
変なところあったり、書き方のアドバイス等ありましたらコメントくれると助かりますm(_ _)m