How to check if an UI Element has reached the top

2019-08-12 15:02发布

问题:

There is a page which has a scroll viewer and some content which is dynamic in nature. In the middle of the page there is a grid. Whenever the user scrolls the page and grid reaches the top of the page i want a notifier. Basically i want to make the grid sticky on top whenever it reaches top of the page. Is there any way we can achieve this in Windows phone application. I dont want to calculate the offset because the content between top of the page and grid is dynamic.

回答1:

This used to be tricky to do but thanks to the new Windows Composition API, it's now fairly simple.

Let's say I have a ScrollViewer named MainScroll which hosts a Grid called StickyGrid and I want to make the latter sticky once it hits the top.

There's the code with comments to explain what it does.

MainScroll.SizeChanged += (s, e) =>
{        
    // Let's first get the offset Y for the main ScrollViewer relatively to the sticky Grid.
    var transform = ((UIElement)MainScroll.Content).TransformToVisual(StickyGrid);
    var offsetY = (float)transform.TransformPoint(new Point(0, 0)).Y;

    // Get Composition variables.
    var scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(MainScroll);
    var stickyGridVisual = ElementCompositionPreview.GetElementVisual(StickyGrid);
    var compositor = scrollProperties.Compositor;

    // Basically, what the expression 
    // "ScrollingProperties.Translation.Y > OffsetY ? 0 : OffsetY - ScrollingProperties.Translation.Y"
    // means is that -
    // When ScrollingProperties.Translation.Y > OffsetY, it means the scroller has yet to scroll to the sticky Grid, so
    // at this time we don't want to do anything, hence the return of 0;
    // when the expression becomes false, we need to offset the the sticky Grid on Y Axis by adding a negative value
    // of ScrollingProperties.Translation.Y. This means the result will forever be just OffsetY after hitting the top.
    var scrollingAnimation = compositor.CreateExpressionAnimation("ScrollingProperties.Translation.Y > OffsetY ? 0 : OffsetY - ScrollingProperties.Translation.Y");
    scrollingAnimation.SetReferenceParameter("ScrollingProperties", scrollProperties);
    scrollingAnimation.SetScalarParameter("OffsetY", offsetY);

    // Kick off the expression animation.
    stickyGridVisual.StartAnimation("Offset.Y", scrollingAnimation);
};

Here is a working demo on GitHub.