可拖动的Boxview不会更新Xamarin

我的第一个问题是框视图在左上angular生成,而不是我指定的devise网格行10和网格列3

第二个问题是可拖拽的视图,在代码本地拖拽视图的第一部分,它正确地调用了触摸事件,但也许它不会在GUI中更新?

<ContentPage> <ContentPage.Padding> <OnPlatform x:TypeArguments="Thickness"> <On Platform="iOS, Android" Value="0,40,0,0" /> </OnPlatform> </ContentPage.Padding> <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" > <local:DraggableView.Content> <BoxView x:Name="image" BackgroundColor="Pink" Grid.Row="10" Grid.Column="3"/> </local:DraggableView.Content> </local:DraggableView> </Grid> 

助手

 public enum DragDirectionType { All, Vertical, Horizontal } public enum DragMode { Touch, LongPress } 

DraggableView

  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 void DragStarted() { DragStart(this, default(EventArgs)); IsDragging = true; } public void DragEnded() { IsDragging = false; DragEnd(this, default(EventArgs)); } } } 

这是代码的Android部分

 [assembly: ExportRenderer(typeof(DraggableView), typeof(DraggableViewRenderer))] namespace BabakusXamarin.Droid { 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; } } 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) { } } 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 (touchedDown) { 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 base.OnTouchEvent(e); } 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); } } } 

我的第一个问题是框视图在左上angular生成,而不是我指定的devise网格行10和网格列3

正如Nick上面提到的, Grid.RowGrid.Column从0开始,你应该在DraggableView而不是BoxView上设置它们。

修改你的代码如下

 <local:DraggableView x:Name="dragView" DragMode="LongPress" DragDirection="All" Grid.Row="9" Grid.Column="2" > <local:DraggableView.Content> <BoxView x:Name="image" BackgroundColor="Pink" /> </local:DraggableView.Content> </local:DraggableView> 

第二个问题是可拖拽的视图,在代码本地拖拽视图的第一部分,它正确地调用了触摸事件,但也许它不会在GUI中更新?

你testing了哪个平台? Android或iOS?

它完美的工作在我身边(iOS模拟器)。

在这里输入图像说明

更新:

在改变方法OnTouchEvent的逻辑之后,它按预期工作。

 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 (touchedDown) //{ 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; } 

过去,我也做了类似的控制。 我在Android上遇到的部分问题是,我还必须将屏幕密度合并到适当的位置。 这是我的实现。

控制:

 public class DraggableContentView : ContentView { public event EventHandler TouchEnded; public event EventHandler TouchesBegan; public event EventHandler PositionChanged; public void InvokeTouchBegan() { var parentLayout = Parent as Layout<View>; parentLayout?.RaiseChild(this); TouchesBegan?.Invoke(this, EventArgs.Empty); } public void InvokePositionChanged() { PositionChanged?.Invoke(this, EventArgs.Empty); } public void InvokeTouchEnded() { TouchEnded?.Invoke(this, EventArgs.Empty); } } 

Android渲染器:

 public class DraggableContentViewRenderer : ViewRenderer<DraggableContentView, Android.Views.View> { private float _density, _downX, _downY; public DraggableContentViewRenderer() { _density = Android.App.Application.Context.Resources.DisplayMetrics.Density; } protected override void OnElementChanged(ElementChangedEventArgs<DraggableContentView> e) { base.OnElementChanged(e); if (Element != null) { if (Control == null) { SetNativeControl(new Android.Views.View(Xamarin.Forms.Forms.Context)); } } } public override bool DispatchTouchEvent(MotionEvent e) { if (!Element.IsEnabled) return false; switch (e.Action) { case MotionEventActions.Down: { _downX = e.GetX(); _downY = e.GetY(); Element.InvokeTouchBegan(); break; } case MotionEventActions.Move: { var x = e.GetX(); var y = e.GetY(); var dx = (x - _downX) / _density; var dy = (y - _downY) / _density; Element.TranslationX += dx; Element.TranslationY += dy; Element.InvokePositionChanged(); break; } case MotionEventActions.Up: case MotionEventActions.Cancel: { Element.InvokeTouchEnded(); break; } default: break; } return true; } } 

iOS渲染器:

 public class DraggableContentViewRenderer : ViewRenderer<DraggableContentView, UIView> { private CGPoint _offsetLocation; protected override void OnElementChanged(ElementChangedEventArgs<DraggableContentView> e) { base.OnElementChanged(e); if (Element != null) { if (Control == null) { SetNativeControl(new UIView()); } } } public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan(touches, evt); var t = touches.ToArray<UITouch>(); if (t.Length != 1) return; var loc = t[0].LocationInView(this); var touchedView = HitTest(loc, evt); if (touchedView == null) return; _offsetLocation = new CGPoint(loc.X - touchedView.Frame.X, loc.Y - touchedView.Frame.Y); Element.InvokeTouchBegan(); } public override void TouchesMoved(NSSet touches, UIEvent evt) { base.TouchesMoved(touches, evt); var newLoc = ((UITouch)touches.First()).LocationInView(this); Element.TranslationX += newLoc.X - _offsetLocation.X; Element.TranslationY += newLoc.Y - _offsetLocation.Y; Element.InvokePositionChanged(); } public override void TouchesEnded(NSSet touches, UIEvent evt) { base.TouchesEnded(touches, evt); Element.InvokeTouchEnded(); } }