简体   繁体   English

Xamarin.Forms - 捕捉行为

[英]Xamarin.Forms - Snap behavior

Some years ago I made a class in Xamarin.iOS which was simply a UIView that snaps to the edges of the screen.几年前,我在 Xamarin.iOS 中创建了一个类,它只是一个捕捉到屏幕边缘的 UIView。

public class MovableUIButton : UIView
{
    private UIPanGestureRecognizer PanGesture;

    private UIButton btnShoppingCart;

    private UIDynamicAnimator animator;
    private PointF snapPoint;
    private bool isInitialized = false;
    private UISnapBehavior snap;

    // offsets used to position image relative to touch point while being dragged
    private float dx = 0;
    private float dy = 0;

    public event EventHandler TouchUpInside;

    public MovableUIButton(CGRect rect) : base(rect)
    {
        Initialize();
    }

    public MovableUIButton(IntPtr handle) : base(handle)
    {
        Initialize();
    }

    private void Initialize()
    {
        PanGesture = new UIPanGestureRecognizer(DidPan);
        this.AddGestureRecognizer(PanGesture);

        // Make it round
        this.Layer.CornerRadius = this.Bounds.Width / 2;
        this.BackgroundColor = UIColor.FromRGB(89f / 255f, 157f / 255f, 255f / 255f);

        // Set the Border
        this.Layer.BorderColor = UIColor.White.CGColor;
        this.Layer.BorderWidth = 3;

        // Set a Shadow
        this.Layer.ShadowColor = UIColor.White.CGColor;
        this.Layer.ShadowOpacity = .5f;
        this.Layer.ShadowRadius = 8.0f;
        this.Layer.ShadowOffset = new System.Drawing.SizeF(0f, 0f);

        btnShoppingCart = new UIButton(Bounds);
        btnShoppingCart.Font = FontAwesome.Font(30);
        btnShoppingCart.SetTitle(BaseFontAwesome.FAShoppingCart, UIControlState.Normal);
        btnShoppingCart.UserInteractionEnabled = true;
        btnShoppingCart.TouchUpInside += BtnShoppingCart_TouchUpInside;
        this.AddSubview(btnShoppingCart);
    }

    private void InitializeAnimator()
    {
        snapPoint = new PointF((float)SetX(Superview.Bounds), (float)SetY(Superview.Bounds));
        animator = new UIDynamicAnimator(Superview);
        isInitialized = true;
    }

    private void DidPan()
    {
        if (isInitialized == false)
        {
            InitializeAnimator();
        }

        if ((PanGesture.State == UIGestureRecognizerState.Began || PanGesture.State == UIGestureRecognizerState.Changed) && (PanGesture.NumberOfTouches == 1))
        {
            // remove any previosuly applied snap behavior to avoid a flicker that will occur if both the gesture and physics are operating on the view simultaneously
            if (snap != null)
                animator.RemoveBehavior(snap);

            var p0 = PanGesture.LocationInView(Superview);

            if (dx == 0)
                dx = (float)(p0.X - this.Center.X);

            if (dy == 0)
                dy = (float)(p0.Y - this.Center.Y);

            // this is where the offsets are applied so that the location of the image follows the point where the image is touched as it is dragged,
            // otherwise the center of the image would snap to the touch point at the start of the pan gesture
            var p1 = new PointF((float)(p0.X - dx), (float)(p0.Y - dy));

            this.Center = p1;
        }
        else if (PanGesture.State == UIGestureRecognizerState.Ended)
        {
            // reset offsets when dragging ends so that they will be recalculated for next touch and drag that occurs
            dx = 0;
            dy = 0;

            snapPoint = new PointF((float)SetX(Superview.Bounds), (float)SetY(Superview.Bounds));

            SnapImageIntoPlace((System.Drawing.PointF)PanGesture.LocationInView(Superview));
        }
    }

    void SnapImageIntoPlace(PointF touchPoint)
    {
        snap = new UISnapBehavior(this, snapPoint);
        animator.AddBehavior(snap);
    }

    private nfloat SetX(CGRect superBounds)
    {
        nfloat x = 0f;

        if (this.Center.X > superBounds.Width / 2)
        {
            x = superBounds.Width - 20;
        }
        else
        {
            x = 20;
        }

        return x;
    }

    private nfloat SetY(CGRect superBounds)
    {
        nfloat y = 0f;

        if (this.Center.Y < 20)
        {
            y = 20;
        }
        else if (this.Center.Y > superBounds.Height - 20)
        {
            y = superBounds.Height - 20;
        }
        else
        {
            return this.Center.Y;
        }

        return y;
    }

    public override void TouchesBegan(NSSet touches, UIEvent evt)
    {
        base.TouchesBegan(touches, evt);
    }

    private void BtnShoppingCart_TouchUpInside(object sender, EventArgs e)
    {
        TouchUpInside?.Invoke(this, null);
    }
}

This class contains a UISnapBehavior object which is not available in Xamarin.Forms.此类包含Xamarin.Forms中不可用的UISnapBehavior对象。 Because I want to port this to Xamarin.Forms, is there an easy workaround or a similar class to UISnapBehavior ?因为我想将它移植到 Xamarin.Forms,是否有一个简单的解决方法或类似于UISnapBehavior 的类?

Not sure if you're still waiting for an answer to this two years later, but hopefully this can still be useful to someone.不确定两年后你是否还在等待这个问题的答案,但希望这对某人仍然有用。

You should be able to take this class and put it in your .iOS project and create a custom renderer for a custom control in you pcl.您应该能够获取此类并将其放入您的 .iOS 项目中,并为您的 pcl 中的自定义控件创建自定义渲染器。 something like this:像这样:

Custom Renderer in your iOS project: iOS 项目中的自定义渲染器:

[assembly: ExportRenderer(typeof(MovableUIButtonView), typeof(MovableButtonRenderer_iOS))]
namespace Test.iOS.Renderers
{
    public class MovableButtonRenderer_iOS : ViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            if(Control == null)
                SetNativeControl(new MovableUIButton(Bounds));

            base.OnElementChanged(e);
        }
    }
}

Custom Control to be put into the pcl:要放入 pcl 的自定义控件:

namespace Test.Controls
{
    public class MovableUIButtonView : ContentView
    {
    }
}

the XAML on whatever page you use it on:您在任何页面上使用的 XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:Test.Controls"
             mc:Ignorable="d"
             x:Class="Test.TestVW">

    <Grid>
        <local:MovableUIButtonView></local:MovableUIButtonView>
    </Grid>

</ContentPage>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM