Xamarin.Forms实现touch事件
Xamarin.Forms的View没有touch事件,只能自己实现
首先,在共享项目里面,放入这几个类,结构大概是这样的:
using System;
using Xamarin.Forms; namespace TouchTracking
{
public class TouchActionEventArgs : EventArgs
{
public TouchActionEventArgs(long id, TouchActionType type, Point location, bool isInContact)
{
Id = id;
Type = type;
Location = location;
IsInContact = isInContact;
} public long Id { private set; get; } public TouchActionType Type { private set; get; } public Point Location { private set; get; } public bool IsInContact { private set; get; }
}
}
namespace TouchTracking
{
public delegate void TouchActionEventHandler(object sender, TouchActionEventArgs args);
}
namespace TouchTracking
{
public enum TouchActionType
{
Entered,
Pressed,
Moved,
Released,
Exited,
Cancelled
}
}
using Xamarin.Forms; namespace TouchTracking
{
public class TouchEffect : RoutingEffect
{
public event TouchActionEventHandler TouchAction; public TouchEffect() : base("XamarinDocs.TouchEffect")
{
} public bool Capture { set; get; } public void OnTouchAction(Element element, TouchActionEventArgs args)
{
TouchAction?.Invoke(element, args);
}
}
}
using System;
using SkiaSharp;
using TouchTracking; namespace SkiaSharpFormsDemos
{
public class TouchPoint
{
// For painting
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill
}; // For dragging
bool isBeingDragged;
long touchId;
SKPoint previousPoint; public TouchPoint()
{
} public TouchPoint(float x, float y)
{
Center = new SKPoint(x, y);
} public SKPoint Center { set; get; } public float Radius { set; get; } = ; public SKColor Color { set; get; } = new SKColor(, , , ); public void Paint(SKCanvas canvas)
{
paint.Color = Color;
canvas.DrawCircle(Center.X, Center.Y, Radius, paint);
} public bool ProcessTouchEvent(long id, TouchActionType type, SKPoint location)
{
bool centerMoved = false; // Assumes Capture property of TouchEffect is true!
switch (type)
{
case TouchActionType.Pressed:
if (!isBeingDragged && PointInCircle(location))
{
isBeingDragged = true;
touchId = id;
previousPoint = location;
centerMoved = false;
}
break; case TouchActionType.Moved:
if (isBeingDragged && touchId == id)
{
Center += location - previousPoint;
previousPoint = location;
centerMoved = true;
}
break; case TouchActionType.Released:
if (isBeingDragged && touchId == id)
{
Center += location - previousPoint;
isBeingDragged = false;
centerMoved = true;
}
break; case TouchActionType.Cancelled:
isBeingDragged = false;
break;
}
return centerMoved;
} bool PointInCircle(SKPoint pt)
{
return (Math.Pow(pt.X - Center.X, ) + Math.Pow(pt.Y - Center.Y, )) < (Radius * Radius);
}
}
}
然后,在android的项目里面,加入这个类
using System;
using System.Collections.Generic;
using System.Linq; using Xamarin.Forms;
using Xamarin.Forms.Platform.Android; using Android.Views; [assembly: ResolutionGroupName("XamarinDocs")]
[assembly: ExportEffect(typeof(TouchTracking.Droid.TouchEffect), "TouchEffect")] namespace TouchTracking.Droid
{
public class TouchEffect : PlatformEffect
{
Android.Views.View view;
Element formsElement;
TouchTracking.TouchEffect libTouchEffect;
bool capture;
Func<double, double> fromPixels;
int[] twoIntArray = new int[]; static Dictionary<Android.Views.View, TouchEffect> viewDictionary =
new Dictionary<Android.Views.View, TouchEffect>(); static Dictionary<int, TouchEffect> idToEffectDictionary =
new Dictionary<int, TouchEffect>(); protected override void OnAttached()
{
// Get the Android View corresponding to the Element that the effect is attached to
view = Control == null ? Container : Control; // Get access to the TouchEffect class in the .NET Standard library
TouchTracking.TouchEffect touchEffect =
(TouchTracking.TouchEffect)Element.Effects.
FirstOrDefault(e => e is TouchTracking.TouchEffect); if (touchEffect != null && view != null)
{
viewDictionary.Add(view, this); formsElement = Element; libTouchEffect = touchEffect; // Save fromPixels function
fromPixels = view.Context.FromPixels; // Set event handler on View
view.Touch += OnTouch;
}
} protected override void OnDetached()
{
if (viewDictionary.ContainsKey(view))
{
viewDictionary.Remove(view);
view.Touch -= OnTouch;
}
} void OnTouch(object sender, Android.Views.View.TouchEventArgs args)
{
// Two object common to all the events
Android.Views.View senderView = sender as Android.Views.View;
MotionEvent motionEvent = args.Event; // Get the pointer index
int pointerIndex = motionEvent.ActionIndex; // Get the id that identifies a finger over the course of its progress
int id = motionEvent.GetPointerId(pointerIndex); senderView.GetLocationOnScreen(twoIntArray);
Point screenPointerCoords = new Point(twoIntArray[] + motionEvent.GetX(pointerIndex),
twoIntArray[] + motionEvent.GetY(pointerIndex)); // Use ActionMasked here rather than Action to reduce the number of possibilities
switch (args.Event.ActionMasked)
{
case MotionEventActions.Down:
case MotionEventActions.PointerDown:
FireEvent(this, id, TouchActionType.Pressed, screenPointerCoords, true); idToEffectDictionary.Add(id, this); capture = libTouchEffect.Capture;
break; case MotionEventActions.Move:
// Multiple Move events are bundled, so handle them in a loop
for (pointerIndex = ; pointerIndex < motionEvent.PointerCount; pointerIndex++)
{
id = motionEvent.GetPointerId(pointerIndex); if (capture)
{
senderView.GetLocationOnScreen(twoIntArray); screenPointerCoords = new Point(twoIntArray[] + motionEvent.GetX(pointerIndex),
twoIntArray[] + motionEvent.GetY(pointerIndex)); FireEvent(this, id, TouchActionType.Moved, screenPointerCoords, true);
}
else
{
CheckForBoundaryHop(id, screenPointerCoords); if (idToEffectDictionary[id] != null)
{
FireEvent(idToEffectDictionary[id], id, TouchActionType.Moved, screenPointerCoords, true);
}
}
}
break; case MotionEventActions.Up:
case MotionEventActions.Pointer1Up:
if (capture)
{
FireEvent(this, id, TouchActionType.Released, screenPointerCoords, false);
}
else
{
CheckForBoundaryHop(id, screenPointerCoords); if (idToEffectDictionary[id] != null)
{
FireEvent(idToEffectDictionary[id], id, TouchActionType.Released, screenPointerCoords, false);
}
}
idToEffectDictionary.Remove(id);
break; case MotionEventActions.Cancel:
if (capture)
{
FireEvent(this, id, TouchActionType.Cancelled, screenPointerCoords, false);
}
else
{
if (idToEffectDictionary[id] != null)
{
FireEvent(idToEffectDictionary[id], id, TouchActionType.Cancelled, screenPointerCoords, false);
}
}
idToEffectDictionary.Remove(id);
break;
}
} void CheckForBoundaryHop(int id, Point pointerLocation)
{
TouchEffect touchEffectHit = null; foreach (Android.Views.View view in viewDictionary.Keys)
{
// Get the view rectangle
try
{
view.GetLocationOnScreen(twoIntArray);
}
catch // System.ObjectDisposedException: Cannot access a disposed object.
{
continue;
}
Rectangle viewRect = new Rectangle(twoIntArray[], twoIntArray[], view.Width, view.Height); if (viewRect.Contains(pointerLocation))
{
touchEffectHit = viewDictionary[view];
}
} if (touchEffectHit != idToEffectDictionary[id])
{
if (idToEffectDictionary[id] != null)
{
FireEvent(idToEffectDictionary[id], id, TouchActionType.Exited, pointerLocation, true);
}
if (touchEffectHit != null)
{
FireEvent(touchEffectHit, id, TouchActionType.Entered, pointerLocation, true);
}
idToEffectDictionary[id] = touchEffectHit;
}
} void FireEvent(TouchEffect touchEffect, int id, TouchActionType actionType, Point pointerLocation, bool isInContact)
{
// Get the method to call for firing events
Action<Element, TouchActionEventArgs> onTouchAction = touchEffect.libTouchEffect.OnTouchAction; // Get the location of the pointer within the view
touchEffect.view.GetLocationOnScreen(twoIntArray);
double x = pointerLocation.X - twoIntArray[];
double y = pointerLocation.Y - twoIntArray[];
Point point = new Point(fromPixels(x), fromPixels(y)); // Call the method
onTouchAction(touchEffect.formsElement,
new TouchActionEventArgs(id, actionType, point, isInContact));
}
}
}
然后,在ios的项目里面,加入这个类
using System;
using System.Linq; using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS; using System.Collections.Generic; using CoreGraphics;
using Foundation;
using UIKit; [assembly: ResolutionGroupName("XamarinDocs")]
[assembly: ExportEffect(typeof(TouchTracking.iOS.TouchEffect), "TouchEffect")] namespace TouchTracking.iOS
{
public class TouchEffect : PlatformEffect
{
UIView view;
TouchRecognizer touchRecognizer; protected override void OnAttached()
{
// Get the iOS UIView corresponding to the Element that the effect is attached to
view = Control == null ? Container : Control; // Get access to the TouchEffect class in the .NET Standard library
TouchTracking.TouchEffect effect = (TouchTracking.TouchEffect)Element.Effects.FirstOrDefault(e => e is TouchTracking.TouchEffect); if (effect != null && view != null)
{
// Create a TouchRecognizer for this UIView
touchRecognizer = new TouchRecognizer(Element, view, effect);
view.AddGestureRecognizer(touchRecognizer);
}
} protected override void OnDetached()
{
if (touchRecognizer != null)
{
// Clean up the TouchRecognizer object
touchRecognizer.Detach(); // Remove the TouchRecognizer from the UIView
view.RemoveGestureRecognizer(touchRecognizer);
}
}
} class TouchRecognizer : UIGestureRecognizer
{
Element element; // Forms element for firing events
UIView view; // iOS UIView
TouchTracking.TouchEffect touchEffect;
bool capture; static Dictionary<UIView, TouchRecognizer> viewDictionary =
new Dictionary<UIView, TouchRecognizer>(); static Dictionary<long, TouchRecognizer> idToTouchDictionary =
new Dictionary<long, TouchRecognizer>(); public TouchRecognizer(Element element, UIView view, TouchTracking.TouchEffect touchEffect)
{
this.element = element;
this.view = view;
this.touchEffect = touchEffect; viewDictionary.Add(view, this);
} public void Detach()
{
viewDictionary.Remove(view);
} // touches = touches of interest; evt = all touches of type UITouch
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt); foreach (UITouch touch in touches.Cast<UITouch>())
{
long id = touch.Handle.ToInt64();
FireEvent(this, id, TouchActionType.Pressed, touch, true); if (!idToTouchDictionary.ContainsKey(id))
{
idToTouchDictionary.Add(id, this);
}
} // Save the setting of the Capture property
capture = touchEffect.Capture;
} public override void TouchesMoved(NSSet touches, UIEvent evt)
{
base.TouchesMoved(touches, evt); foreach (UITouch touch in touches.Cast<UITouch>())
{
long id = touch.Handle.ToInt64(); if (capture)
{
FireEvent(this, id, TouchActionType.Moved, touch, true);
}
else
{
CheckForBoundaryHop(touch); if (idToTouchDictionary[id] != null)
{
FireEvent(idToTouchDictionary[id], id, TouchActionType.Moved, touch, true);
}
}
}
} public override void TouchesEnded(NSSet touches, UIEvent evt)
{
base.TouchesEnded(touches, evt); foreach (UITouch touch in touches.Cast<UITouch>())
{
long id = touch.Handle.ToInt64(); if (capture)
{
FireEvent(this, id, TouchActionType.Released, touch, false);
}
else
{
CheckForBoundaryHop(touch); if (idToTouchDictionary[id] != null)
{
FireEvent(idToTouchDictionary[id], id, TouchActionType.Released, touch, false);
}
}
idToTouchDictionary.Remove(id);
}
} public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
base.TouchesCancelled(touches, evt); foreach (UITouch touch in touches.Cast<UITouch>())
{
long id = touch.Handle.ToInt64(); if (capture)
{
FireEvent(this, id, TouchActionType.Cancelled, touch, false);
}
else if (idToTouchDictionary[id] != null)
{
FireEvent(idToTouchDictionary[id], id, TouchActionType.Cancelled, touch, false);
}
idToTouchDictionary.Remove(id);
}
} void CheckForBoundaryHop(UITouch touch)
{
long id = touch.Handle.ToInt64(); // TODO: Might require converting to a List for multiple hits
TouchRecognizer recognizerHit = null; foreach (UIView view in viewDictionary.Keys)
{
CGPoint location = touch.LocationInView(view); if (new CGRect(new CGPoint(), view.Frame.Size).Contains(location))
{
recognizerHit = viewDictionary[view];
}
}
if (recognizerHit != idToTouchDictionary[id])
{
if (idToTouchDictionary[id] != null)
{
FireEvent(idToTouchDictionary[id], id, TouchActionType.Exited, touch, true);
}
if (recognizerHit != null)
{
FireEvent(recognizerHit, id, TouchActionType.Entered, touch, true);
}
idToTouchDictionary[id] = recognizerHit;
}
} void FireEvent(TouchRecognizer recognizer, long id, TouchActionType actionType, UITouch touch, bool isInContact)
{
// Convert touch location to Xamarin.Forms Point value
CGPoint cgPoint = touch.LocationInView(recognizer.View);
Point xfPoint = new Point(cgPoint.X, cgPoint.Y); // Get the method to call for firing events
Action<Element, TouchActionEventArgs> onTouchAction = recognizer.touchEffect.OnTouchAction; // Call that method
onTouchAction(recognizer.element,
new TouchActionEventArgs(id, actionType, xfPoint, isInContact));
}
}
}
然后,在UWP的项目里面,加入这个类
using System;
using System.Linq;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP; [assembly: ResolutionGroupName("XamarinDocs")]
[assembly: ExportEffect(typeof(TouchTracking.UWP.TouchEffect), "TouchEffect")] namespace TouchTracking.UWP
{
public class TouchEffect : PlatformEffect
{
FrameworkElement frameworkElement;
TouchTracking.TouchEffect effect;
Action<Element, TouchActionEventArgs> onTouchAction; protected override void OnAttached()
{
// Get the Windows FrameworkElement corresponding to the Element that the effect is attached to
frameworkElement = Control == null ? Container : Control; // Get access to the TouchEffect class in the .NET Standard library
effect = (TouchTracking.TouchEffect)Element.Effects.
FirstOrDefault(e => e is TouchTracking.TouchEffect); if (effect != null && frameworkElement != null)
{
// Save the method to call on touch events
onTouchAction = effect.OnTouchAction; // Set event handlers on FrameworkElement
frameworkElement.PointerEntered += OnPointerEntered;
frameworkElement.PointerPressed += OnPointerPressed;
frameworkElement.PointerMoved += OnPointerMoved;
frameworkElement.PointerReleased += OnPointerReleased;
frameworkElement.PointerExited += OnPointerExited;
frameworkElement.PointerCanceled += OnPointerCancelled;
}
} protected override void OnDetached()
{
if (onTouchAction != null)
{
// Release event handlers on FrameworkElement
frameworkElement.PointerEntered -= OnPointerEntered;
frameworkElement.PointerPressed -= OnPointerPressed;
frameworkElement.PointerMoved -= OnPointerMoved;
frameworkElement.PointerReleased -= OnPointerReleased;
frameworkElement.PointerExited -= OnPointerEntered;
frameworkElement.PointerCanceled -= OnPointerCancelled;
}
} void OnPointerEntered(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Entered, args);
} void OnPointerPressed(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Pressed, args); // Check setting of Capture property
if (effect.Capture)
{
(sender as FrameworkElement).CapturePointer(args.Pointer);
}
} void OnPointerMoved(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Moved, args);
} void OnPointerReleased(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Released, args);
} void OnPointerExited(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Exited, args);
} void OnPointerCancelled(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Cancelled, args);
} void CommonHandler(object sender, TouchActionType touchActionType, PointerRoutedEventArgs args)
{
PointerPoint pointerPoint = args.GetCurrentPoint(sender as UIElement);
Windows.Foundation.Point windowsPoint = pointerPoint.Position; onTouchAction(Element, new TouchActionEventArgs(args.Pointer.PointerId,
touchActionType,
new Point(windowsPoint.X, windowsPoint.Y),
args.Pointer.IsInContact));
}
}
}
这样,自定义的touch事件就完成了
在共享项目的xaml里面,类似这样即可使用:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
xmlns:tt="clr-namespace:TouchTracking"
x:Class="App1.MainPage"> <Grid x:Name="p1" BackgroundColor="Aquamarine">
<Grid.Effects>
<tt:TouchEffect Capture="True" TouchAction="OnTouchEffectAction" />
</Grid.Effects> </Grid> </ContentPage>
Xamarin.Forms实现touch事件的更多相关文章
- 菜鸟的Xamarin.Forms前行之路——按钮的按下抬起事件的监控(可扩展至其他事件)
提问:监控按钮的点击事件,可以通过按钮的Click事件,或者Command绑定,那么如何监控按钮的按下与抬起,或者移动,长按,双击等事件? 解决方法:各个平台自定义渲染依赖注入. 共享项目PCL: 1 ...
- Xamarin.Forms中的ListView的ItemTrapped事件与ItemSelected事件的区别
今天对Xamarin.Forms中的ListView的两个事件(ItemTrapped和ItemSelected)做了小小的研究,发现有以下几点区别: 1.ItemTrapped事件会优先被触发. 2 ...
- Xamarin.Forms介绍
On May 28, 2014, Xamarin introduced Xamarin.Forms, which allows you to write user-interface code tha ...
- Xamarin.Forms 开发资源集合(复制)
复制:https://www.cnblogs.com/mschen/p/10199997.html 收集整理了下 Xamarin.Forms 的学习参考资料,分享给大家,稍后会不断补充: UI样式 S ...
- Xamarin.Forms 开发资源集合
收集整理了下 Xamarin.Forms 的学习参考资料,分享给大家,稍后会不断补充: UI样式 Snppts: Xamarin Forms UI Snippets. Prebuilt Templat ...
- Xamarin.Forms 简介
An Introduction to Xamarin.Forms 来源:http://developer.xamarin.com/guides/cross-platform/xamarin-forms ...
- Xamarin.Forms入门-使用 Xamarin.Forms 来创建跨平台的用户界面
Xamarin.Forms 是一个跨平台的.基于原生控件的UI工具包,开发人员可以轻松的创建适用于 Android,iOS 以及 Windows Phone的用户界面.Xamarin.Forms 通过 ...
- 演练:使用Xamarin.Forms开发产品介绍性质的应用(VB版)
概述 Xamarin这个使用mono和.net core的跨平台开发框架这几年在不断发展.被微软收购后的Xamarin为个人开发者提供了免费版的Xamarin for Visual Studio,吸引 ...
- Xamarin.Forms——WebView技术研究
在Xamarin中有一些Forms原生不太好实现的内容可以考虑使用HTML.Javascript.CSS那一套前端技术来实现,使用WebView来承载显示本地或网络上的HTML文件.不像OpenUri ...
随机推荐
- python基础学习之02 序列
#encoding=utf-8 import math a=[1,23,4,5,6] print a a[1:1]=[2,3,5] print a a a[1]='a' print a a[1]={1 ...
- HDU 5305 Friends(dfs)
Friends Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Su ...
- Codeforces Round #319 (Div. 1)C. Points on Plane 分块思想
C. Points on Plane On a pl ...
- Android分包MultiDex原理详解
MultiDex的产生背景 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的 ...
- git分支的合并和冲突解决【转】
本文转载自:http://blog.csdn.net/Kingson_Wu/article/details/39227611 http://gitbook.liuhui998.com/3_3.html ...
- 简单动态规划——最长公共子序列&&最长回文子序列&&最长上升||下降子序列
最长公共子序列,顾名思义当然是求两个字符串的最长公共子序列啦,当然,这只是一道非常菜的动规,所以直接附上代码: #include<iostream> #include<cstdio& ...
- bzoj1833
http://www.lydsy.com/JudgeOnline/problem.php?id=1833 2.5个小时就花在这上面了... 水到200题了...然并卵,天天做水题有什么前途... #i ...
- linux安装 pip和setuptools
安装 setuptools wget http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg sh s ...
- c3p0-config.xml文件简单说明与备忘
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <named-confi ...
- gulp的使用安装
gulp安装:用cnpm的时候把npm换成cnpm就好了. npm install -g gulp(全局安装,安装一次就好) npm install --save-dev gulp(安装到项目目录下, ...