以编程方式创建浮动可拖动按钮,无需故事板(Xamarin)

时间:2017-01-24 06:23:42

标签: c# visual-studio drag-and-drop xamarin.ios uibutton

我有一个以编程方式创建的按钮

InfoBtn = _utilProvider.FloatingBtn("My Button"); //Returns Floating UIButton
InfoBtn.Frame = new CGRect((ScreenWidth / 2) - 22.5, ScreenHeight - 65, 55, 55);
View.Add(InfoBtn);

enter image description here

我想以编程方式向其添加拖放功能。问题是,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方法。

在基本上尝试在线发现每个教程后,我感到很沮丧。

非常感谢任何帮助

1 个答案:

答案 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();
};