在 Xamarin.Form 下擴充套件手勢
一 手勢基礎(Android & iOS)
> Andorid手勢基礎
當用戶觸控式螢幕幕時會產生很多的觸控事件,down、up、move等等。View類有個View.OnTouchListener內部介面,通過重寫他的onTouch(View v, MotionEvent event)方法,我們可以處理一些touch事件,如下:
[java] view plain copy
print?
public class MainActivity extends Activity {
...
// This example shows an Activity, but you would use the same approach if
// you were subclassing a View.
@Override
public boolean onTouchEvent(MotionEvent event){
int action = MotionEventCompat.getActionMasked(event);
switch(action) {
case (MotionEvent.ACTION_DOWN) :
Log.d(DEBUG_TAG,"Action was DOWN");
return true;
case (MotionEvent.ACTION_MOVE) :
Log.d(DEBUG_TAG,"Action was MOVE");
return true;
case (MotionEvent.ACTION_UP) :
Log.d(DEBUG_TAG,"Action was UP");
return true;
case (MotionEvent.ACTION_CANCEL) :
Log.d(DEBUG_TAG,"Action was CANCEL");
return true;
case (MotionEvent.ACTION_OUTSIDE) :
Log.d(DEBUG_TAG,"Movement occurred outside bounds " +
"of current screen element");
return true;
default :
return super.onTouchEvent(event);
}
}
OnTouch提供的事件還是相對較簡單,如果需要處理一些複雜的手勢,用這個介面就會很麻煩,因為我們要根據使用者觸控的軌跡去判斷是什麼手勢。Android sdk給我們提供了GestureDetector(Gesture:手勢Detector:識別)類,通過這個類我們可以識別很多的手勢。
public class GestureDetector extends Object
Java.lang.Object
android.view.GestureDetector
GestureDetector屬於android.view包,android還提供了android.gesture包支援更多的手勢操作,以後我們會介紹到。官方的介紹中使用了GestureDetectorCompat處理手勢識別,為什麼使用GestureDetectorCompat替換了GestureDetector呢,官方的是這樣解釋的:
GestureDetectorCompat例項化有下面兩種方法:
GestureDetector
GestureDetector類對外提供了兩個介面:OnGestureListener,OnDoubleTapListener,還有一個內部類SimpleOnGestureListener;SimpleOnGestureListener類是GestureDetector提供給我們的一個更方便的響應不同手勢的類,它實現了上述兩個介面,該類是static class,也就是說它實際上是一個外部類,我們可以在外部繼承這個類,重寫裡面的手勢處理方法。因此實現手勢識別有兩種方法,一種實現OnGestureListener介面,另一種是使用SimpleOnGestureListener類。
OnGestureListener有下面的幾個動作:
按下(onDown): 剛剛手指接觸到觸控式螢幕的那一剎那,就是觸的那一下。
拋擲(onFling): 手指在觸控式螢幕上迅速移動,並鬆開的動作。
長按(onLongPress): 手指按在持續一段時間,並且沒有鬆開。
滾動(onScroll): 手指在觸控式螢幕上滑動。
按住(onShowPress): 手指按在觸控式螢幕上,它的時間範圍在按下起效,在長按之前。
擡起(onSingleTapUp):手指離開觸控式螢幕的那一剎那。
使用OnGestureListener介面,這樣需要過載OnGestureListener介面所有的方法,適合監聽所有的手勢,正如官方文件提到的“Detecing All Supported Gestures
=========================================================================
>iOS 手勢基礎
UIGestureRecognize手勢識別器的使用簡介
手勢識別器是一個抽象類, 特殊的觸控事件. 我們不使用它本身,而是使用它的子類
型別
類 名
平移
UIPanGestureRecognizer
輕掃(滑動)
UISwipeGestureRecognizer
長按
UILongPressGestureRecognizer
捏合
UIPinchGestureRecognizer
旋轉
UIRotationGestureRecognizer
輕拍
UITapGestureRecognizer
二 實戰(ps:下面以自定義以為XF定義以隨便一個手勢為例:)
XF部分:
using System;
using Xamarin.Forms;
namespace KKMobile.Control
{
public class LongPressMaskingView : Xamarin.Forms.Grid
{
public event EventHandler LongPressActivated;
public event EventHandler LongPressEnd;
public event EventHandler TapUPed;
public LongPressMaskingView()
{
}
public void HandTapUped(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
if (TapUPed != null)
{
TapUPed(this, new EventArgs());
}
});
}
public void HandleLongPress_End(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
if (LongPressEnd != null)
{
LongPressEnd(this, new EventArgs());
}
});
}
public void HandleLongPress(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
if (LongPressActivated != null)
{
System.Diagnostics.Debug.WriteLine("HandleLongPress");
LongPressActivated(this, new EventArgs());
}
});
}
#region 繫結手勢
// public static readonly BindableProperty TappedCommandProperty =
//BindableProperty.Create(nameof(TappedCommand),
// typeof(ICommand),
// typeof(LongPressGerCachImage),
// default(ICommand));
// public ICommand TappedCommand
// {
// get { return (ICommand)GetValue(TappedCommandProperty); }
// set { SetValue(TappedCommandProperty, value); }
// }
// public static readonly BindableProperty LongPressCommandProperty =
// BindableProperty.Create(nameof(LongPressCommand),
// typeof(ICommand),
// typeof(LongPressGerCachImage),
// default(ICommand));
// public ICommand LongPressCommand
// {
// get { return (ICommand)GetValue(LongPressCommandProperty); }
// set { SetValue(LongPressCommandProperty, value); }
// }
// public LongPressGerCachImage() { }
#endregion
}
}
===============================================================================
Xamarin.iOS 實現
using System;
using Foundation;
using UIKit;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using KKMobile.Control;
using KKMobile.iOS.Renderer;
[assembly: ExportRenderer(typeof(LongPressMaskingView), typeof(LongPressMaskingViewRenderer))]
namespace KKMobile.iOS.Renderer
{
public class LongPressMaskingViewRenderer : ViewRenderer
{
LongPressMaskingView view;
UILongPressGestureRecognizer longPressGer { get; set; }
UITapGestureRecognizer TapGer { get; set; }
public LongPressMaskingViewRenderer()
{
longPressGer = new UILongPressGestureRecognizer((longPress) =>
{
if (longPress.State == UIGestureRecognizerState.Began)
{
view.HandleLongPress(view, new EventArgs());
}
if (longPress.State == UIGestureRecognizerState.Ended)
{
view.HandleLongPress_End(view, new EventArgs());
}
})
{ MinimumPressDuration = 0.5, NumberOfTouchesRequired = 1 };
//**
TapGer = new UITapGestureRecognizer((Tap) =>
{
if (Tap.State == UIGestureRecognizerState.Ended)
{
view.HandTapUped(view,new EventArgs());
}
}) { };
this.AddGestureRecognizer(TapGer);
this.AddGestureRecognizer(longPressGer);
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
view = e.NewElement as LongPressMaskingView;
}
if (e.NewElement == null)
{
if (longPressGer != null)
{
this.RemoveGestureRecognizer(longPressGer);
}
}
if (e.OldElement == null)
{
this.AddGestureRecognizer(longPressGer);
}
}
//UITapGestureRecognizer tapGesturesRecognizer;
//UILongPressGestureRecognizer longPressGesturesRecognizer;
//protected override void OnElementChanged(ElementChangedEventArgs<View> e)
//{
// base.OnElementChanged(e);
// tapGesturesRecognizer = new UITapGestureRecognizer(() =>
// {
// var grid = (LongPressGerCachImage)Element;
// if (grid.TappedCommand.CanExecute(Element.BindingContext))
// {
// grid.TappedCommand.Execute(Element.BindingContext);
// }
// });
// longPressGesturesRecognizer = new UILongPressGestureRecognizer(() =>
// {
// var grid = (LongPressGerCachImage)Element;
// if (longPressGesturesRecognizer.State == UIGestureRecognizerState.Ended &&
// grid.LongPressCommand.CanExecute(Element.BindingContext))
// {
// grid.LongPressCommand.Execute(Element.BindingContext);
// }
// });
// this.RemoveGestureRecognizer(tapGesturesRecognizer);
// this.RemoveGestureRecognizer(longPressGesturesRecognizer);
// this.AddGestureRecognizer(tapGesturesRecognizer);
// this.AddGestureRecognizer(longPressGesturesRecognizer);
//}
}
}
-----------
===============================================================================
Xamarin.Android實現
一》先建立一個手勢事件監聽類
sing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace KKMobile.Droid.Renderer
{
public class FancyGestureListener : GestureDetector.SimpleOnGestureListener
{
public event EventHandler HandTapUped;
public override bool OnSingleTapUp(MotionEvent e) //擡起(onSingleTapUp):手指離開觸 摸屏的那一剎那。
{
HandTapUped(this, null);
return true;
}
}
}
二》建立安卓手勢Render類
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using Android.Views;
using KKMobile.Droid.Renderer;
using KKMobile.Control;
using System;
[assembly: ExportRenderer(typeof(LongPressMaskingView), typeof(LongPressMaskingViewRenderer_Droid))]
namespace KKMobile.Droid.Renderer
{
public class LongPressMaskingViewRenderer_Droid : ViewRenderer
{
LongPressMaskingView _longPressMaskingView;
private readonly FancyGestureListener _listener;
private readonly GestureDetector _detector;
public LongPressMaskingViewRenderer_Droid()
{
_listener = new FancyGestureListener();
_detector = new GestureDetector(_listener);
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
_longPressMaskingView = e.NewElement as LongPressMaskingView;
}
if (e.NewElement == null)
{
this.GenericMotion -= HandleGenericMotion;
this.Touch -= HandleTouch;
//_listener.HandleLongPress -= OnHandLongPress;
//_listener.HandLongPressEnded -= OnHandLongPressEnded;
_listener.HandTapUped -= OnHandTapUped;
}
if (e.OldElement == null)
{
this.GenericMotion += HandleGenericMotion;
this.Touch += HandleTouch;
//_listener.HandleLongPress += OnHandLongPress;
//_listener.HandLongPressEnded += OnHandLongPressEnded;
_listener.HandTapUped += OnHandTapUped;
}
}
void HandleTouch(object sender, TouchEventArgs e)
{
Console.WriteLine("====="+e.Event.Action);
try
{
_longPressMaskingView = this.Element as LongPressMaskingView;
if (e.Event.Action == MotionEventActions.Down)
{
Console.WriteLine(e.Event.Action);
_longPressMaskingView.HandleLongPress(this, new System.EventArgs());
Console.WriteLine("--down--");
}
if (e.Event.Action == MotionEventActions.Up || e.Event.Action == MotionEventActions.Cancel)
{
Console.WriteLine(e.Event.Action);
_longPressMaskingView.HandleLongPress_End(this, new System.EventArgs());
Console.WriteLine("--up--");
}
_detector.OnTouchEvent(e.Event);
}
catch (Exception ex) {
}
}
void HandleGenericMotion(object sender, GenericMotionEventArgs e)
{
_detector.OnTouchEvent(e.Event);
}
void OnHandTapUped(object sender, EventArgs e)
{
_longPressMaskingView = this.Element as LongPressMaskingView;
_longPressMaskingView.HandTapUped(this, new System.EventArgs());
}
}
}