c# - 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);
}
}
此类包含Xamarin.Forms中不可用的UISnapBehavior对象。因为我想将此移植到 Xamarin.Forms,是否有简单的解决方法或与UISnapBehavior类似的类?
解决方案
不知道两年后你是否还在等待这个答案,但希望这对某人仍然有用。
您应该能够学习该课程并将其放入您的 .iOS 项目中,并为您的 pcl 中的自定义控件创建自定义渲染器。像这样的东西:
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);
}
}
}
要放入 pcl 的自定义控件:
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>
推荐阅读
- c# - 比较日期的问题
- datatables - DataTables - 大屏幕上的响应式隐藏列
- swift - 菜单栏右键菜单中使用的NSMenuItems显示为灰色无法点击
- java - MDC 仅用于日志记录吗?
- python - 如何获取删除字符的所有字符串组合
- java - 由于 ChromeDriver 未实例化,Selenium 测试未在 jenskins 中运行
- android - LocationListener 导致 android 中的内存泄漏
- xamarin.forms - 如何使用 xamarin 表单检查我的应用程序的移动数据的允许/拒绝权限
- matlab - 在数组中查找匹配或最接近的值(从给定值)
- python - 将项目列表转换为熊猫中的虚拟对象