问题是当touchevent结束时,应该调用restore position命令并将其恢复到原始位置。我认为问题在于我的财产改变了事件
第二个问题是,它应该能够锁定到最接近的数字标签,并将它们正确地放在它们上面,但是我不知道如何做到这一点。我想要一些关于如何做到这一点的提示,因为我很无能为力。
网格
<Grid BackgroundColor="White" ColumnSpacing="10" RowSpacing="10">
<Label Text="Red" FontSize="Medium" HorizontalOptions="Center" />
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<BoxView Color="Black" Grid.Column="1" Grid.RowSpan="1"/>
<BoxView Color="Gray" Grid.Column="2" Grid.RowSpan="1"/>
<Label Text="9" Font ="60" Grid.Row="1" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="8" Font ="60" Grid.Row="2" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="7" Font ="60" Grid.Row="3" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="6" Font ="60" Grid.Row="4" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="5" Font ="60" Grid.Row="5" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="4" Font ="60" Grid.Row="6" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="3" Font ="60" Grid.Row="7" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="2" Font ="60" Grid.Row="8" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="1" Font ="60" Grid.Row="9" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<Label Text="0" Font ="60" Grid.Row="10" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Black" />
<local:DraggableView x:Name="dragView" DragMode="LongPress" DragDirection="All" Grid.Row="3" Grid.RowSpan="3" Grid.Column="3" >
<local:DraggableView.Content>
<BoxView x:Name="image" BackgroundColor="Pink" />
</local:DraggableView.Content>
</local:DraggableView>
</Grid>
Crossplatform Code,Xamarin
public partial class DraggableView : ContentView
{
public event EventHandler DragStart = delegate { };
public event EventHandler DragEnd = delegate { };
public static readonly BindableProperty DragDirectionProperty = BindableProperty.Create(
propertyName: "DragDirection",
returnType: typeof(DragDirectionType),
declaringType: typeof(DraggableView),
defaultValue: DragDirectionType.All,
defaultBindingMode: BindingMode.TwoWay);
public DragDirectionType DragDirection
{
get { return (DragDirectionType)GetValue(DragDirectionProperty); }
set { SetValue(DragDirectionProperty, value); }
}
public static readonly BindableProperty DragModeProperty = BindableProperty.Create(
propertyName: "DragMode",
returnType: typeof(DragMode),
declaringType: typeof(DraggableView),
defaultValue: DragMode.LongPress,
defaultBindingMode: BindingMode.TwoWay);
public DragMode DragMode
{
get { return (DragMode)GetValue(DragModeProperty); }
set { SetValue(DragModeProperty, value); }
}
public static readonly BindableProperty IsDraggingProperty = BindableProperty.Create(
propertyName: "IsDragging",
returnType: typeof(bool),
declaringType: typeof(DraggableView),
defaultValue: false,
defaultBindingMode: BindingMode.TwoWay);
public bool IsDragging
{
get { return (bool)GetValue(IsDraggingProperty); }
set { SetValue(IsDraggingProperty, value); }
}
public static readonly BindableProperty RestorePositionCommandProperty = BindableProperty.Create(nameof(RestorePositionCommand), typeof(ICommand), typeof(DraggableView), default(ICommand), BindingMode.TwoWay, null, OnRestorePositionCommandPropertyChanged);
static void OnRestorePositionCommandPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var source = bindable as DraggableView;
if (source == null)
{
return;
}
source.OnRestorePositionCommandChanged();
}
private void OnRestorePositionCommandChanged()
{
OnPropertyChanged("RestorePositionCommand");
}
public ICommand RestorePositionCommand
{
get
{
return (ICommand)GetValue(RestorePositionCommandProperty);
}
set
{
SetValue(RestorePositionCommandProperty, value);
}
}
public void DragStarted()
{
DragStart(this, default(EventArgs));
IsDragging = true;
}
public void DragEnded()
{
IsDragging = false;
DragEnd(this, default(EventArgs));
}
Android部分代码
public class DraggableViewRenderer : VisualElementRenderer<Xamarin.Forms.View>
{
float originalX;
float originalY;
float dX;
float dY;
bool firstTime = true;
bool touchedDown = false;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
LongClick -= HandleLongClick;
}
if (e.NewElement != null)
{
LongClick += HandleLongClick;
var dragView = Element as DraggableView;
dragView.RestorePositionCommand = new Command(() =>
{
if (!firstTime)
{
SetX(originalX);
SetY(originalY);
}
});
}
}
private void HandleLongClick(object sender, LongClickEventArgs e)
{
var dragView = Element as DraggableView;
if (firstTime)
{
originalX = GetX();
originalY = GetY();
firstTime = false;
}
dragView.DragStarted();
touchedDown = true;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var dragView = Element as DraggableView;
base.OnElementPropertyChanged(sender, e);
}
protected override void OnVisibilityChanged(AView.View changedView, [GeneratedEnum] ViewStates visibility)
{
base.OnVisibilityChanged(changedView, visibility);
if (visibility == ViewStates.Visible)
{
}
}
// What happens when you toch
public override bool OnTouchEvent(MotionEvent e)
{
float x = e.RawX;
float y = e.RawY;
var dragView = Element as DraggableView;
switch (e.Action)
{
case MotionEventActions.Down:
if (dragView.DragMode == DragMode.Touch)
{
if (!touchedDown)
{
if (firstTime)
{
originalX = GetX();
originalY = GetY();
firstTime = false;
}
dragView.DragStarted();
}
touchedDown = true;
}
dX = x - this.GetX();
dY = y - this.GetY();
break;
case MotionEventActions.Move:
if (dragView.DragDirection == DragDirectionType.All || dragView.DragDirection == DragDirectionType.Horizontal)
{
SetX(x - dX);
}
if (dragView.DragDirection == DragDirectionType.All || dragView.DragDirection == DragDirectionType.Vertical)
{
SetY(y - dY);
}
break;
case MotionEventActions.Up:
touchedDown = false;
dragView.DragEnded();
break;
case MotionEventActions.Cancel:
touchedDown = false;
break;
}
return true;
}
public override bool OnInterceptTouchEvent(MotionEvent e)
{
BringToFront();
return true;
}
}
iOS部件
public class DraggableViewRenderer : VisualElementRenderer<View>
{
bool longPress = false;
bool firstTime = true;
double lastTimeStamp = 0f;
UIPanGestureRecognizer panGesture;
CGPoint lastLocation;
CGPoint originalPosition;
UIGestureRecognizer.Token panGestureToken;
void DetectPan()
{
var dragView = Element as DraggableView;
if (longPress || dragView.DragMode == DragMode.Touch)
{
if (panGesture.State == UIGestureRecognizerState.Began)
{
dragView.DragStarted();
if (firstTime)
{
originalPosition = Center;
firstTime = false;
}
}
CGPoint translation = panGesture.TranslationInView(Superview);
var currentCenterX = Center.X;
var currentCenterY = Center.Y;
if (dragView.DragDirection == DragDirectionType.All || dragView.DragDirection == DragDirectionType.Horizontal)
{
currentCenterX = lastLocation.X + translation.X;
}
if (dragView.DragDirection == DragDirectionType.All || dragView.DragDirection == DragDirectionType.Vertical)
{
currentCenterY = lastLocation.Y + translation.Y;
}
Center = new CGPoint(currentCenterX, currentCenterY);
if (panGesture.State == UIGestureRecognizerState.Ended)
{
dragView.DragEnded();
longPress = false;
}
}
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
RemoveGestureRecognizer(panGesture);
panGesture.RemoveTarget(panGestureToken);
}
if (e.NewElement != null)
{
var dragView = Element as DraggableView;
panGesture = new UIPanGestureRecognizer();
panGestureToken = panGesture.AddTarget(DetectPan);
AddGestureRecognizer(panGesture);
dragView.RestorePositionCommand = new Command(() =>
{
if (!firstTime)
{
Center = originalPosition;
}
});
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var dragView = Element as DraggableView;
base.OnElementPropertyChanged(sender, e);
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
lastTimeStamp = evt.Timestamp;
Superview.BringSubviewToFront(this);
lastLocation = Center;
}
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
if (evt.Timestamp - lastTimeStamp >= 0.5)
{
longPress = true;
}
base.TouchesMoved(touches, evt);
}
}
答案 0 :(得分:1)
问题是当touchevent结束时,应该调用restore position命令并将其恢复到原始位置。我认为问题在于我的财产改变了事件
如果您需要DraggableView
,则应尝试使用ViewRenderer
代替VisualElementRenderer<Xamarin.Forms.View>
。
Renderer
不是自定义视图,您不应该尝试覆盖渲染器中的OnTouchEvent
,它不会工作,您可以创建自定义视图原生项目,然后在SetNativeControl
:
ViewRenderer
//Create this custom view in your Xamarin.Android project.
public class DragViewNative:View
{
public DragViewNative(Context context) : base(context)
{
}
public override bool OnTouchEvent(MotionEvent e)
{
//implement your OnTouchEvent logic here
...
}
...
}
public class DraggableViewRenderer : ViewRenderer
{
...
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
//set native control to be your custom view
SetNativeControl(new DragViewNative(Xamarin.Forms.Forms.Context));
//other logic here
}
}
<强>更新强>
对于RestorePositionCommand
未触发的问题:
由于您未手动调用该命令,因此未触发该命令。由于它是您在控件中定义的自定义ICommand
,因此您需要手动调用它来触发它。例如,以下代码将在DragEnded
函数中执行:
//Inside DraggableView.cs
public void DragEnded()
{
IsDragging = false;
//add this line and your command will be triggered
this.RestorePositionCommand.Execute(null);
DragEnd(this, default(EventArgs));
}