Search code examples
c#animationuwpparallaxwindows-community-toolkit

UWP Parallax with offset


I develop UWP application with listview of images with translucated items background like on Windows Phone Start screen (e.g. https://www.windowscentral.com/sites/wpcentral.com/files/styles/larger/public/field/image/2014/04/Clean_vs_Busy.jpg?itok=58NioLgB). I decided to base my solution on UWP Community toolkit parallax service. First I took left-top point of item:

var p = parallaxElement.TransformToVisual(scroller).TransformPoint(new Point(0, 0));

Where should I add this offset in animation expression? Also I did not find full documentation for this.

 ExpressionAnimation expression = compositor.CreateExpressionAnimation(
        "Matrix4x4.CreateFromTranslation(Vector3(HorizontalMultiplier * scroller.Translation.X, VerticalMultiplier * scroller.Translation.Y, 0.0f))");
    expression.SetReferenceParameter("scroller", scrollerViewerManipulation);
    expression.SetScalarParameter("offsetX", (float)p.X);
    expression.SetScalarParameter("offsetY", (float)p.Y);

In other words, I'd like to make effect "looking through items on shared large image"; items are wholes in canvas.


Solution

  • To animate all of the images of your list, you can follow the sample from the Windows Composition team.

    Here's the tl/dr version:

    Create the animation. Do this when the page is loaded:

    private void SetupAnimation()
    {
        // available with SDK version 15063
        Compositor compositor = Window.Current.Compositor;
        // available with previous SDK version
        //Compositor compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
    
        // Get scrollviewer using UWP Community Toolkit extension method
        ScrollViewer myScrollViewer = ImageList.FindDescendant<ScrollViewer>();
        _scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(myScrollViewer);
    
        // Setup the expression
        var scrollPropSet = _scrollProperties.GetSpecializedReference<ManipulationPropertySetReferenceNode>();
        var startOffset = ExpressionValues.Constant.CreateConstantScalar("startOffset", 0.0f);
        var parallaxValue = 0.5f;
        var parallax = (scrollPropSet.Translation.Y + startOffset);
        _parallaxExpression = parallax * parallaxValue - parallax;
    }
    

    Animate each image in the list when the container changes (NOTE: subscribe to the ContainerContentChanging event of your ListView)

    private void ImageList_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        // Find the image element to animate
        Image image = args.ItemContainer.ContentTemplateRoot.GetFirstDescendantOfType<Image>();
    
        Visual visual = ElementCompositionPreview.GetElementVisual(image);
        // You'll want to use the right size for your images
        visual.Size = new Vector2(960f, 960f);
    
        if (_parallaxExpression != null)
        {
            _parallaxExpression.SetScalarParameter("StartOffset", (float)args.ItemIndex * visual.Size.Y / 4.0f);
        visual.StartAnimation("Offset.Y", _parallaxExpression);
        }
    }
    

    This sample works with a ListView or GridView.