Xamarin.Forms - Привязка поведения
Несколько лет назад я создал класс в 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);
}
}
Этот класс содержит объект UISnapBehavior, который недоступен в Xamarin.Forms. Поскольку я хочу перенести это в Xamarin.Forms, есть ли простой обходной путь или подобный класс для UISnapBehavior?
0 ответов
Не уверен, что через два года вы все еще ждете ответа на этот вопрос, но, надеюсь, это все еще может быть кому-то полезно.
Вы должны иметь возможность взять этот класс и поместить его в свой проект.iOS и создать настраиваемое средство визуализации для настраиваемого элемента управления в вашем ПК. что-то вроде этого:
Пользовательский рендерер в вашем проекте 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);
}
}
}
Пользовательский элемент управления, который нужно поместить в ПК:
namespace Test.Controls
{
public class MovableUIButtonView : ContentView
{
}
}
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>