我有一个以编程方式创建的按钮
InfoBtn = _utilProvider.FloatingBtn("My Button"); //Returns Floating UIButton
InfoBtn.Frame = new CGRect((ScreenWidth / 2) - 22.5, ScreenHeight - 65, 55, 55);
View.Add(InfoBtn);
我想以编程方式向其添加拖放功能。问题是,Xamarin连接的事件不会让我以这种方式使用自定义事件处理程序,例如UIEvent
(直接从https://www.cocoanetics.com/2010/11/draggable-buttons-labels/ iOS示例转换):
InfoBtn.TouchDragInside += (btn, uievent) =>
{
var button = (UIButton)btn;
var e = (UIEvent)uievent; //ERROR: Can not convert type 'System.EventArgs' to 'UIKit.UIEvent'
// get the touch
UITouch touch = (UITouch)e.TouchesForView(button).AnyObject;
// get delta
CGPoint previousLocation = touch.PreviousLocationInView(button);
CGPoint location = touch.LocationInView(button);
nfloat delta_x = location.X - previousLocation.X;
nfloat delta_y = location.Y - previousLocation.Y;
// move button
button.Center = new CGPoint(button.Center.X + delta_x, button.Center.Y + delta_y);
};
根据Xamarin对Using Touch in iOS
https://developer.xamarin.com/guides/ios/application_fundamentals/touch/ios_touch_walkthrough/的示例,他们使用了故事板。
创建了自定义UIViewController
partial class TouchViewController : UIViewController
并通过设置自定义类
分配给ViewController<viewController id="18" sceneMemberID="viewController" customClass="TouchViewController">
如何以编程方式设置customClass
?
我还尝试添加UIGestureRecognizer
InfoBtn.AddGestureRecognizer(new MyGestureRecognizer());
partial class MyGestureRecognizer : UIGestureRecognizer
{
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
// Touch started
}
}
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
base.TouchesCancelled(touches, evt);
}
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
base.TouchesEnded(touches, evt);
}
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
base.TouchesMoved(touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
// move the shape
}
}
}
但它只进入TouchesBegan
方法。
在基本上尝试在线发现每个教程后,我感到很沮丧。
非常感谢任何帮助
答案 0 :(得分:1)
好的,我使用https://github.com/TwoRedCells/UIDragDropGestureRecognizer-Xamarin.iOS
让它工作我稍微修改了一下类,这是工作代码:
ViewDidLoad()
中的:
InfoBtn = _utilProvider.FloatingBtn("My Button"); //Returns Floating UIButton
var dd = new DragDropGestureRecognizer();
dd.Dragging += (object sender, DragDropEventArgs e) =>
{
var view = ((DragDropGestureRecognizer)sender).View;
// Reposition box.
var x = e.ViewWasAt.X + e.Delta.X;
var y = e.ViewWasAt.Y + e.Delta.Y;
view.Center = new CGPoint(x, y);
};
InfoBtn.AddGestureRecognizer(dd);
InfoBtn.TouchUpInside += async (object sender, EventArgs e) =>
{
//Button On Click
};
InfoBtn.Frame = new CGRect((ScreenWidth / 2) - 22.5, ScreenHeight - 65, 55, 55);
View.Add(InfoBtn);
添加了一个与我的应用程序具有相同名称空间的类DragDropGestureRecognizer.cs
:
using System;
using CGPoint = System.Drawing.PointF;
using Foundation;
using UIKit;
namespace myNS
{
public class DragDropGestureRecognizer : UIGestureRecognizer
{
public DragDropGestureRecognizer()
{
}
public event EventHandler<DragDropEventArgs> Held;
protected void OnHeld(object sender, DragDropEventArgs e)
{
if (Held != null)
Held(sender, e);
}
public event EventHandler<DragDropEventArgs> Dragging;
protected void OnDragging(object sender, DragDropEventArgs e)
{
if (Dragging != null)
Dragging(sender, e);
}
public event EventHandler<DragDropEventArgs> Dropped;
protected void OnDropped(object sender, DragDropEventArgs e)
{
if (Dropped != null)
Dropped(sender, e);
}
public bool DidDrag { get; private set; }
public CGPoint DownAt { get; private set; }
public CGPoint DragAt { get; private set; }
public CGPoint ViewWasAt { get; private set; }
public CGPoint Delta
{
get { return new CGPoint(DragAt.X - DownAt.X, DragAt.Y - DownAt.Y); }
}
public bool Active { get { return DidDrag; } }
public override UIGestureRecognizerState State
{
get { return base.State; }
set { base.State = value; }
}
private CGPoint TouchPoint { get { return (CGPoint)LocationInView(View.Superview); } }
public override bool CanBePreventedByGestureRecognizer(UIGestureRecognizer preventingGestureRecognizer)
{
return false;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
if (NumberOfTouches > 1)
{
State = UIGestureRecognizerState.Failed;
return;
}
OnHeld(this, new DragDropEventArgs(default(UIGestureRecognizerState), DragAt, Delta, ViewWasAt));
DownAt = TouchPoint;
ViewWasAt = (CGPoint)View.Center;
State = UIGestureRecognizerState.Possible;
}
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
base.TouchesEnded(touches, evt);
if (DidDrag)
{
State = UIGestureRecognizerState.Recognized;
OnDropped(this, new DragDropEventArgs(State, DragAt, Delta, ViewWasAt));
}
else
State = UIGestureRecognizerState.Failed;
}
public override void TouchesCancelled(NSSet touches, UIEvent evt)
{
base.TouchesCancelled(touches, evt);
State = UIGestureRecognizerState.Failed;
}
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
base.TouchesMoved(touches, evt);
if (State == UIGestureRecognizerState.Failed)
return;
DragAt = TouchPoint;
if (Distance(DownAt, DragAt) > 30 || DidDrag) //Won't move until dragged further than 30px
{
DidDrag = true;
OnDragging(this, new DragDropEventArgs(State, DragAt, Delta, ViewWasAt));
State = UIGestureRecognizerState.Changed;
}
}
public override void Reset()
{
base.Reset();
State = UIGestureRecognizerState.Possible;
DownAt = CGPoint.Empty;
DragAt = CGPoint.Empty;
DidDrag = false;
}
private float Distance(CGPoint point1, CGPoint point2)
{
var dx = point1.X - point2.X;
var dy = point1.Y - point2.Y;
return (float)Math.Sqrt(dx * dx + dy * dy);
}
}
public class DragDropEventArgs : EventArgs
{
public DragDropEventArgs(UIGestureRecognizerState state, CGPoint point, CGPoint delta, CGPoint viewWasAt)
{
State = state;
Point = point;
Delta = delta;
ViewWasAt = viewWasAt;
}
public UIGestureRecognizerState State { get; private set; }
public CGPoint Point { get; private set; }
public CGPoint Delta { get; private set; }
public CGPoint ViewWasAt { get; private set; }
}
}
感谢Yvan Rodrigues - TwoRedCells
Android等效:
private int _xPad, _yPad, _xDelta, _yDelta;
prviate bool _moved;
InfoBtn.Touch += (v, me) => //InfoBtn is a button within a frameLayout
{
int X = (int)me.Event.RawX;
int Y = (int)me.Event.RawY;
switch (me.Event.Action & MotionEventActions.Mask)
{
case MotionEventActions.Down:
_xPad = frameLayout.PaddingLeft;
_yPad = frameLayout.PaddingTop;
_xDelta = X;
_yDelta = Y;
_moved = false;
break;
case MotionEventActions.Up:
if (!_moved)
{
//On Button Click
}
break;
case MotionEventActions.PointerDown:
break;
case MotionEventActions.PointerUp:
break;
case MotionEventActions.Move:
var _x = X - _xDelta;
var _y = Y - _yDelta;
_moved = _moved || Math.Abs(_x) > 100 || Math.Abs(_y) > 100; //100px
if (_moved)
{
var padleft = _x - _xPad;
padleft = padleft + InfoBtn.Width > Resources.DisplayMetrics.WidthPixels ? Resources.DisplayMetrics.WidthPixels - InfoBtn.Width : padleft;
var padtop = _y - _yPad;
padtop = padtop + InfoBtn.Height > Resources.DisplayMetrics.HeightPixels ? Resources.DisplayMetrics.HeightPixels - InfoBtn.Height : padtop;
frameLayout.SetPadding(0, 0, padleft, padtop);
}
break;
}
frameLayout.Invalidate();
};