Viewport Origin animation

2019-02-24 22:41发布

问题:

I am developing a Windows phone app, where I have a viewportcontroller, that enables me to zoom in and out on content. I want to center the zoom at the point where I zoom. Which I can do with

Viewportcontroller.SetViewportOrigin()

But this makes the viewportcontroller jump to the origin I set. Which does not look very nice. I therefore would like to create a storyboard that changes the origin gradually as the zooming occurs.

I therefore would like to ask how I should do this with a property of the ViewportControl. I have tried with some different animation types, translation and xy. But either I am choosing the property wrong or choosing the wrong animation type. Because nothing is working :(

My Problem is therefore twofold. What type of animation do I choose. And how do I change it? Should it be a DoubleAnimation Where I set to and from? But I Cannot seem to set a point here? Any help IS MUCH APPRECIATED!

回答1:

I tried a few different approaches and this one came out to be the smoothest. It's not pretty, but it works.

public partial class MainPage : PhoneApplicationPage
{
    private const int MoveCount = 25;

    private double _tickX;
    private double _tickY;

    private int _adjustCount = MoveCount+1;

    public MainPage()
    {
        InitializeComponent();
        Viewport.ViewportChanged += ViewportOnViewportChanged;
    }

    private void ViewportOnViewportChanged(object sender, ViewportChangedEventArgs viewportChangedEventArgs)
    {
        AdjstViewport();
    }

    private void AdjstViewport()
    {
        if (_adjustCount >= MoveCount) return;
        _adjustCount++;
        Viewport.SetViewportOrigin(new Point(Viewport.Viewport.X + _tickX, Viewport.Viewport.Y + _tickY));                        
    }

    private async void OnButtonClick(object sender, System.Windows.RoutedEventArgs e)
    {
        _adjustCount = 0;

        var content = (FrameworkElement)Viewport.Content;
        double zoomOriginX = (content.ActualWidth / 2) - (Viewport.Viewport.Width / 2);
        double zoomOriginY = (content.ActualHeight / 2) - (Viewport.Viewport.Height / 2);

        double distanceX = zoomOriginX - Viewport.Viewport.X;
        double distanceY = zoomOriginY - Viewport.Viewport.Y;

        _tickX = distanceX / MoveCount;
        _tickY = distanceY / MoveCount;

        AdjstViewport();
    }
}


回答2:

I have no experience with the ViewportControl, and I am assuming ViewportControl.SetViewportOrigin() is the only way to set the origin (i.e. : there are no properties to do it).

If that's the case, you could wrap the ViewportControl in a custom control.

Add two dependency properties that control (ViewportX and ViewportY, or one dependency property of type Point), and in the storyboard, animate those two properties (with a simple DoubleAnimation).

In the value changed callbacks of those properties, you can then call SetViewportOrigin() with the changed values.

so something like:

public class WrappedViewport : Control
{
    private ViewportControl _viewportControl;
    protected override OnApplyTemplate()
    {
        // make sure there is an appropriate default style in generic.xaml
        _viewportControl = (ViewportControl)GetTemplateChild("Viewport"); 
    }

    #region ViewportX
    private static void ViewportXChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        WrappedViewport owner = (WrappedViewport)d;
        owner._viewportControl.SetViewportOrigin(ViewportX, ViewportY);
    }

    private static readonly DependencyProperty ViewportXProperty = DependencyProperty.Register("ViewportX",
                                                                                          typeof(double),
                                                                                          typeof(WrappedViewport),
                                                                                          new PropertyMetadata(0d, ViewportXChangedCallback));

    public double ViewportX
    {
        get { return (double)GetValue(ViewportXProperty ); }
        set { SetValue(ViewportXProperty , value); }
    }
    #endregion

    #region ViewportY
    private static void ViewportYChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        WrappedViewport owner = (WrappedViewport)d;
        owner._viewportControl.SetViewportOrigin(ViewportX, ViewportY);
    }

    private static readonly DependencyProperty ViewportYProperty = DependencyProperty.Register("ViewportY",
                                                                                          typeof(double),
                                                                                          typeof(WrappedViewport),
                                                                                          new PropertyMetadata(0d, ViewportYChangedCallback));

    public double ViewportY
    {
        get { return (double)GetValue(ViewportYProperty ); }
        set { SetValue(ViewportYProperty , value); }
    }
    #endregion
}

See also http://msdn.microsoft.com/en-us/library/ms752914(v=vs.110).aspx