首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DraggableView C# Xamarin的恢复位置命令

DraggableView C# Xamarin的恢复位置命令
EN

Stack Overflow用户
提问于 2017-11-22 14:32:54
回答 1查看 87关注 0票数 0

问题是,当touchevent结束时,应该调用restore position命令,并将其还原回原来的位置。我认为问题在于我的财产变更事件。

第二个问题是,它应该能够锁在最近的数字标签上,并且能够正确地在它们上居中,但是我不知道如何做到这一点。我只是想要一些关于如何做这件事的建议,因为我是相当无知的。

网格

代码语言:javascript
复制
<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>

跨平台代码

代码语言:javascript
复制
  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部分

代码语言:javascript
复制
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零件

代码语言:javascript
复制
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);
    }

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-11-23 06:20:40

问题是,当touchevent结束时,应该调用restore position命令,并将其还原回原来的位置。我认为问题在于我的财产变更事件。

  1. 如果您想要一个DraggableView,那么您应该尝试使用ViewRenderer而不是VisualElementRenderer<Xamarin.Forms.View>
  2. Renderer不是一个自定义视图,您不应该试图在呈现器中覆盖OnTouchEvent,它不会工作,您可以在本机项目中创建一个自定义视图,然后在您的ViewRenderer中使用SetNativeControl: //在Xamarin.Android项目中创建此自定义视图。公共类DragView本机:视图{公共DragViewNative(上下文上下文):基类(上下文){}公共覆盖bool OnTouchEvent(MotionEvent e) {//在这里实现您的OnTouchEvent逻辑.}公共类DraggableViewRenderer : ViewRenderer {.保护覆盖OnElementChanged(ElementChangedEventArgs e) { base.OnElementChanged(e);//将本机控件设置为自定义视图SetNativeControl(新的DragViewNative(Xamarin.Forms.Forms.Context));//此处的其他逻辑}}

更新:用于解决RestorePositionCommand未触发的问题:

该命令不会被触发,因为您没有手动调用它。由于它是您在控件中定义的自定义ICommand,因此需要手动调用它来触发它。例如,下面的代码将让它在您的DragEnded函数中执行:

代码语言:javascript
复制
//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));
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47437239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档