我正在使用平移手势识别器进行一些测试。设置非常简单,我有一个20x20的盒子视图,并由相对布局设置。平移手势的处理程序
switch (args.StatusType)
{
case GestureStatus.Running:
box.TranslationX = box.X + args.TotalX;
box.TranslationY = box.Y + args.TotalY;
break;
case GestureStatus.Completed:
box.TranslationX = 0;
box.TranslationY = 0;
break;
}
所以它运行正常,但是当我尝试在屏幕上拖动框视图时,它不会正确地转换值。当它试图重绘盒子时,它也给出了这种非常讨厌的闪烁效果。有没有更好的方法来做这个?有没有办法摆脱闪烁?
答案 0 :(得分:1)
我在Xamarin论坛上找到了一个可以帮助您解决问题的实现(Pinch and Pan gesture recognizers not working on Android project)。这是Pan实现,我用我的项目测试它,并注意到“闪烁”效果不再存在:
private double startScale, currentScale, xOffset, yOffset, startX, startY;
...
public void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Started:
startX = e.TotalX;
startY = e.TotalY;
Content.AnchorX = 0;
Content.AnchorY = 0;
break;
case GestureStatus.Running:
var maxTranslationX = Content.Scale * Content.Width - Content.Width;
Content.TranslationX = Math.Min(0, Math.Max(-maxTranslationX, xOffset + e.TotalX - startX));
var maxTranslationY = Content.Scale * Content.Height - Content.Height;
Content.TranslationY = Math.Min(0, Math.Max(-maxTranslationY, yOffset + e.TotalY - startY));
break;
case GestureStatus.Completed:
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
break;
}
}
如果有帮助,请告诉我。
答案 1 :(得分:1)
好吧,如果是具有PanGestureRecognizer的盒子,则闪烁的效果仅仅是因为TotalX和TotalY相对于盒子 translation 坐标。
尝试更改
box.TranslationX = box.X + args.TotalX;
box.TranslationY = box.Y + args.TotalY;
作者
box.TranslationX = box.TranslationX + args.TotalX;
box.TranslationY = box.TranslationY + args.TotalY;
应该可以。
编辑:它仅涉及Xamarin Android,它对UWP的工作方式有所不同。
答案 2 :(得分:1)
扩展 Julien的解决方案,该解决方案(在Android平台上)为我解决了该问题...
PanUpdatedEventArgs 中包含的Pan Gesture坐标可以被截取并重新计算,以抵消BoxView本身的运动。然后将新的 Args 传递给另一个处理程序:
public void Handle_PanUpdated(object sender, Xamarin.Forms.PanUpdatedEventArgs e)
{
double TranslationX = box.TranslationX;
double TranslationY = box.TranslationY;
double TotalX_Modified = e.TotalX + TranslationX;
double TotalY_Modified = e.TotalY + TranslationY;
if (Device.RuntimePlatform == Device.Android)
{
e = new PanUpdatedEventArgs(e.StatusType, e.GestureId, TotalX_Modified, TotalY_Modified);
}
Handle_PanUpdate_Modified(sender, e);
}
答案 3 :(得分:0)
我终于做到了, 假设我想在屏幕上拖动Boxview,而没有任何闪烁或协调准确性问题, 我为要在屏幕上拖动的视图创建了一个容器, DragEnd事件及其上的特定EventArgs,当此事件以主要形式引发时,我从布局的子代列表中删除了此容器,并使用EventArgs携带的数据重新添加了一个新容器:
PanContainer.cs:
public class PanContainer : ContentView
{
public delegate void DragEndEventHandler(object sender, DragEventArgs e);
public PanContainer()
{
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);
}
public event DragEndEventHandler DragEnd;
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Running:
Content.TranslationX = e.TotalX;
Content.TranslationY = e.TotalY;
break;
case GestureStatus.Completed:
OnDragEnd(new DragEventArgs(Content.TranslationX, Content.TranslationY, Width, Height, X, Y));
break;
case GestureStatus.Started:
break;
case GestureStatus.Canceled:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
protected virtual void OnDragEnd(DragEventArgs e)
{
DragEnd?.Invoke(this, e);
}
}
public class DragEventArgs : EventArgs
{
public DragEventArgs(double translationX, double translationY, double w, double h, double x, double y)
{
ContentTranslationX = translationX;
ContentTranslationY = translationY;
Width = w;
Height = h;
X = x;
Y = y;
}
public double ContentTranslationX { get; set; }
public double ContentTranslationY { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
并采用主要形式:
private void DraggableOnDragEnd(object sender, DragEventArgs e)
{
var bv = new BoxView
{
BackgroundColor = Color.Brown
};
var pc = new PanContainer
{
Padding = 4,
BackgroundColor = Color.Chartreuse,
Content = bv
};
absoluteLayout.Children.Add(pc,
new Rectangle(e.X + e.ContentTranslationX, e.Y + e.ContentTranslationY, e.Width, e.Height));
Task.Run(() =>
{
Device.BeginInvokeOnMainThread(() =>
{
absoluteLayout.Children.Remove(
absoluteLayout.Children.First(x => x.GetType() == typeof(PanContainer)));
var v = absoluteLayout.Children.First(x => x.GetType() == typeof(PanContainer));
((PanContainer) v).DragEnd += DraggableOnDragEnd;
});
});
}
它可以正常工作,但是也许有更好的方法来做..