2017-11-22 15 views
0

問題は、toucheventが終了するとrestore positionコマンドが呼び出され、元の位置に戻されるという問題があります。私は問題が私の財産変更イベントにあると思う。DraggableViewの復元位置コマンドC#Xamarin

2番目の問題は、最も近い番号のラベルに引っかかり、センター自体を適切に並べ替えることができるはずだが、どうすればいいのかわからない。私はこれを行う方法についてのヒントがほしいと思う。

グリッド

<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> 

クロスプラットフォームのコード、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); 
    } 

} 

答えて

1

問題は、toucheventが終了するときにrestore positionコマンドを呼び出して元の位置に戻す必要があることです。私はこの問題は、あなたがDraggableViewをしたい場合は、あなたがViewRenderer代わりのVisualElementRenderer<Xamarin.Forms.View>を使用してみてください私の財産変更されたイベント

  1. であると思います。

  2. Rendererが、あなたはレンダラでOnTouchEventを上書きしようとするべきではありません、それは動作しませんカスタムビューではありません、あなたは、あなたのViewRendererSetNativeControlを使用し、ネイティブプロジェクトにカスタムビューを作成することができます

    //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 
        } 
    } 
    

更新:

COMM: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)); 
} 
+0

私はあなたが何を意味するかわからないんだけど、これはどのよう適切に実装していない私のonrestoreコマンドを使用して、私の問題を解決できますか? ELI5できますか? –

+0

これはxamarin.formsでカスタムコントロールを作成するためのヒントです。コマンドの問題については、自分のアップデートを参照してください。 –

+0

私はdragonativeについて少し混乱しています、私はちょうど新しいdragviewネイティブの元のOntouchevent関数を置くと思いますか? –

関連する問題